我通常使用Next.js 14(App Router)和Supabase进行身份验证,同时搭配Postgres来构建项目。对于Next.js应用来说,默认的部署方案通常是Vercel,这是有充分理由的:它能为开发者提供极佳的开发体验。

但在将同一个项目在两个平台上运行了一周后,我开始考虑使用Cloudflare Workers作为替代方案。我发现它的延迟性能有所提升(TTFB时间缩短了),而且其免费版本也更适合我的使用需求。

过去,在Cloudflare上部署Next.js应用确实存在一些挑战。早期的解决方案如Cloudflare Pages在支持Next.js的全部功能方面存在局限,而像next-on-pages这样的工具往往也会落后于最新的版本更新。

但随着@opennextjs/cloudflare的出现,这种情况发生了改变。这个工具允许你将标准的Next.js应用编译成Cloudflare Worker,从而支持SSR、ISR、中间件以及Image组件等功能——而且这一切都不需要对代码进行大规模修改。

在这份指南中,我会详细向你介绍我是如何将我的全栈Next.js + Supabase应用部署到Cloudflare Workers上的。

这篇文章正是我在刚开始学习这个过程时希望自己能拥有的参考资料。

目录

为什么选择Cloudflare Workers而不是Vercel?

在部署Next.js应用时,Vercel通常是首选方案。它能为开发者提供流畅的开发体验,并且与Next.js的集成度也非常高。

但Cloudflare Workers提供了一个极具吸引力的替代方案,尤其是当你关注全局性能和成本效益时。

以下是在撰写本文时进行的简要对比:

适用场景 Vercel(适合开发个人项目) Cloudflare Workers(免费 tier)
请求量 合理的使用限制 每日可处理数百万次请求
冷启动时间 约100–300毫秒(取决于所在地区) 接近于零(得益于V8隔离技术)
边缘节点分布 用于SSR的边缘节点区域有限 全球拥有300多个边缘节点
带宽限制 约100GB/月(为软性上限) 免费 tier没有严格的带宽限制
自定义域名支持 支持 支持
图片优化功能 使用量会被计入总消耗量 可通过IMAGES绑定来实现相关功能
付费方案 最低费用为约20美元/月 采用按使用量计费的模式

关键要点

  • 全球范围内的低延迟:Cloudflare通过遍布全球的边缘节点来运行你的应用程序,从而显著缩短用户的响应时间。

  • 极短的冷启动时间:得益于V8隔离技术,函数几乎可以瞬间启动并运行。

  • 高性价比:免费 tier对于个人项目、博客以及许多中小型应用程序来说已经足够使用了。

需要考虑的权衡因素

Cloudflare Workers使用的是V8隔离运行环境,而非完整的Node.js环境。这意味着:

  • 一些Node.js API(如fschild_process)无法使用

  • 某些原生二进制文件或库可能无法正常运行

不过,对于大多数现代开发架构来说——比如Next.js + Supabase + Stripe + Resend这样的组合——这种限制其实并不常见,也不会造成太大问题。

简而言之:如果你想要最简单、即插即用的Next.js部署方案,那就选择Vercel;而如果你追求更好的边缘节点性能和更灵活的扩展能力,那么Cloudflare Workers才是更适合你的选择。

先决条件

在开始使用之前,请确保你已经完成了以下准备工作。这些步骤大多只需要几分钟即可完成:

  • Node.js 18+pnpm 9+(你也可以使用npm或yarn,但本指南推荐使用pnpm。)

  • 一个Cloudflare账户 👉 点击此处注册

  • 如果你的应用程序需要使用数据库,那么还需要一个Supabase账户 👉 访问Supabase官网

  • 为你的项目创建一个GitHub仓库(后续进行CI/CD配置时需要使用它)

  • 一个域名(可选)——默认情况下,你会获得一个免费的*.workers.dev域名。

安装Wrangler(Cloudflare CLI工具)

我们将使用Wrangler来构建和部署应用程序:

pnpm add -D wrangler

技术栈

以下是该项目所使用的技术栈:

  • Next.js (v14.2.x): 对于公共页面和仪表板页面,均使用了App Router与Edge运行时。

  • Supabase: 负责处理身份验证、Postgres数据库管理以及行级安全功能。

  • Tailwind CSS + UI辅助工具:用于页面样式设计,并通过Framer Motion实现轻量级的动画效果。

  • Cloudflare Workers:@opennextjs/cloudflarewrangler共同支持部署功能。

  • GitHub Actions: 用于自动化持续集成/持续交付流程及应用程序部署。

注意: 如果你使用的是Next.js 15或更高版本,可以删除构建脚本中的--dangerouslyUseUnsupportedNextVersion标志,因为这个选项仅适用于某些特定版本的Next.js 14配置。

步骤1 — 安装Cloudflare适配器

在现有的Next.js项目中,安装OpenNext适配器以及Cloudflare提供的CLI工具Wrangler:

pnpm add @opennextjs/cloudflare
pnpm add -D wrangler

然后将部署脚本添加到package.json文件中:

{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",

    "cloudflare-build": "opennextjs-cloudflare build --dangerouslyUseUnsupportedNextVersion",
    "preview":          "pnpm cloudflare-build && opennextjs-cloudflare preview",
    "deploy":           "pnpm cloudflare-build && wrangler deploy",
    "upload":           "pnpm cloudflare-build && opennextjs-cloudflare upload",
    "cf-typegen":       "wrangler types --env-interface CloudflareEnv cloudflare-env.d.ts"
  }
}

各脚本的功能如下:

脚本名称 功能
pnpm cloudflare-build 将你的Next.js应用程序编译为.open-next/格式的文件包(包含Worker组件),但不会进行上传操作。
pnpm preview 使用wrangler dev在本地构建并运行Worker组件,这个模式最接近生产环境下的运行效果。
pnpm deploy 构建完成后将应用程序上传到Cloudflare服务器,此操作会直接应用于生产环境
pnpm upload 构建并上传新版本的代码,但不会立即将其推送到生产环境(适用于分阶段部署的场景)。
pnpm cf-typegen 在修改了wrangler.jsonc文件后,重新生成cloudflare-env.d.ts类型定义文件。

提醒: 基于Pages框架的@cloudflare/next-on-pages是另一套工具。我们并未使用Pages框架,而是直接部署真正的Worker组件,因此请不要将这两种方案混淆。

步骤2——将Wire OpenNext连接到下一个开发环境

为了让 `pnpm dev` 能够像在生产环境中一样读取你的 Cloudflare 配置信息(环境变量、R2、KV、D1 等),请编辑 `next.config.mjs` 文件:

/** @type {import('next').NextConfig} */
const nextConfig = {};

if (process.env.NODE_ENV !== "production") {
  const { initOpenNextCloudflareForDev } = await import(
    "@opennextjs/cloudflare"
  );
  initOpenNextCloudflareForDev();
}

export default nextConfig;

我们只在开发环境中调用这个函数,这样 `next build` 的执行速度就不会受到影响,同时 CI 工具也不会无缘无故地启动 Miniflare 实例。

步骤 3 — 使用 `.dev.vars` 文件配置本地环境

在本地使用 Cloudflare Workers 时,Wrangler 会使用一个名为 `.dev_vars` 的文件来存储环境变量(而不是 Next.js 所使用的 `.env.local` 文件)。

一种简单且可靠的方法是在你的代码仓库中保留一个示例文件,而忽略真正的配置文件。

示例:`.devvars.example` 文件

NEXT_PUBLICSUPABASE_URL="https://YOUR-PROJECT-ref.supabase.co"
NEXTPUBLIC_supABASE_ANON_KEY="YOUR-ANON-KEY"
NEXT_PUBLIC_DASHBOARD_DEFAULT_EMAIL="admin@example.com"

配置你的本地环境

运行以下命令:

cp .devvars.example .dev_vars
cp .devVars .env.local

为什么需要同时使用这两个文件?

保持这两个文件的内容同步,可以确保你的应用程序在开发环境和 Cloudflare 运行环境中表现一致。

更新 `.gitignore` 文件

请确保以下文件被忽略:

.devvars
.env*.local
.open-next
.wrangler

步骤 4 — 从本地机器部署应用程序

当 `pnpm preview` 能够正常运行时,你就可以开始部署你的应用程序了:

pnpm deploy
实际执行的命令是:pnpm cloudflare-build && wrangler deploy

首次执行这些命令时,Wrangler 会完成以下操作:

  1. 将你的应用程序编译成 `.open-next/worker.js` 文件。

  2. 将生成的脚本文件及相关资源上传到 Cloudflare。

  3. 显示你的应用程序的在线地址,例如 `https://porfolio..workers.dev`。

在浏览器中打开该页面。恭喜您——现在您已经连接到了Cloudflare在全球330多个城市提供的边缘计算服务。无论从哪里访问,页面都应该能在<100毫秒内加载完成。

这是我用自己的这种方式部署的在线作品集

步骤5——将密钥上传到Worker节点

本地文件中的.devvars并不会被wrangler deploy自动上传到云端。因此,您需要手动将这些密钥上传:

wrangler secret put NEXT_PUBLIC_supABASE_URL
wrangler secret put NEXT_PUBLIC_SUPABASE_ANON_KEY
wrangler secret put NEXTPUBLIC_DASHBOARD_DEFAULT_EMAIL

您也可以通过Cloudflare的控制面板来操作这些密钥:

进入Cloudflare控制面板 → 选择Workers & Pages → 找到对应的Worker节点 → 进入Settings → 然后选择Variables and Secrets → 最后点击Add

重要提示:NEXT_PUBLIC_*这些变量会在构建过程中被嵌入到客户端的代码包中,因此当运行ppnm cloudflare-build命令时,这些变量也必须处于可用的状态(在本地开发环境中,这些变量通常存储在.env.local文件中;在持续集成环境中,请参考步骤10)。

步骤6——使用GitHub Actions设置持续部署

当您的本地开发环境能够正常运行后,下一步就是实现自动部署功能,这样每次向main分支进行推送操作时,生产环境都会自动更新。

通过以下工作流程,您可以实现这一目标:

  • 拉取请求会先执行验证步骤

  • 只有当构建过程成功完成后,才会进行生产环境的部署

  • 有问题的代码永远不会被发布到线上环境中

在您的项目目录中创建以下文件:

.github/workflows/deploy.yml

name: 持续集成/部署到Cloudflare Workers

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
  workflow_dispatch:

concurrency:
  group: cloudflare-deploy-${{ github.ref }}
  cancel-in-progress: true

jobs:
  verify:
    name: 代码检查与构建
    runs-on: ubuntu-latest
    timeout-minutes: 10

    steps:
      - uses: actions/checkout@v4

      - uses: pnpm/action-setup@v4
        with:
          version: 10

      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: pnpm

      - run: pnpm install --frozen-lockfile
      - run: pnpm lint
      - run: pnpm build
        env:
          NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.NEXTPUBLIC_supABASE_URL }}
          NEXT_PUBLICSUPABASE_ANON_KEY: ${{ secrets.NEXT_PUBLIC_supABASE_ANON_KEY }}
          NEXT_PUBLIC_DASHBOARD_DEFAULT_EMAIL: ${{ secrets.NEXT PUBLIC_Dashboard_DEFAULT_EMAIL }}

  deploy:
    name: 部署到Cloudflare Workers
    needs: verify
    if: github.event_name == 'push' & github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    timeout-minutes: 15

    steps:
      - uses: actions/checkout@v4

      - uses: pnpm/action-setup@v4
        with:
          version: 10

      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: pnpm

      - run: pnpm install --frozen-lockfile

      - name: 构建并部署
        run: pnpm run deploy
        env:
          CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
          CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE ACCOUNT_ID }}
          NEXT_PUBLIC_supABASE_URL: ${{ secrets.NEXTPUBLICSUPABASE_URL }}
          NEXT_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.NEXT_PUBLIC_supABASE_ANON_KEY }}
          NEXT_PUBLIC_DASHBOARD_DEFAULT_EMAIL: ${{ secrets.NEXT PUBLIC_Dashboard_DEFAULT_EMAIL }}

必需的 GitHub 仓库密钥

进入 GitHub 仓库 → 设置 → 密钥与变量 → 动作 → 新增仓库密钥,然后添加以下内容:

密钥 获取位置
CLOUDFLARE_API_TOKEN https://dash.cloudflare.com/profile/api-tokens → “编辑 Cloudflare Workers”模板
CLOUDFLARE_ACCOUNT_ID Cloudflare 控制面板 → 右侧边栏中的“账户 ID”
CLOUDFLARE ACCOUNT_SUBDOMAIN 你的*.workers.dev子域名(仅用于部署链接)
NEXT_PUBLICSUPABASE_URL Supabase 项目设置
NEXT_public_supABASE_ANON_KEY Supabase 项目设置
NEXTPUBLIC_DASHBOARD_DEFAULT_EMAIL /dashboard/login页面中预先填充的电子邮件地址

就这样。将这些密钥推送到main分支后,大约 90 秒后系统就会正式上线。提交 Pull Request 后,系统只会执行代码检查与构建操作,因此有问题的代码永远不会被部署到生产环境中。

步骤 7 — 更新项目(日常开发流程)

完成初始设置后,后续的开发流程其实非常简单,而这正是我们追求的目标。以下是我每天的实际操作步骤:

代码修改

git checkout -b feat/new-section
# ...编辑文件...
pnpm dev                # 在本地进行开发测试
pnpm preview            # 在 Worker 运行环境中进行最终测试
git commit -am "feat: 添加新章节"
git push origin feat/new-section

提交 Pull Request 后,需要确认相关任务是否已经成功运行。然后审核代码、合并更改,并将其部署到生产环境。这些操作会自动由 Cloudflare 完成。

更新环境变量/密钥

# 本地开发环境
nano .dev.vars

# 生产环境
wrangler secret put NEXT_PUBLICSUPABASE_URL
# ...其他操作...

最后的思考

当初开始进行这次迁移时,我其实很担心离开 Vercel——因为 Vercel 提供的 Next.js 开发体验确实非常优秀。但一旦你的项目规模超出了个人业余项目的范围,Cloudflare 的经济性优势与边缘计算性能就远远无法与之相比了。

借助 @opennextjs/cloudflare,开发者的使用体验也得到了显著提升:我的pnpm dev操作流程与本地开发环境完全一致,pnpm preview可以模拟生产环境进行测试,而git push命令也能在大约 90 秒内完成全局部署。

如果你之前因为 Cloudflare Pages 与 Next.js 的配合体验不佳而犹豫不决,那么现在这个时机已经到了。这个周末可以在你的副项目中尝试这套开发流程,亲自验证它的效果吧。

如果你觉得这些内容对你有帮助,完整的代码仓库可以在这里找到——你可以随时克隆它作为起点来开始你的项目开发。

祝你的项目顺利上线!

塔里库尔

Comments are closed.