字
字节笔记本
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 模式后的构建过程:
- 仅预渲染应用的根路由
- 渲染路由器配置的 pending 回退组件
- 生成的 HTML 存储到
/_shell.html的静态 HTML 页面 - 配置默认重写以将所有 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 200Vercel 配置
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 200Shell 中的动态数据
由于 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 | 低 | 中 |
| 自托管 | 中 | 可变 |
分享: