使用 Cloudflare 和全栈框架实现快速开发

1,644 阅读7分钟

去年 Cloudflare 发布了一系列新功能,使在 Cloudflare 上部署 Web 应用程序变得更加容易,我们看到 Astro、Next.js、Nuxt、Qwik、Remix、SolidStart、SvelteKit 和其他托管 Web 应用程序的大幅增长。

近日 Cloudflare 对这些 Web 框架的集成模块进行了重大的升级,使其在开发中使用 Cloudflare 的 D1 数据库、R2 对象存储、AI 模型以及 Cloudflare 开发者平台的其他强大功能的复杂应用程序变得更加容易。

在过去,如果想使用 D1 开发一个由 Web 框架驱动的应用程序并在本地运行它,必须构建应用程序的生产版本,然后使用「wrangler Pages dev」在本地运行它。

虽然这有效,但每次代码迭代都需要几秒钟,对于大型应用程序来说需要几十秒。使用生产构建进行迭代实在是太慢了,会让我们脱离流程,并且不允许利用框架作者投入大量精力的所有 DX 优化,现如今这种情况正在改变。

我们的目标是以最自然的方式与 Web 框架集成,开发人员在将应用程序部署到 Cloudflare 时无需学习和采用重大的工作流程更改或自定义 API。

无论你是 Next.js、Nuxt 开发人员还是更喜欢其他框架,现在都可以继续使用你熟悉的本地开发工作流程,并将您的应用程序发布到 Cloudflare 上。

所有全栈 Web 框架都配有本地开发服务器,该服务器是根据框架定制的,通常会提供出色的开发体验,只有一个例外:它们本身不支持 Cloudflare 开发平台的一些重要功能,尤其是我们的存储解决方案。

你不得不做出艰难选择:要么使用特定框架的开发服务器开发应用,但放弃许多 Cloudflare 功能;要么充分利用 Cloudflare 平台包括 D1 或 R2 等资源,但放弃特定框架的开发工具。

这样,你的迭代周期会变慢,浏览器中看到代码更改结果的时间将从毫秒级变为秒级。但现在不再如此!让我们来看看。

构建应用程序

让我们使用 C3(create-cloudflare CLI)创建一个新应用程序。我们可以使用我们选择的任何包管理器,但为了在这篇文章中保持简单,我们将坚持使用默认的 npm 客户端。只需运行:

npm create cloudflare@latest

为您的应用程序提供一个名称,或者坚持使用随机生成的名称。然后选择「网站或网络应用程序」类别,并选择您选择的全栈框架。

我们支持多种:Astro、Next.js、Nuxt、Qwik、Remix、SolidStart 和 SvelteKit。

由于 C3 将应用程序搭建委托给最新版本的特定于框架的 CLI,因此您将完全按照框架作者的意图搭建应用程序,而不会错过任何框架功能或选项。然后,C3 会将集成和部署到 Cloudflare 所需的一切添加到您的应用程序中,这样您就无需自行配置。

通过我们的应用程序脚手架,只需几个步骤即可让它显示存储在数据库中的产品列表。首先,我们将数据库的配置添加到 wrangler.toml 配置文件中:

[[d1_databases]]
binding = "DB"
database_name = "blog-products-db"
database_id = "XXXXXXXXXXXXXXXX"

现在,您可以通过 wrangler.toml 文件配置绑定资源,甚至对于部署到 Pages 的全栈应用程序也是如此。我们将在专门的公告中分享更多有关页面配置增强的信息。

现在让我们创建一个简单的 schema.sql 文件来表示我们的数据库模式:

CREATE TABLE products(product_id INTEGER PRIMARY KEY, name TEXT, price INTEGER);
INSERT INTO products (product_id, name, price) VALUES (1, 'Apple', 250), (2, 'Banana', 100), (3, 'Cherry', 375);

并初始化我们的数据库:

npx wrangler d1 execute blog-products-db --local --file schema.sql

请注意,我们使用 wrangler d1 execute–local 标志将更改应用到本地 D1 数据库。这是我们的开发服务器将连接到的数据库。

接下来,如果您使用 TypeScript,请运行以下命令让 TypeScript 了解您的数据库:

npm run build-cf-types

该命令针对通过 C3 创建的所有全栈应用程序进行了预配置,并执行 wrangler types 来更新包含所有已配置绑定的 Cloudflare 环境的界面。

我们现在可以通过一个方便的快捷方式启动框架提供的开发服务器:

npm run dev

此快捷方式将启动框架的开发服务器,无论它是由 next dev、ninto 还是 vite 提供支持。

开发工作流程

为了减少开发延迟并保留特定于自定义框架的体验,我们需要使 Web 框架及其开发服务器能够以无缝、几乎不可见的方式与 wrangler 和 miniflare 集成。

Miniflare 是这个难题的关键组成部分。它是我们针对 Cloudflare 特定资源的本地模拟器,由我们的 JavaScript 运行时 workd 提供支持。

通过依赖 workerd,我们确保 Cloudflare 的 JavaScript API 以忠实模拟我们生产环境的方式在本地运行。问题在于框架开发服务器已经依赖 Node.js 来运行应用程序,因此将另一个 JS 运行时引入其中会破坏这些开发服务器的架构方式的许多假设。

然而,我们的团队想出了一个有趣的方法来弥合这两个 JS 运行时之间的差距。我们称之为 getPlatformProxy() API,它现在是 wrangler 的一部分,并由 miniflare 的魔法代理提供强大支持。

该 API 公开了一个 JS 代理对象,其行为就像包含所有绑定资源的普通 Workers env 对象一样。代理对象使 Node.js 中的代码能够透明地调用在workerd 中运行的 JavaScript 代码,以及访问特定于 Cloudflare 的运行时 API。

借助 Node.js 和 Workerd 运行时之间的这座桥梁,您的应用程序现在可以在由 Node.js 提供支持的开发服务器中运行时,直接访问 D1、R2、KV 和其他存储解决方案的 Cloudflare 模拟器。或者您甚至可以编写一个 Node.js 脚本来执行相同的操作:

import {getPlatformProxy} from 'wrangler';

const {env} = getPlatformProxy();
console.dir(env);
const db = env.DB;

const productsResults = await db.prepare('SELECT * FROM products').all();
console.log(productsResults.results);

有了 getPlatformProxy() API 可用后,剩下的工作就是更新所有框架适配器、插件,在某些情况下更新框架本身以使用此 API。

Vite 未来改进

虽然 getPlatformProxy() API 对于许多场景来说都是一个很好的解决方案,但我们还可以做得更好。如果我们可以在 JS 运行时而不是 Node.js 中运行整个应用程序,我们就可以更忠实地模拟生产环境,并减少开发人员的摩擦和生产意外。

在理想的世界中,我们希望您针对在生产中部署的相同运行时进行开发,这只能通过将workerd直接集成到所有框架的开发服务器中来实现,考虑到数量,这不是一个小壮举。现有的框架以及它们之间的差异。

不过我们还是有点幸运。当我们开始这项工作时,我们很快意识到 Vite 这个被许多全栈框架使用的流行开发服务器正在获得越来越多的采用。事实上,Remix 最近才转向 Vite,并证实了 Vite 作为当今 Web 开发的共同基础的受欢迎程度。

如果 Vite 能够为在替代 JavaScript 运行时中运行全栈应用程序提供一流的支持,那么我们就可以让任何使用 Vite 的人在本地开发其应用程序,并完全访问 Cloudflare 开发者平台。不再需要特定于框架的自定义集成和解决方法 - 所有开发人员都可以访问全栈框架、Vite 和 Cloudflare 的所有功能。

我们非常高兴能够与 Vite 团队就 Vite 环境提案进行合作,这可以实现这一点。该提案仍在不断完善中,敬请关注更新。

参考链接:blog.cloudflare.com/blazing-fas…