tanstack-start
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTanStack Start
TanStack Start
Version: @tanstack/react-start@1.x
Requires: React 18.0+, TypeScript 5.0+, Vite, TanStack Router
版本:@tanstack/react-start@1.x
依赖要求:React 18.0+、TypeScript 5.0+、Vite、TanStack Router
Quick Setup
快速设置
bash
npm install @tanstack/react-start @tanstack/react-router
npm install -D @tanstack/router-pluginbash
npm install @tanstack/react-start @tanstack/react-router
npm install -D @tanstack/router-pluginVite Config
Vite 配置
ts
// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
export default defineConfig({
plugins: [tanstackStart(), react()],
})ts
// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
export default defineConfig({
plugins: [tanstackStart(), react()],
})Root Route
根路由
tsx
// src/routes/__root.tsx
import {
HeadContent,
Outlet,
Scripts,
createRootRoute,
} from '@tanstack/react-router'
export const Route = createRootRoute({
head: () => ({
meta: [
{ charSet: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
],
}),
component: RootComponent,
})
function RootComponent() {
return (
<html lang="en">
<head>
<HeadContent />
</head>
<body>
<Outlet />
<Scripts />
</body>
</html>
)
}tsx
// src/routes/__root.tsx
import {
HeadContent,
Outlet,
Scripts,
createRootRoute,
} from '@tanstack/react-router'
export const Route = createRootRoute({
head: () => ({
meta: [
{ charSet: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
],
}),
component: RootComponent,
})
function RootComponent() {
return (
<html lang="en">
<head>
<HeadContent />
</head>
<body>
<Outlet />
<Scripts />
</body>
</html>
)
}Devtools
开发者工具
Standalone (TanStack Router only):
bash
npm install -D @tanstack/react-router-devtoolstsx
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools'
// In root layout, before </body>
<TanStackRouterDevtools position="bottom-right" />
<Scripts />Unified TanStack Devtools (recommended with multiple TanStack libraries):
If using Start + Query (or other TanStack libraries), use the unified shell instead of individual devtools components:
TanStackDevtoolsbash
npm install -D @tanstack/react-devtoolstsx
import { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools'
import { TanStackDevtools } from '@tanstack/react-devtools'
// In root layout, before </body>
<TanStackDevtools
config={{ position: 'bottom-right' }}
plugins={[
{ name: 'TanStack Router', render: <TanStackRouterDevtoolsPanel /> },
// Add more plugins: Query, etc.
]}
/>
<Scripts />Use variants (, ) when embedding inside .
*PanelTanStackRouterDevtoolsPanelReactQueryDevtoolsPanelTanStackDevtools独立版(仅支持TanStack Router):
bash
npm install -D @tanstack/react-router-devtoolstsx
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools'
// 在根布局的</body>前添加
<TanStackRouterDevtools position="bottom-right" />
<Scripts />统一TanStack开发者工具(搭配多个TanStack库时推荐使用):
如果同时使用Start + Query(或其他TanStack库),请使用统一的外壳,而非单独的开发者工具组件:
TanStackDevtoolsbash
npm install -D @tanstack/react-devtoolstsx
import { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools'
import { TanStackDevtools } from '@tanstack/react-devtools'
// 在根布局的</body>前添加
<TanStackDevtools
config={{ position: 'bottom-right' }}
plugins={[
{ name: 'TanStack Router', render: <TanStackRouterDevtoolsPanel /> },
// 添加更多插件:Query等
]}
/>
<Scripts />在中嵌入时,请使用变体(如、)。
TanStackDevtools*PanelTanStackRouterDevtoolsPanelReactQueryDevtoolsPanelRule Categories
规则分类
| Priority | Rule | Description |
|---|---|---|
| CRITICAL | sf-server-functions | createServerFn, GET/POST methods, handler pattern |
| HIGH | sf-middleware | createMiddleware, client/server execution, chaining |
| HIGH | sf-validation | Input validation with Zod/Standard Schema, trust boundaries |
| HIGH | ssr-streaming | Streaming SSR with Suspense, TTFB optimization |
| HIGH | seo-head-management | head() per route, meta tags, HeadContent, OG tags |
| HIGH | auth-patterns | beforeLoad guards, session server fns, cookie forwarding |
| MEDIUM | ssr-hydration | Hydration mismatch prevention, client-only components |
| MEDIUM | ssr-prerendering | Static prerendering, ISR via Cache-Control |
| MEDIUM | api-routes | createAPIFileRoute, REST handlers, webhooks |
| MEDIUM | deployment | Hosting adapters, env vars, production config |
| MEDIUM | config-project-setup | Vite plugin, root route, project structure |
| 优先级 | 规则 | 描述 |
|---|---|---|
| 关键 | sf-server-functions | createServerFn、GET/POST方法、处理器模式 |
| 高 | sf-middleware | createMiddleware、客户端/服务器执行、链式调用 |
| 高 | sf-validation | 使用Zod/标准Schema进行输入验证、信任边界 |
| 高 | ssr-streaming | 结合Suspense的流式SSR、TTFB优化 |
| 高 | seo-head-management | 按路由配置head()、元标签、HeadContent、OG标签 |
| 高 | auth-patterns | beforeLoad守卫、会话服务器函数、Cookie转发 |
| 中 | ssr-hydration | 避免 hydration 不匹配、客户端专属组件 |
| 中 | ssr-prerendering | 静态预渲染、通过Cache-Control实现ISR |
| 中 | api-routes | createAPIFileRoute、REST处理器、Webhooks |
| 中 | deployment | 托管适配器、环境变量、生产环境配置 |
| 中 | config-project-setup | Vite插件、根路由、项目结构 |
Critical Rules
关键规则
ALWAYS use createServerFn
for server-side code
createServerFn始终使用createServerFn
编写服务器端代码
createServerFntsx
import { createServerFn } from '@tanstack/react-start'
const getUser = createServerFn({ method: 'GET' })
.handler(async () => {
return db.users.findFirst()
})tsx
import { createServerFn } from '@tanstack/react-start'
const getUser = createServerFn({ method: 'GET' })
.handler(async () => {
return db.users.findFirst()
})ALWAYS validate server function inputs
始终验证服务器函数的输入
tsx
const updateUser = createServerFn({ method: 'POST' })
.inputValidator((data: { name: string; email: string }) => data)
.handler(async ({ data }) => {
return db.users.update({ where: { email: data.email }, data })
})tsx
const updateUser = createServerFn({ method: 'POST' })
.inputValidator((data: { name: string; email: string }) => data)
.handler(async ({ data }) => {
return db.users.update({ where: { email: data.email }, data })
})NEVER access window
/document
in components rendered on the server
windowdocument切勿在服务器端渲染的组件中访问window
/document
windowdocumenttsx
// BAD — hydration mismatch
function Bad() {
return <span>{window.innerWidth}px</span>
}
// GOOD — use useEffect for client-only state
function Good() {
const [width, setWidth] = useState<number | null>(null)
useEffect(() => setWidth(window.innerWidth), [])
return <span>{width ?? '...'}px</span>
}tsx
// 错误写法 — 会导致hydration不匹配
function Bad() {
return <span>{window.innerWidth}px</span>
}
// 正确写法 — 使用useEffect处理客户端专属状态
function Good() {
const [width, setWidth] = useState<number | null>(null)
useEffect(() => setWidth(window.innerWidth), [])
return <span>{width ?? '...'}px</span>
}ALWAYS use head()
for SEO metadata
head()始终使用head()
配置SEO元数据
head()tsx
export const Route = createFileRoute('/about')({
head: () => ({
meta: [
{ title: 'About Us' },
{ name: 'description', content: 'Learn about our company' },
],
}),
})tsx
export const Route = createFileRoute('/about')({
head: () => ({
meta: [
{ title: 'About Us' },
{ name: 'description', content: 'Learn about our company' },
],
}),
})Key Patterns
核心模式
Auth Guard with Redirect
带重定向的身份验证守卫
tsx
// routes/_authed.tsx
export const Route = createFileRoute('/_authed')({
beforeLoad: async ({ location }) => {
const user = await getCurrentUserFn()
if (!user) {
throw redirect({
to: '/login',
search: { redirect: location.href },
})
}
return { user }
},
})tsx
// routes/_authed.tsx
export const Route = createFileRoute('/_authed')({
beforeLoad: async ({ location }) => {
const user = await getCurrentUserFn()
if (!user) {
throw redirect({
to: '/login',
search: { redirect: location.href },
})
}
return { user }
},
})Server Function with Validation
带验证的服务器函数
tsx
const createPost = createServerFn({ method: 'POST' })
.inputValidator((data: { title: string; body: string }) => data)
.handler(async ({ data }) => {
const post = await db.posts.create({ data })
return post
})tsx
const createPost = createServerFn({ method: 'POST' })
.inputValidator((data: { title: string; body: string }) => data)
.handler(async ({ data }) => {
const post = await db.posts.create({ data })
return post
})Streaming Dashboard
流式仪表盘
tsx
export const Route = createFileRoute('/dashboard')({
loader: async ({ context: { queryClient } }) => {
// Await critical data
await queryClient.ensureQueryData(userQueries.profile())
// Prefetch non-critical (streams in via Suspense)
queryClient.prefetchQuery(statsQueries.dashboard())
},
component: DashboardPage,
})
function DashboardPage() {
const { data: user } = useSuspenseQuery(userQueries.profile())
return (
<div>
<Header user={user} />
<Suspense fallback={<StatsSkeleton />}>
<DashboardStats />
</Suspense>
</div>
)
}tsx
export const Route = createFileRoute('/dashboard')({
loader: async ({ context: { queryClient } }) => {
// 等待关键数据加载完成
await queryClient.ensureQueryData(userQueries.profile())
// 预取非关键数据(通过Suspense流式加载)
queryClient.prefetchQuery(statsQueries.dashboard())
},
component: DashboardPage,
})
function DashboardPage() {
const { data: user } = useSuspenseQuery(userQueries.profile())
return (
<div>
<Header user={user} />
<Suspense fallback={<StatsSkeleton />}>
<DashboardStats />
</Suspense>
</div>
)
}