tanstack-start
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTanStack Start Skills
TanStack Start 技能
Overview
概述
TanStack Start is a full-stack React framework built on TanStack Router, powered by Vite and Nitro (via Vinxi). It provides server-side rendering, streaming, server functions (RPC), middleware, API routes, and deploys to any platform via Nitro presets.
Package:
Router Plugin:
Build Tool: Vinxi (Vite + Nitro)
Status: RC (Release Candidate)
RSC Support: React Server Components support is in active development and will land as a non-breaking v1.x addition
@tanstack/react-start@tanstack/router-pluginTanStack Start是基于TanStack Router构建的全栈React框架,由Vite和Nitro(通过Vinxi)提供支持。它提供服务端渲染(SSR)、流式渲染、服务器函数(RPC)、中间件、API路由,并可通过Nitro预设部署至任意平台。
包:
路由插件:
构建工具: Vinxi(Vite + Nitro)
状态: RC(候选发布版)
RSC支持: React Server Components支持正在积极开发中,将作为非破坏性更新加入v1.x版本
@tanstack/react-start@tanstack/router-pluginInstallation & Project Setup
安装与项目设置
bash
npx @tanstack/cli create my-appbash
npx @tanstack/cli create my-appOr manually:
或手动安装:
npm install @tanstack/react-start @tanstack/react-router react react-dom
npm install -D @tanstack/router-plugin typescript vite vite-tsconfig-paths
undefinednpm install @tanstack/react-start @tanstack/react-router react react-dom
npm install -D @tanstack/router-plugin typescript vite vite-tsconfig-paths
undefinedProject Structure
项目结构
my-app/
app/
routes/
__root.tsx # Root layout
index.tsx # / route
posts.$postId.tsx # /posts/:postId
api/
users.ts # /api/users API route
client.tsx # Client entry
router.tsx # Router creation
ssr.tsx # SSR entry
routeTree.gen.ts # Auto-generated route tree
app.config.ts # TanStack Start config
tsconfig.json
package.jsonmy-app/
app/
routes/
__root.tsx # 根布局
index.tsx # / 路由
posts.$postId.tsx # /posts/:postId 路由
api/
users.ts # /api/users API路由
client.tsx # 客户端入口
router.tsx # 路由创建文件
ssr.tsx # SSR入口
routeTree.gen.ts # 自动生成的路由树
app.config.ts # TanStack Start配置文件
tsconfig.json
package.jsonConfiguration (app.config.ts
)
app.config.ts配置(app.config.ts
)
app.config.tstypescript
import { defineConfig } from '@tanstack/react-start/config'
import viteTsConfigPaths from 'vite-tsconfig-paths'
export default defineConfig({
vite: {
plugins: [
viteTsConfigPaths({ projects: ['./tsconfig.json'] }),
],
},
server: {
preset: 'node-server', // 'vercel' | 'netlify' | 'cloudflare-pages' | etc.
},
tsr: {
appDirectory: './app',
routesDirectory: './app/routes',
generatedRouteTree: './app/routeTree.gen.ts',
},
})typescript
import { defineConfig } from '@tanstack/react-start/config'
import viteTsConfigPaths from 'vite-tsconfig-paths'
export default defineConfig({
vite: {
plugins: [
viteTsConfigPaths({ projects: ['./tsconfig.json'] }),
],
},
server: {
preset: 'node-server', // 'vercel' | 'netlify' | 'cloudflare-pages' | 其他
},
tsr: {
appDirectory: './app',
routesDirectory: './app/routes',
generatedRouteTree: './app/routeTree.gen.ts',
},
})Server Functions (createServerFn
)
createServerFn服务器函数(createServerFn
)
createServerFnServer functions provide type-safe RPC calls between client and server.
服务器函数支持客户端与服务器之间的类型安全RPC调用。
Basic Server Functions
基础服务器函数
typescript
import { createServerFn } from '@tanstack/react-start'
// GET (data fetching, cacheable)
const getUsers = createServerFn()
.handler(async () => {
const users = await db.query.users.findMany()
return users
})
// POST (mutations, side effects)
const createUser = createServerFn({ method: 'POST' })
.validator((data: { name: string; email: string }) => data)
.handler(async ({ data }) => {
const user = await db.insert(users).values(data).returning()
return user
})typescript
import { createServerFn } from '@tanstack/react-start'
// GET(数据获取,可缓存)
const getUsers = createServerFn()
.handler(async () => {
const users = await db.query.users.findMany()
return users
})
// POST(数据变更,副作用操作)
const createUser = createServerFn({ method: 'POST' })
.validator((data: { name: string; email: string }) => data)
.handler(async ({ data }) => {
const user = await db.insert(users).values(data).returning()
return user
})With Zod Validation
结合Zod验证
typescript
import { z } from 'zod'
const updateUser = createServerFn({ method: 'POST' })
.validator(
z.object({
id: z.string(),
name: z.string().min(1),
email: z.string().email(),
})
)
.handler(async ({ data }) => {
// data is fully typed: { id: string; name: string; email: string }
return await db.update(users).set(data).where(eq(users.id, data.id))
})typescript
import { z } from 'zod'
const updateUser = createServerFn({ method: 'POST' })
.validator(
z.object({
id: z.string(),
name: z.string().min(1),
email: z.string().email(),
})
)
.handler(async ({ data }) => {
// data类型已完全定义:{ id: string; name: string; email: string }
return await db.update(users).set(data).where(eq(users.id, data.id))
})Middleware
中间件
Creating Middleware
创建中间件
typescript
import { createMiddleware } from '@tanstack/react-start'
const loggingMiddleware = createMiddleware().handler(async ({ next }) => {
console.log('Request started')
const result = await next()
console.log('Request completed')
return result
})typescript
import { createMiddleware } from '@tanstack/react-start'
const loggingMiddleware = createMiddleware().handler(async ({ next }) => {
console.log('请求开始')
const result = await next()
console.log('请求完成')
return result
})Auth Middleware with Context
带上下文的认证中间件
typescript
const authMiddleware = createMiddleware().handler(async ({ next }) => {
const request = getWebRequest()
const session = await getSession(request)
if (!session?.user) {
throw redirect({ to: '/login' })
}
// Pass typed context to handler
return next({ context: { user: session.user } })
})typescript
const authMiddleware = createMiddleware().handler(async ({ next }) => {
const request = getWebRequest()
const session = await getSession(request)
if (!session?.user) {
throw redirect({ to: '/login' })
}
// 将类型化上下文传递给处理器
return next({ context: { user: session.user } })
})Chaining Middleware
链式中间件
typescript
const adminMiddleware = createMiddleware()
.middleware([authMiddleware])
.handler(async ({ next, context }) => {
// context.user is typed from authMiddleware
if (context.user.role !== 'admin') {
throw redirect({ to: '/unauthorized' })
}
return next({ context: { isAdmin: true } })
})
// Usage
const adminAction = createServerFn({ method: 'POST' })
.middleware([adminMiddleware])
.handler(async ({ context }) => {
// context: { user: User; isAdmin: boolean }
return { success: true }
})typescript
const adminMiddleware = createMiddleware()
.middleware([authMiddleware])
.handler(async ({ next, context }) => {
// context.user 继承自authMiddleware的类型
if (context.user.role !== 'admin') {
throw redirect({ to: '/unauthorized' })
}
return next({ context: { isAdmin: true } })
})
// 使用示例
const adminAction = createServerFn({ method: 'POST' })
.middleware([adminMiddleware])
.handler(async ({ context }) => {
// context: { user: User; isAdmin: boolean }
return { success: true }
})API Routes (Server Routes)
API路由(服务器路由)
typescript
// app/routes/api/users.ts
import { createAPIFileRoute } from '@tanstack/react-start/api'
export const APIRoute = createAPIFileRoute('/api/users')({
GET: async ({ request }) => {
const users = await db.query.users.findMany()
return Response.json(users)
},
POST: async ({ request }) => {
const body = await request.json()
const user = await db.insert(users).values(body).returning()
return new Response(JSON.stringify(user), { status: 201 })
},
})typescript
// app/routes/api/users.ts
import { createAPIFileRoute } from '@tanstack/react-start/api'
export const APIRoute = createAPIFileRoute('/api/users')({
GET: async ({ request }) => {
const users = await db.query.users.findMany()
return Response.json(users)
},
POST: async ({ request }) => {
const body = await request.json()
const user = await db.insert(users).values(body).returning()
return new Response(JSON.stringify(user), { status: 201 })
},
})SSR Strategies
SSR策略
Streaming SSR (Default)
流式SSR(默认)
typescript
export const Route = createFileRoute('/dashboard')({
loader: async () => ({
criticalData: await fetchCriticalData(),
deferredData: defer(fetchSlowData()),
}),
component: Dashboard,
})
function Dashboard() {
const { criticalData, deferredData } = Route.useLoaderData()
return (
<div>
<CriticalSection data={criticalData} />
<Suspense fallback={<Loading />}>
<Await promise={deferredData}>
{(data) => <SlowSection data={data} />}
</Await>
</Suspense>
</div>
)
}typescript
export const Route = createFileRoute('/dashboard')({
loader: async () => ({
criticalData: await fetchCriticalData(),
deferredData: defer(fetchSlowData()),
}),
component: Dashboard,
})
function Dashboard() {
const { criticalData, deferredData } = Route.useLoaderData()
return (
<div>
<CriticalSection data={criticalData} />
<Suspense fallback={<Loading />}>
<Await promise={deferredData}>
{(data) => <SlowSection data={data} />}
</Await>
</Suspense>
</div>
)
}Deployment
部署
Supported Platforms (Nitro Presets)
支持的平台(Nitro预设)
typescript
// app.config.ts
export default defineConfig({
server: {
preset: 'node-server', // Self-hosted Node.js
// preset: 'vercel', // Vercel
// preset: 'netlify', // Netlify
// preset: 'cloudflare-pages', // Cloudflare Pages
// preset: 'aws-lambda', // AWS Lambda
// preset: 'deno-server', // Deno Deploy
// preset: 'bun', // Bun
},
})typescript
// app.config.ts
export default defineConfig({
server: {
preset: 'node-server', // 自托管Node.js
// preset: 'vercel', // Vercel
// preset: 'netlify', // Netlify
// preset: 'cloudflare-pages', // Cloudflare Pages
// preset: 'aws-lambda', // AWS Lambda
// preset: 'deno-server', // Deno Deploy
// preset: 'bun', // Bun
},
})Best Practices
最佳实践
- Use validators for all server function inputs - runtime safety and TypeScript inference
- Compose middleware for cross-cutting concerns (auth, logging, rate limiting)
- Use GET for data fetching (cacheable, preloadable)
createServerFn - Use POST for mutations and side effects
createServerFn - Use for route-level auth guards
beforeLoad - Use for non-critical data to improve TTFB
defer() - Set on the router for instant navigation
defaultPreload: 'intent' - Co-locate server functions with the routes that use them
- 为所有服务器函数输入使用验证器 - 运行时安全与TypeScript类型推断
- 组合中间件处理横切关注点(认证、日志、速率限制)
- 使用GET进行数据获取(可缓存、可预加载)
createServerFn - 使用POST进行数据变更与副作用操作
createServerFn - **使用**实现路由级别的认证守卫
beforeLoad - **使用**处理非关键数据以提升TTFB(首字节时间)
defer() - **在路由上设置**实现即时导航
defaultPreload: 'intent' - 将服务器函数与使用它们的路由放在一起
Common Pitfalls
常见陷阱
- Server functions cannot close over client-side variables (they're extracted to separate bundles)
- Data returned from server functions must be serializable
- Forgetting in loaders leads to streaming issues
await - Importing server-only code in client bundles causes build errors
- Missing loses all type safety
declare module '@tanstack/react-router'
- 服务器函数无法引用客户端变量(它们会被提取到单独的打包文件中)
- 服务器函数返回的数据必须可序列化
- 在加载器中忘记会导致流式渲染问题
await - 在客户端打包文件中导入仅服务器端代码会导致构建错误
- 缺少会丢失所有类型安全
declare module '@tanstack/react-router'