Cloudflare Workers 部署
把同一套 TanStack Start 代码部署到 Cloudflare Workers,同时继续使用 PostgreSQL 和 S3/R2 存储。
Cloudflare Workers 部署适合主要用户在海外、希望用 Cloudflare 边缘运行时承载 Web 服务的项目。01MVP Start 使用 Muse Web 的 Worker 入口,并通过 Cloudflare Vite 插件生成 Workers 可运行产物。
Cloudflare Workers 路径和 Docker 路径共用 PostgreSQL、S3/R2、账号、支付、后台和业务代码。它不是 D1 分支,也不是第二套产品代码。
适用场景
| 场景 | 建议 |
|---|---|
| 用户主要在国内,需要备案路径或更可控的服务器网络 | 用 Zeabur 部署 或 Docker 部署 |
| 用户主要在海外,希望低成本部署 Web 服务 | 用 Cloudflare Workers |
| 只需要 Cloudflare DNS、CDN、WAF | 不需要迁移应用运行时,继续用 Zeabur 或 Docker |
| 已经决定 Cloudflare-first,并且业务很轻 | 可以另行评估 D1,但不是模板默认路径 |
和 Docker 共用什么
Workers 部署只替换 Web 运行时,不替换核心底座:
| 层级 | 选择 |
|---|---|
| 数据库 | PostgreSQL,例如 Supabase、Neon、Zeabur PostgreSQL 或自有 PostgreSQL |
| 对象存储 | Cloudflare R2 或其他 S3 兼容存储 |
| Auth / API / 支付 / 后台 | 继续使用同一套 @muse/auth、@muse/api、@muse/db 和 Web 代码 |
| 静态资源 | Workers Assets 提供前端静态资源 |
这样做可以让国内部署和海外部署共用一套代码。国内用户多时,把 Web 跑在国内服务器或 Zeabur Docker;海外用户多时,把 Web 跑在 Cloudflare Workers,数据库仍然使用 PostgreSQL。
跑通后的关键经验
Cloudflare Workers 路径能成立,关键是只把 Web 运行时换到 Worker,数据库、存储和业务代码继续沿用同一套主线:
| 问题 | 推荐处理 |
|---|---|
| PostgreSQL 连接 | 生产环境优先用 Cloudflare Hyperdrive。Worker 绑定 HYPERDRIVE,运行时读取 env.HYPERDRIVE.connectionString 给 Drizzle/Postgres.js |
| 数据库连接池 | Workers 不适合把普通 PostgreSQL client 当 Node 服务一样长期全局缓存。Hyperdrive 会维护底层连接池,应用侧按请求创建轻量 client 更稳 |
| SSR 内部 API 调用 | Node/Docker 可以把服务端 oRPC 请求改写到 127.0.0.1;Worker 不能这样做。Worker 中应让服务端 oRPC 直接调用同一个 Hono app,避免自请求公网域名或 loopback |
| 原生 Node 模块 | sharp 这类原生模块不能作为 Worker SSR 路径的顶层 import。只在真正需要图片处理的上传/OG 路由里动态加载,或换成 Worker 兼容服务 |
| 验证标准 | 不能只看首页 200。必须验证 /api/health 的 database check、一个依赖 SSR 数据加载的页面,以及登录/支付/上传等核心路径 |
这个经验会影响代码结构:Cloudflare 是同一套 Web 代码的第二个运行时。运行时差异应该收敛在 Worker 入口、数据库连接创建、服务端 RPC fetch 和少数不兼容 SDK 的加载方式上。
为什么不是 D1
D1 可以用于轻量网站,但 01MVP Start 默认不把 D1 作为长期主库:
- 模板内置账号、支付、订单、后台、积分和 AI 任务,这些系统后续会持续增长
- PostgreSQL 在复杂查询、事务、索引、备份、迁移和跨平台托管上更适合作为长期数据库
- 如果一开始用 D1,业务变重后再迁移到 PostgreSQL,会比一开始统一 PostgreSQL 更贵
- Workers 可以连接 PostgreSQL,因此没有必要为了使用 Workers 就拆出一套 D1 数据层
只做轻量 Cloudflare 项目时可以单独评估 D1;否则建议继续用 PostgreSQL。
当前脚本
products/muse/apps/web/package.json 中保留了 Cloudflare 相关脚本:
vpr @muse/web#build:cf
vpr @muse/web#preview:cf
vpr @muse/web#deploy:cf这些脚本会启用 CF_DEPLOY=1,让 Vite 加载 @cloudflare/vite-plugin,并输出 TanStack Start 的 Workers 产物。脚本不写死生产域名;VITE_WEB_URL 和 VITE_SERVER_URL 优先从外部环境变量、products/muse/packages/config/.env 或共享配置 packages/config/.env 读取。只有这些位置都没有提供时,脚本才使用模板内置的生产 URL 默认值。
Wrangler 配置
配置文件位于 products/muse/apps/web/wrangler.jsonc。核心结构如下:
{
"name": "muse",
"main": "./src/server.ts",
"compatibility_flags": ["nodejs_compat", "nodejs_compat_populate_process_env"],
"assets": {
"directory": "./dist/client",
"binding": "ASSETS"
},
"routes": [
{
"pattern": "cfmuse.01mvp.com",
"custom_domain": true
}
],
"vars": {
"VITE_WEB_URL": "https://cfmuse.01mvp.com",
"VITE_SERVER_URL": "https://cfmuse.01mvp.com/api",
"AUTH_COOKIE_PREFIX": "cfmuse-session",
"NODE_ENV": "production",
"HEALTH_CHECK_TIMEOUT_MS": "5000",
"HEALTH_CHECK_DATABASE_RETRIES": "2",
"HEALTH_CHECK_DATABASE_RETRY_DELAY_MS": "250",
"AUTH_CAPTCHA_MODE": "off",
"CAPTCHA_MODE": "off",
"CAPTCHA_PROVIDER": "off"
},
"hyperdrive": [
{
"binding": "HYPERDRIVE",
"id": "<your-hyperdrive-id>"
}
]
}./src/server.ts 是 Worker 专用入口。它会把 Worker bindings 注入到 server runtime env,在存在 HYPERDRIVE 绑定时把 env.HYPERDRIVE.connectionString 写入 DATABASE_URL,并让 SSR 期间的 oRPC 请求直接进入同一个 Hono app,避免 Worker 自请求公网域名。
正式接入前需要按项目补充:
- 生产域名 routes 或 custom domain
- PostgreSQL 连接方式,推荐 Hyperdrive;如果不用 Hyperdrive,再评估连接池或数据库提供商的 Serverless 连接方案
- Secret 环境变量
- R2、KV、Hyperdrive 等 Cloudflare 绑定
- 日志与观测配置
本地预览
安装依赖
vp install --frozen-lockfile生成 Worker 构建产物
vpr @muse/web#build:cf本地预览
vpr @muse/web#preview:cf打开预览地址,检查首页、文档页、登录入口、API 路由和静态资源。
环境变量和 Secret
Cloudflare Workers 不会自动读取 Zeabur 或本地 .env.prd 环境变量。生产密钥要用 Wrangler Secret 或 Cloudflare Dashboard 配置。
如果使用 Hyperdrive,数据库连接串不需要长期作为 Worker Secret 维护;Worker 运行时从 HYPERDRIVE binding 读取 connectionString。如果你使用 Supabase、Neon 或其他 Serverless PostgreSQL 方案,不经过 Hyperdrive,才把对应连接串作为 DATABASE_URL secret。
cd products/muse/apps/web
vp exec wrangler secret put BETTER_AUTH_SECRET
vp exec wrangler secret put OPENAI_API_KEY创建 Hyperdrive 时使用目标 PostgreSQL 的公网连接信息:
vp exec wrangler hyperdrive create app-postgres \
--connection-string "postgresql://user:password@host:5432/database" \
--sslmode require \
--caching-disabled \
--origin-connection-limit 5 \
--binding HYPERDRIVE创建成功后,把返回的 id 写入 wrangler.jsonc 的 hyperdrive binding。
构建期需要 VITE_WEB_URL 和 VITE_SERVER_URL 指向目标域名。可以把它们写入部署环境变量;本地验证时也可以临时在命令前传入:
VITE_WEB_URL=https://your-domain.com \
VITE_SERVER_URL=https://your-domain.com/api \
vpr @muse/web#build:cf公开变量可以放在 wrangler.jsonc 的 vars 中,但不要把真实密钥写进 vars。
Serverless/edge 数据库连接需要单独评估。生产环境通常使用 Hyperdrive、连接池或数据库提供商的 Serverless 连接方案,不建议让每个 Worker 请求无限制直连 PostgreSQL。
运行时适配点
接入 Cloudflare Workers 时,至少保留以下运行时适配:
- Worker
fetch(req, env)里先把env注入服务端运行时配置,再创建 TanStack Start handler。 - 如果存在
env.HYPERDRIVE.connectionString,优先把它作为运行时DATABASE_URL,覆盖普通DATABASE_URLsecret。 - Drizzle/Postgres.js 在 Hyperdrive 环境下使用较小连接数,例如
max: 5;如果没有数组类型需求,可以关闭fetch_types减少一次额外往返。 - Worker 环境不要复用 Node/Docker 的
127.0.0.1服务端 RPC URL。服务端 oRPC 请求应走同进程 Hono adapter。 - 检查服务端入口的顶层 import。文件系统、原生模块、长连接 SDK、图片处理库都可能在 Worker 上失败,应该延迟到具体路由或替换成兼容实现。
兼容性验证
Cloudflare Workers 和 Node.js 运行时不完全一致。部署前至少验证:
-
vpr @muse/web#build:cf成功 -
vpr @muse/web#preview:cf能打开首页和核心文档页 -
/api/docs-search能返回搜索结果 -
/api/health返回 healthy,并且checks.database.status是healthy - 一个依赖服务端数据加载的页面返回 200,例如 checkout、后台列表或账号页
- 登录、注册、OAuth 回调和 session 行为正常
- Drizzle 能连接目标数据库
- 文件上传、S3/R2 访问和公开 URL 正常
- AI、邮件、支付 SDK 在 Workers 运行时无兼容性错误
- 静态资源和文档 assets 无 404
发布
确认本地预览通过后再执行部署:
vpr @muse/web#deploy:cf部署后检查:
vp exec wrangler deployments status再访问生产域名,按部署后验证逐项检查。
常见问题
上线检查
-
wrangler.jsonc中的 worker 名称、域名和 bindings 已按项目更新 - 所有密钥已通过 Wrangler Secret 或 Dashboard 配置
- 数据库连接方案已验证
-
build:cf和preview:cf都通过 - 文档 assets、搜索、登录、上传、AI、邮件和支付都在 Workers 预览环境验证过
- 部署后确认 Cloudflare 已收到最新版本
想和其他创造者交流?
这篇文档有问题?