TanStack Start Deployment: 3分钟完成边缘部署(真实配置)

真实的部署流水线。将 TanStack Start 部署到 Cloudflare Workers 全流程详解:CI/CD 配置、预览部署与回滚策略。

Sam Rivera
Sam Rivera
May 29, 202611 min read
其他语言:Deutsch · English

TL;DR: 将 TanStack Start 应用部署到 Cloudflare Workers,需要精细配置 wrangler.jsonc、跨开发和生产环境管理环境变量、配置 D1 数据库及自动化迁移、集成 R2 对象存储,并搭建可靠的 CI/CD 流水线。本指南涵盖从脚手架搭建到生产监控的每一步,助你在 Cloudflare 边缘网络上自信交付。


引言:为什么选择 Cloudflare Workers 部署 TanStack Start

TanStack Start 是构建在 Vinxi 之上的全栈 React 框架,将服务端渲染、流式传输和静态生成带入 TanStack 生态。在部署层面,Cloudflare Workers 为 Start 应用提供了极具吸引力的运行时选择。

与需要冷启动、区域固定和手动扩缩容的传统 Node.js 服务器不同,Cloudflare Workers 基于 V8 isolate 运行在全球 330+ 个位置。这意味着你的 TanStack Start 应用可以从边缘向每位用户就近提供初始 HTML、流式内容更新和处理 API 请求。

但这种架构转变也带来了新的配置挑战。Workers 运行时不支持 Node.js API(如 fs、net、child_process)。构建流水线、环境变量和数据库连接都需要进行适配。本指南将详细介绍我们大规模运行 TanStack Start on Cloudflare Workers 所用的生产就绪配置。


wrangler.jsonc 深度配置

wrangler.jsonc 是 Cloudflare 部署的单一真相来源。以下是我们使用的生产配置,并附有详细注解:

jsonc
{
  "$schema": "https://raw.githubusercontent.com/cloudflare/workers-sdk/main/packages/wrangler/config-schema.json",
  "name": "tanstack-ship",
  "main": "./dist/worker.js",
  "compatibility_date": "2026-05-01",
  "compatibility_flags": ["nodejs_compat"],
  "assets": {
    "directory": "./dist/public",
    "binding": "ASSETS",
    "html_handling": "auto",
    "not_found_handling": "404"
  },
  "workers_dev": false,
  "route": {
    "pattern": "tanstack-ship.com",
    "custom_domain": true,
    "zone_id": "YOUR_ZONE_ID"
  },
  "d1_databases": [
    {
      "binding": "DB",
      "database_name": "tanstack-ship-db",
      "database_id": "YOUR_D1_DATABASE_ID",
      "migrations_dir": "./migrations"
    }
  ],
  "r2_buckets": [
    {
      "binding": "R2",
      "bucket_name": "tanstack-ship-assets"
    }
  ],
  "vars": {
    "APP_VERSION": "1.0.0",
    "SENTRY_DSN": ""
  },
  "env": {
    "production": {
      "vars": {
        "SENTRY_DSN": "https://your-sentry-dsn@o123.ingest.sentry.io/456"
      },
      "routes": [
        {
          "pattern": "tanstack-ship.com",
          "custom_domain": true
        }
      ]
    },
    "preview": {
      "workers_dev": true,
      "vars": {
        "SENTRY_DSN": ""
      }
    }
  },
  "observability": {
    "enabled": true,
    "head_sampling_rate": 0.1
  }
}

关键字段说明

  • compatibility_flags:nodejs_compat 标志启用部分 Node.js API(如 Buffer、process.env)。许多 npm 包依赖这些 API,请务必保持此标志开启。
  • assets:html_handling: "auto" 指示 Workers 对目录请求返回 index.html——这对客户端路由兜底至关重要。not_found_handling: "404" 确保未知路径返回正确的 404。
  • env 块:定义环境特定覆盖。preview 环境使用 workers_dev: true 以适配 *.workers.dev 子域名,而 production 则绑定自定义域名。

环境变量:开发 vs 生产

本地开发

在项目根目录创建 .dev.vars 文件:

# .dev.vars — 由 wrangler dev 加载
SENTRY_DSN=
STRIPE_SECRET_KEY=your-stripe-secret-key
RESEND_API_KEY=your-resend-api-key
PUBLIC_SITE_URL=http://localhost:5173

Cloudflare 的 wrangler dev 命令会自动读取 .dev.vars 并将其注入 Worker 运行时。

生产密钥

对于生产密钥,请使用 wrangler secret put 将敏感值与配置文件隔离:

bash
npx wrangler secret put SENTRY_DSN
npx wrangler secret put STRIPE_SECRET_KEY

密钥在静态时加密,在边缘运行时注入。它们不会出现在 wrangler.jsonc 的 vars 区段中——这是常见的安全错误。

类型安全的访问模式

将所有环境变量访问集中到一个模块中,并使用 Zod 进行运行时验证:

typescript
// src/env.ts
import { z } from "zod";

const envSchema = z.object({
  SENTRY_DSN: z.string().optional(),
  STRIPE_SECRET_KEY: z.string().min(1),
  RESEND_API_KEY: z.string().min(1),
  PUBLIC_SITE_URL: z.string().url().default("http://localhost:5173"),
  DB: z.any(),    // D1 binding
  R2: z.any(),    // R2 binding
  ASSETS: z.any(), // Assets binding
});

export type Env = z.infer<typeof envSchema>;

export function parseEnv(env: Record<string, unknown>): Env {
  const result = envSchema.safeParse(env);
  if (!result.success) {
    console.error("Invalid environment variables:", result.error.flatten());
    throw new Error("Environment validation failed");
  }
  return result.data;
}

此模式提供运行时类型安全,并在 CI 早期阶段捕获配置错误的环境。


D1 数据库配置与迁移

1. 创建数据库

bash
npx wrangler d1 create tanstack-ship-db

将返回的 database_id 复制到 wrangler.jsonc 中。

2. 编写迁移

将 SQL 迁移文件放在 migrations/ 目录中:

sql
-- migrations/0001_users.sql
CREATE TABLE IF NOT EXISTS users (
  id TEXT PRIMARY KEY,
  email TEXT UNIQUE NOT NULL,
  name TEXT NOT NULL,
  created_at TEXT NOT NULL DEFAULT (datetime('now'))
);

CREATE INDEX idx_users_email ON users(email);

3. 应用迁移

本地:

bash
npx wrangler d1 migrations apply tanstack-ship-db --local

生产:

bash
npx wrangler d1 migrations apply tanstack-ship-db --remote

4. CI 中的自动化迁移

yaml
# .github/workflows/deploy.yml(节选)
- name: Apply D1 Migrations
  run: npx wrangler d1 migrations apply tanstack-ship-db --remote
  env:
    CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}

在部署新版本 Worker 之前运行迁移,实现零停机时间部署。


R2 对象存储集成

在 wrangler.jsonc 中添加 R2 绑定后,配置客户端以处理文件上传和获取:

typescript
// src/lib/r2-client.ts
import type { R2Bucket } from "@cloudflare/workers-types";

let bucket: R2Bucket;

export function initR2(r2: R2Bucket) {
  bucket = r2;
}

export async function uploadFile(
  key: string,
  body: ReadableStream | ArrayBuffer,
  contentType: string
) {
  return bucket.put(key, body, {
    httpMetadata: { contentType },
    customMetadata: { uploadedAt: new Date().toISOString() },
  });
}

export async function getFile(key: string) {
  const object = await bucket.get(key);
  if (!object) return null;
  return object;
}

生产环境优化

缓存响应头

typescript
function setCachingHeaders(response: Response, pathname: string): Response {
  const headers = new Headers(response.headers);

  // 静态资源:长期缓存
  if (/\.(js|css|png|jpg|webp|svg|woff2?)$/i.test(pathname)) {
    headers.set("Cache-Control", "public, max-age=31536000, immutable");
  }
  // HTML 页面:短期 CDN 缓存,浏览器不缓存
  else if (pathname.endsWith(".html") || !pathname.includes(".")) {
    headers.set("Cache-Control", "public, s-maxage=60, stale-while-revalidate=600");
  }

  return new Response(response.body, {
    status: response.status,
    headers,
  });
}

启用流式传输

jsonc
// wrangler.jsonc
{
  "compatibility_flags": ["nodejs_compat"],
  "streaming": true
}

启用流式传输后,Suspense 边界可以逐步发送内容,改善用户感知的加载性能。


CI/CD 流水线配置

yaml
# .github/workflows/deploy.yml
name: Deploy
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: "22"
      - run: npm ci
      - run: npm run typecheck
      - run: npm run lint
      - run: npm run build
        env:
          PUBLIC_SITE_URL: ${{ vars.PUBLIC_SITE_URL }}
      - name: Apply D1 Migrations
        run: npx wrangler d1 migrations apply tanstack-ship-db --remote
        env:
          CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
      - name: Deploy to Cloudflare Workers
        run: npx wrangler deploy --env production
        env:
          CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}

常见部署问题及解决方案

  1. Node.js 内置模块 "Module not found":启用 nodejs_compat 标志。若仍然报错,请寻找 Workers 兼容的替代方案。

  2. D1 迁移报 "Table already exists":始终使用 CREATE TABLE IF NOT EXISTS 和 CREATE INDEX IF NOT EXISTS。

  3. 刷新时客户端路由返回 404:确认 wrangler.jsonc 中设置了 html_handling: "auto"。

  4. 环境变量在运行时未定义:将密钥迁移至 wrangler secret put,vars 区段仅用于非敏感配置。

  5. 打包体积超过 1MB 限制:确保 Vite 构建进行了 tree-shaking。对重型依赖使用动态 import()。


结语

将 TanStack Start 部署到 Cloudflare Workers,是交付全栈 React 应用最高性能且最具性价比的方式之一。边缘运行时带来全球分发、即时冷启动和慷慨的免费额度。

核心要点:

  • 使用 Zod 在边缘验证环境变量,在任何逻辑运行之前。
  • 在部署之前运行迁移,而非之后。
  • 积极但审慎地设置缓存响应头——HTML 使用 s-maxage,静态资源使用 immutable。
  • 尽早启用可观测性——出现问题时你会需要这些链路追踪。

如需亲手实践完整应用的构建流程,请参阅 TanStack Start 端到端教程。如需将 D1 数据库推至生产,请阅读 边缘数据库:Cloudflare D1 生产实践。官方参考请查阅 Wrangler CLI、Cloudflare D1 和 R2 文档。