tanstack-start
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTanStack Start
TanStack Start
Full-stack React framework with SSR, server functions, and Vite bundling.
基于SSR、服务端函数和Vite打包的全栈React框架。
Project Setup
项目搭建
New project:
bash
pnpm create cloudflare@latest my-app --framework=tanstack-start -y --no-deployExisting app: See references/migration.md for converting React/Vite apps.
新项目:
bash
pnpm create cloudflare@latest my-app --framework=tanstack-start -y --no-deploy现有项目: 如需将React/Vite项目迁移,请查看references/migration.md。
Critical Configuration
关键配置
vite.config.ts
vite.config.ts
typescript
import { defineConfig } from 'vite'
import tsConfigPaths from 'vite-tsconfig-paths'
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
import viteReact from '@vitejs/plugin-react'
export default defineConfig({
plugins: [
tsConfigPaths(),
tanstackStart(),
viteReact(), // MUST come AFTER tanstackStart
],
})typescript
import { defineConfig } from 'vite'
import tsConfigPaths from 'vite-tsconfig-paths'
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
import viteReact from '@vitejs/plugin-react'
export default defineConfig({
plugins: [
tsConfigPaths(),
tanstackStart(),
viteReact(), // 必须在tanstackStart之后
],
})tsconfig.json gotcha
tsconfig.json 注意事项
Do NOT enable - it leaks server bundles into client bundles.
verbatimModuleSyntax请勿启用——它会导致服务端包泄露到客户端包中。
verbatimModuleSyntaxServer Functions
服务端函数
See references/server-functions.md for complete guide.
⚠️ Critical: Route loaders run on server for initial SSR, but run on CLIENT during navigation. Always wrap server code into ensure it runs server-side.createServerFn()
When to use what (Cloudflare Workers):
| Use Case | Solution |
|---|---|
| Server code in route loaders | |
| Server code from client event handlers | API routes ( |
| Access Cloudflare bindings | |
createServerFn - for loaders:
typescript
import { createServerFn } from '@tanstack/react-start'
export const getData = createServerFn().handler(async () => {
return { data: process.env.SECRET } // Server-only
})API routes - for client event handlers:
tsx
// routes/api/users.ts
export const Route = createFileRoute('/api/users')({
server: {
handlers: {
POST: async ({ request }) => {
const body = await request.json()
return Response.json(await db.users.create(body))
},
},
},
})
// In component: fetch('/api/users', { method: 'POST', body: JSON.stringify(data) })Key APIs:
- - Server-only functions for loaders
createServerFn() - - API routes for client event handlers
server.handlers - - Reusable middleware
createMiddleware({ type: 'function' }) - :
@tanstack/react-start/server,getRequestHeaders(),setResponseHeader()getCookies()
完整指南请查看references/server-functions.md。
⚠️ 重要提示:路由加载器在初始SSR时运行在服务端,但在导航过程中运行在客户端。请始终将服务端代码包裹在中,以确保其在服务端运行。createServerFn()
使用场景对应方案(Cloudflare Workers):
| 使用场景 | 解决方案 |
|---|---|
| 路由加载器中的服务端代码 | |
| 客户端事件处理器调用的服务端代码 | API路由( |
| 访问Cloudflare绑定 | |
createServerFn - 用于加载器:
typescript
import { createServerFn } from '@tanstack/react-start'
export const getData = createServerFn().handler(async () => {
return { data: process.env.SECRET } // 仅服务端可用
})API路由 - 用于客户端事件处理器:
tsx
// routes/api/users.ts
export const Route = createFileRoute('/api/users')({
server: {
handlers: {
POST: async ({ request }) => {
const body = await request.json()
return Response.json(await db.users.create(body))
},
},
},
})
// 在组件中调用: fetch('/api/users', { method: 'POST', body: JSON.stringify(data) })核心API:
- - 用于加载器的仅服务端函数
createServerFn() - - 供客户端事件处理器调用的API路由
server.handlers - - 可复用中间件
createMiddleware({ type: 'function' }) - :
@tanstack/react-start/server,getRequestHeaders(),setResponseHeader()getCookies()
Routing
路由
See references/routing.md for complete patterns.
File conventions in :
src/routes/| Pattern | Route |
|---|---|
| |
| |
| Layout (no URL) |
| Root layout (required) |
tsx
import { createFileRoute } from '@tanstack/react-router'
import { createServerFn } from '@tanstack/react-start'
const getPost = createServerFn()
.handler(async () => await db.post.findFirst())
export const Route = createFileRoute('/posts/$postId')({
loader: ({ params }) => getPost({ data: params.postId }),
component: () => {
const post = Route.useLoaderData()
return <h1>{post.title}</h1>
},
})完整路由模式请查看references/routing.md。
src/routes/| 模式 | 路由 |
|---|---|
| |
| |
| 布局(无对应URL) |
| 根布局(必填) |
tsx
import { createFileRoute } from '@tanstack/react-router'
import { createServerFn } from '@tanstack/react-start'
const getPost = createServerFn()
.handler(async () => await db.post.findFirst())
export const Route = createFileRoute('/posts/$postId')({
loader: ({ params }) => getPost({ data: params.postId }),
component: () => {
const post = Route.useLoaderData()
return <h1>{post.title}</h1>
},
})Cloudflare Deployment
Cloudflare部署
See references/cloudflare-deployment.md for complete guide.
bash
pnpm add -D @cloudflare/vite-plugin wranglervite.config.ts - add cloudflare plugin:
typescript
import { cloudflare } from '@cloudflare/vite-plugin'
// Add to plugins: cloudflare({ viteEnvironment: { name: 'ssr' } })wrangler.jsonc:
jsonc
{
"$schema": "./node_modules/wrangler/config-schema.json",
"name": "my-app",
"compatibility_date": "<CURRENT_DATE>", // Use today's YYYY-MM-DD
"compatibility_flags": ["nodejs_compat"],
"main": "@tanstack/react-start/server-entry",
"observability": { "enabled": true }
}Access Cloudflare bindings in server functions:
typescript
import { env } from 'cloudflare:workers'
const value = await env.MY_KV.get('key')Static Prerendering (v1.138.0+):
typescript
tanstackStart({ prerender: { enabled: true } })完整部署指南请查看references/cloudflare-deployment.md。
bash
pnpm add -D @cloudflare/vite-plugin wranglervite.config.ts - 添加cloudflare插件:
typescript
import { cloudflare } from '@cloudflare/vite-plugin'
// 添加到plugins中: cloudflare({ viteEnvironment: { name: 'ssr' } })wrangler.jsonc:
jsonc
{
"$schema": "./node_modules/wrangler/config-schema.json",
"name": "my-app",
"compatibility_date": "<CURRENT_DATE>", // 使用当前日期,格式为YYYY-MM-DD
"compatibility_flags": ["nodejs_compat"],
"main": "@tanstack/react-start/server-entry",
"observability": { "enabled": true }
}在服务端函数中访问Cloudflare绑定:
typescript
import { env } from 'cloudflare:workers'
const value = await env.MY_KV.get('key')静态预渲染(v1.138.0及以上版本):
typescript
tanstackStart({ prerender: { enabled: true } })TanStack Query Integration
TanStack Query集成
See references/query-integration.md for SSR setup.
bash
pnpm add @tanstack/react-query @tanstack/react-router-ssr-querytsx
// Preload in loaders, consume with useSuspenseQuery
loader: ({ context }) => context.queryClient.ensureQueryData(myQueryOptions)SSR设置请查看references/query-integration.md。
bash
pnpm add @tanstack/react-query @tanstack/react-router-ssr-querytsx
// 在加载器中预加载,使用useSuspenseQuery消费数据
loader: ({ context }) => context.queryClient.ensureQueryData(myQueryOptions)Better-Auth Integration
Better-Auth集成
See references/better-auth.md for complete guide.
⚠️ Critical: UsewithcreateFileRoute, NOT the legacyserver.handlers.createAPIFileRoute
Mount the auth handler at :
/src/routes/api/auth/$.tstypescript
import { auth } from '@/lib/auth'
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/api/auth/$')({
server: {
handlers: {
GET: ({ request }) => auth.handler(request),
POST: ({ request }) => auth.handler(request),
},
},
})Auth config with plugin:
tanstackStartCookiestypescript
import { betterAuth } from "better-auth"
import { tanstackStartCookies } from "better-auth/tanstack-start"
export const auth = betterAuth({
// ...your config
plugins: [tanstackStartCookies()] // MUST be last plugin
})Protect routes with middleware:
typescript
import { createMiddleware } from "@tanstack/react-start"
import { getRequestHeaders } from "@tanstack/react-start/server"
import { auth } from "./auth"
export const authMiddleware = createMiddleware().server(
async ({ next }) => {
const session = await auth.api.getSession({ headers: getRequestHeaders() })
if (!session) throw redirect({ to: "/login" })
return next()
}
)
// In route:
export const Route = createFileRoute('/dashboard')({
server: { middleware: [authMiddleware] },
component: Dashboard,
})完整指南请查看references/better-auth.md。
⚠️ 重要提示:请使用搭配createFileRoute,而非旧版的server.handlers。createAPIFileRoute
在挂载认证处理器:
/src/routes/api/auth/$.tstypescript
import { auth } from '@/lib/auth'
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/api/auth/$')({
server: {
handlers: {
GET: ({ request }) => auth.handler(request),
POST: ({ request }) => auth.handler(request),
},
},
})搭配插件的认证配置:
tanstackStartCookiestypescript
import { betterAuth } from "better-auth"
import { tanstackStartCookies } from "better-auth/tanstack-start"
export const auth = betterAuth({
// ...你的配置
plugins: [tanstackStartCookies()] // 必须是最后一个插件
})使用中间件保护路由:
typescript
import { createMiddleware } from "@tanstack/react-start"
import { getRequestHeaders } from "@tanstack/react-start/server"
import { auth } from "./auth"
export const authMiddleware = createMiddleware().server(
async ({ next }) => {
const session = await auth.api.getSession({ headers: getRequestHeaders() })
if (!session) throw redirect({ to: "/login" })
return next()
}
)
// 在路由中使用:
export const Route = createFileRoute('/dashboard')({
server: { middleware: [authMiddleware] },
component: Dashboard,
})GitHub Actions Auto-Deploy
GitHub Actions自动部署
See references/github-actions-deploy.md for CI/CD setup with preview deployments.
如需设置带预览部署的CI/CD,请查看references/github-actions-deploy.md。