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 。
未来对 Vite 开发工作流程的改进
虽然 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