ByteNoteByteNote

字节笔记本

2026年5月3日

TanStack Start - SPA Mode SPA模式

API中转
¥120

对于因 SEO、爬虫或性能原因而不需要 SSR 的应用,可以使用 SPA 模式向用户提供静态 HTML shell,在客户端使用 JavaScript 引导应用。

SPA 模式的好处

好处描述
更容易部署只需要能提供静态资产的 CDN
更便宜CDN 比 Lambda 函数或长运行进程便宜
客户端更简单没有 SSR 意味着水合、渲染和路由出错的可能性更少

没有 SSR 不意味着放弃服务端功能! SPA 模式实际上与服务端函数、服务端路由或其他外部 API 搭配得非常好。

工作原理

启用 SPA 模式后的构建过程:

  1. 仅预渲染应用的根路由
  2. 渲染路由器配置的 pending 回退组件
  3. 生成的 HTML 存储到 /_shell.html 的静态 HTML 页面
  4. 配置默认重写以将所有 404 请求重定向到 SPA shell

配置 SPA 模式

tsx
// vite.config.ts
export default defineConfig({
  plugins: [
    tanstackStart({
      spa: {
        enabled: true,
      },
    }),
  ],
})

必要的重定向

Netlify 配置

text
# _redirects
/_serverFn/* /_serverFn/:splat 200
/api/* /api/:splat 200
/* /_shell.html 200

Vercel 配置

json
{
  "rewrites": [
    { "source": "/_serverFn/:path*", "destination": "/_serverFn/:path*" },
    { "source": "/api/:path*", "destination": "/api/:path*" },
    { "source": "/:path*", "destination": "/_shell.html" }
  ]
}

Cloudflare Workers

text
/_serverFn/* https://your-worker.workers.dev/_serverFn/:splat 200
/api/* https://your-worker.workers.dev/api/:splat 200
/* /_shell.html 200

Shell 中的动态数据

由于 shell 是使用应用的 SSR 构建预渲染的,在根路由上定义的任何 loader 或服务端特定功能都将在预渲染过程中运行:

tsx
export const RootRoute = createRootRoute({
  loader: async () => {
    return { name: 'Tanner' }
  },
  component: Root,
})

export default function Root() {
  const { name } = useLoaderData()
  return (
    <html>
      <body>
        <h1>Hello, {name}!</h1>
        <Outlet />
      </body>
    </html>
  )
}

SPA 模式 vs SSR 模式

特性SPA 模式SSR 模式
初始加载快速(静态 HTML)较慢(服务端渲染)
SEO较差优秀
部署简单(CDN)复杂(需要 Node.js)
成本较高
服务端功能支持支持
水合错误可能发生

预渲染选项

tsx
export default defineConfig({
  plugins: [
    tanstackStart({
      spa: {
        prerender: {
          outputPath: '/custom-shell',
          crawlLinks: true,
          retryCount: 3,
        },
      },
    }),
  ],
})

部署目标

平台配置复杂度成本
Cloudflare
Netlify
Vercel
自托管可变
分享: