tanstack-start

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

TanStack 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-plugin
bash
npm install @tanstack/react-start @tanstack/react-router
npm install -D @tanstack/router-plugin

Vite 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-devtools
tsx
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
TanStackDevtools
shell instead of individual devtools components:
bash
npm install -D @tanstack/react-devtools
tsx
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
*Panel
variants (
TanStackRouterDevtoolsPanel
,
ReactQueryDevtoolsPanel
) when embedding inside
TanStackDevtools
.
独立版(仅支持TanStack Router):
bash
npm install -D @tanstack/react-router-devtools
tsx
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools'

// 在根布局的</body>前添加
<TanStackRouterDevtools position="bottom-right" />
<Scripts />
统一TanStack开发者工具(搭配多个TanStack库时推荐使用):
如果同时使用Start + Query(或其他TanStack库),请使用统一的
TanStackDevtools
外壳,而非单独的开发者工具组件:
bash
npm install -D @tanstack/react-devtools
tsx
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
中嵌入时,请使用
*Panel
变体(如
TanStackRouterDevtoolsPanel
ReactQueryDevtoolsPanel
)。

Rule Categories

规则分类

PriorityRuleDescription
CRITICALsf-server-functionscreateServerFn, GET/POST methods, handler pattern
HIGHsf-middlewarecreateMiddleware, client/server execution, chaining
HIGHsf-validationInput validation with Zod/Standard Schema, trust boundaries
HIGHssr-streamingStreaming SSR with Suspense, TTFB optimization
HIGHseo-head-managementhead() per route, meta tags, HeadContent, OG tags
HIGHauth-patternsbeforeLoad guards, session server fns, cookie forwarding
MEDIUMssr-hydrationHydration mismatch prevention, client-only components
MEDIUMssr-prerenderingStatic prerendering, ISR via Cache-Control
MEDIUMapi-routescreateAPIFileRoute, REST handlers, webhooks
MEDIUMdeploymentHosting adapters, env vars, production config
MEDIUMconfig-project-setupVite plugin, root route, project structure
优先级规则描述
关键sf-server-functionscreateServerFn、GET/POST方法、处理器模式
sf-middlewarecreateMiddleware、客户端/服务器执行、链式调用
sf-validation使用Zod/标准Schema进行输入验证、信任边界
ssr-streaming结合Suspense的流式SSR、TTFB优化
seo-head-management按路由配置head()、元标签、HeadContent、OG标签
auth-patternsbeforeLoad守卫、会话服务器函数、Cookie转发
ssr-hydration避免 hydration 不匹配、客户端专属组件
ssr-prerendering静态预渲染、通过Cache-Control实现ISR
api-routescreateAPIFileRoute、REST处理器、Webhooks
deployment托管适配器、环境变量、生产环境配置
config-project-setupVite插件、根路由、项目结构

Critical Rules

关键规则

ALWAYS use
createServerFn
for server-side code

始终使用
createServerFn
编写服务器端代码

tsx
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

切勿在服务器端渲染的组件中访问
window
/
document

tsx
// 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()
配置SEO元数据

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>
  )
}