Web 开发人员,您好!去年,我们发布了一系列改进,使在 Cloudflare 上部署 Web 应用变得更加容易。随后,我们发现在 Cloudflare 上托管的 Astro、Next.js、Nuxt、Qwik、Remix、SolidStart、SvelteKit 及其他 Web 应用出现大幅增长。今天,我们宣布对与这些 Web 框架的集成进行重大改进,让使用我们的 D1 SQL 数据库、 R2 对象存储、 AI 模型和 Cloudflare 开发人员平台其他强大功能开发复杂应用变得更容易。
在过去,如果您想使用 D1 开发一个由 Web 框架驱动的应用并在本地运行,您必须构建应用的生产版本,然后使用 `wrangler pages dev` 在本地运行。虽然这样可行,但您每次代码迭代都需要数秒钟,大型应用则可能需要几十秒。使用生产构建迭代实在太慢了,导致您脱离流程,而且无法利用框架作者付出大量努力实现的所有开发体验优化。今天这种情况要改变了!
我们的目标是以最自然的方式与 Web 框架集成,让开发人员在将应用部署到 Cloudflare 时,不必学习和适应重大的工作流程变化或自定义 API。无论是 Next.js 开发人员、Nuxt 开发人员,还是偏好其他框架,现在您都可以继续使用熟悉的快速本地开发工作流程,并将您的应用部署到 Cloudflare。
所有全栈 Web 框架都带有一个为框架量身定制的本地开发服务器,往往能提供卓越的开发体验,只有一个例外,它们不原生支持 Cloudflare 开发平台的一些重要功能,尤其是我们的存储解决方案。
因此,直到最近,您都不得不做出一个艰难的选择。您可以使用特定于框架的开发服务器来开发应用,但无法访问 Cloudflare 的许多功能。或者,您可以充分利用 Cloudflare 的平台,包括各种资源,例如 D1 或 R2 ,但您将不得不放弃使用特定于框架的开发人员工具。在这种情况下,您的迭代周期会变慢,需要几秒钟而不是几毫秒才能在浏览器中看到代码更改的结果。但这种情况不再存在了!我们来看一下。
让我们使用 C3 —— 我们的 create-cloudflare CLI ——创建一个新的应用。我们可使用自己选择的任何 npm 客户端(有人用 pnpm 吗?!?),但在本文中,为了简单起见,我们将统一使用默认的 npm 客户端。要开始,只需运行:
$ npm create cloudflare@latest
为应用起一个名字,或使用随机生成的名字。然后,选择“网站或 Web 应用”类别,并挑选您喜欢的全栈框架。我们支持多个框架: 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 的全栈应用也可以。我们将在一则专门的公告中分享有关 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 、Nitro 还是 vite 驱动。
为了访问我们的数据库并列出产品,我们可以使用特定于框架的方法。例如,在使用应用路由器的 Next.js 应用程序中,我们可以使用以下代码更新 app/api/hello/route.ts
:
const db = getRequestContext().env.DB;
const productsResults = await db.prepare('SELECT * FROM products').all();
return Response.json(productsResults.results);
或者,在 Nuxt 应用中,我们可以使用如下代码创建 server/api/hello.ts
文件并填充内容:
export default defineEventHandler(async ({ context }) => {
const db = context.cloudflare.env.DB;
const productsResults = await db.prepare('SELECT * FROM products').all();
return productsResults.results;
});
假设框架开发服务器运行于端口 3000,您可以通过访问 http://localhost:3000/api/hello 测试任一框架中的新 API 路由。为简单起见,我们选择了这些示例的 API 路由,但这也适用于任何 UI 生成路由。
每个 Web 框架都有自己定义路由和在应用中传递请求上下文信息的方式,因此您访问数据库、对象存储和其他资源的方法将取决于您的框架。您可以阅读我们的更新全栈框架指南以了解更多信息:
现在您已经知道如何在您选择的框架中访问 Cloudflare 的资源,关于您的框架的其他所有内容都保持不变。现在,您可以使用针对您的框架优化的开发服务器在本地开发应用,其中通常包括支持热模块替换(HMR)、自定义开发工具、增强调试支持等,同时仍然受益于 Cloudflare 特定的 API 和功能。双赢!
为了减少开发延迟并保留自定义框架的特定体验,我们需要使 Web 框架及其开发服务器能够以无缝、几乎不可见的方式与 Wrangler 和 Miniflare 集成。
Miniflare 是这个拼图中的关键组成部分。这是我们用于 Cloudflare 特定资源的本地模拟程序,由我们的 JavaScript (JS) 运行时 workerd 提供支持。通过依赖于 workerd,我们确保 Cloudflare 的 JavaScript API 在本地运行的方式真实模拟我们的生产环境。问题在于,框架开发服务器已经依赖 Node.js 来运行应用,因此引入另一个 JS 运行时破坏了有关这些开发服务器进行架构设计时的许多假设。
不过,我们的团队想出了一个有趣的方法来将这两个 JS 运行时结合起来。我们称之为 getPlatformProxy() API,它现在是 wrangler 的一部分,并由 miniflare 的 magic 代理提供强大支持。这个 API 暴露了一个 JS 代理对象,其行为就像包含所有绑定资源的常规 Workers env 对象。代理对象使 Node.js 中的代码能够透明地调用 workerd 中运行的 JavaScript 代码,并访问特定于 Cloudflare 的运行时 API。
有了这一 Node.js 和 workerd 运行时之间的桥梁,您的应用现可在由 Node.js 驱动的开发服务器中运行,同时直接访问 Cloudflare的 D1、R2、KV 和其他存储解决方案。您甚至可以编写一个 Node.js 脚本来执行相同的操作:
import {getPlatformProxy} from 'wrangler';
const {env} = getPlatformProxy();
console.dir(env);
const db = env.DB;
// Now let’s execute a DB query that runs in a local D1 db
// powered by miniflare/workerd and access the result from Node.js
const productsResults = await db.prepare('SELECT * FROM products').all();
console.log(productsResults.results);
有了 getPlatformProxy()
API,剩下的工作就是更新所有框架适配器、插件,在某些情况下还要更新框架本身,以便使用这个API。我们感谢框架团队在这一过程中提供的支持,特别是 Astro 的 Alex 、 Nuxt 的 pi0、Remix 的 Pedro 、Solid 的 Ryan 、Svelte 的 Ben 和 Rich ,以及我们 next-on pages 项目的合作者, James Anderson 。
虽然 getPlatformProxy()
API 对很多场景来说是不错的解决方案,但我们可以做得更好。假如能在我们的 JS 运行时而不是 Node.js 中运行整个应用,我们甚至可以更加忠实地模拟生产环境,减少开发人员摩擦,以及对生产环境中的意外情况。
在理想情况下,我们希望您能在与生产环境相同的运行时上进行开发,而这只能通过将 workerd 直接集成到所有框架的开发服务器中来实现。考虑到现有框架的数量及其之间的差异,这可不是一件小事。
不过,我们比较幸运。随着这项工作开始,我们很快意识到, Vite —— 许多全栈框架所采用的热门开发服务器—— 的采用率越来越高。实际上,Remix 在最近切换到了 Vite ,这证实了 Vite 作为当今 Web 开发的共同基础的受欢迎程度。
如果 Vite 拥有对在替代 JavaScript 运行时中运行全栈应用的一流支持,那么我们就可以使任何使用 Vite 的人在本地开发应用,并获得对 Cloudflare 开发人员平台的完全访问。不再需要特定于框架的自定义集成和变通方法——全栈框架、Vite 和 Cloudflare 的所有特性对所有开发人员可用。
听起来好得令人难以置信?也许吧。我们非常高兴能与 Vite 团队就 Vite 环境提案进行合作,此提案正能实现以上目标。该提案仍在发展中,敬请关注更新。
我们旨在使 Cloudflare 成为 Web 开发人员的最佳开发平台。让您能够快速、轻松地使用自己熟悉的框架和工具来开发应用,是我们使命的一个重要组成部分。立即运行如下简单命令,开始您的旅程吧:
$ npm create cloudflare@latest