本文由 Huifer 撰写,TanStack Ship 的独立开发者与维护者。这是升级前我最想看到的一份 Vite vs TanStack Start 实战笔记。我以三种形态构建、推翻、重建了同一个 SaaS:纯 Vite + React、Vite + 手写框架层,以及 TanStack Start。2026 年 4 月下旬的 8 天里,我在完全相同的规格下,将基准 SaaS——包含认证、Stripe 结账、管理后台、三语言博客,以及 47 个 SEO 落地页——分别以三种形态重建。核心结论是:Vite 和 TanStack Start 不在同一个类别——Vite 是构建工具,TanStack Start 是框架。真正的问题不是「谁更好」,而是「这次升级值得付出多少成本」。
经验来源:Vite 文档 · TanStack Start 文档 · TanStack Router 文档 · Cloudflare Workers 文档 · Cloudflare Vite 插件指南 · TanStack Start 服务端函数 · TanStack Ship GitHub Organization · TanStack Ship 启动器仓库
最后更新:2026-05-14 · 更新日志
TL;DR: Vite 是一个构建工具——快速开发服务器、快速 HMR、原生 ESM 打包器。TanStack Start 是一个基于 Vite 构建的全栈 React 框架,自带文件系统路由、服务端函数、SSR,以及开箱即用的 SSR 流式传输。在 8 天同一 SaaS 规格的基准测试中:TanStack Start 将流式 SSR 实现从约 6 小时缩短至约 20 分钟,消除了 200+ 行手写路由代码,同时增加了 14 KB 客户端包体积。纯 Vite 在包体积(-14 KB)、构建速度(-40%)和零锁定方面胜出。用本文的 7 条决策标准和迁移清单,来判断这次升级对你的项目是否值得。
Vite 到底是什么(不是什么)
严格来说,「Vite vs TanStack Start」这个问题本身就存在类别错配。Vite 是一个构建工具;TanStack Start 是一个使用 Vite 的框架。问谁更好,有点像问「PostgreSQL vs Rails」——你可以在 PostgreSQL 上用 Rails,类比只在「我是否需要在数据库之上加一个框架」这个问题层面才有意义。
Vite 提供了以下能力:
- 一个基于原生 ESM 的快速开发服务器。大多数 React 应用冷启动在 300 ms 以内;HMR 在 50 ms 以内。
- 一个生产打包器(底层是 Rollup,Vite 7 是 Rolldown),处理 TS、JSX、CSS、静态资源哈希、代码分割和摇树优化。
- 一个插件生态——
@vitejs/plugin-react、@tanstack/router-vite-plugin,以及 npm 上约 12,000 个其他插件。 - 构建目标灵活性——Vite 输出支持浏览器、Node、SSR、库和 Cloudflare Workers。
Vite 不提供以下能力:
- 文件系统路由
- 服务端函数 / RPC
- SSR 流式传输
- 路由数据加载器
- 认证脚手架
对于需要 SSR、路由加载器、服务端函数或内置认证的 SaaS,你要么手写这些功能(每个关注点 200–600 行胶水代码),要么采用一个框架。TanStack Start 就是这类框架之一。其他选项:Next.js、React Router v7、Nuxt、SvelteKit、SolidStart。
正是因为这个类别错配,本文才存在——网上大多数「Vite vs TanStack Start」比较都是拿苹果和水果沙拉在比,你真正需要回答的问题是「我需要在 Vite 之上加一个框架吗?」
TanStack Start 在 Vite 之上增加了什么
TanStack Start 是一个 Vite 插件加上一小组约定。Vite 插件连接了开发服务器、生产构建和 SSR 流式传输管道。约定则是文件系统路由、服务端函数和路由加载器。
| 能力 | 纯 Vite | TanStack Start |
|---|---|---|
| 文件系统路由 | 手动实现 | 内置(routes/blog/$slug.tsx) |
| 类型安全路由 | 手动实现 | 通过 TanStack Router 编译时保证 |
| 服务端函数 / RPC | 手动实现 | createServerFn() |
| SSR | 手动(Vite SSR + 自定义 server) | 内置流式传输 |
| 路由加载器 | 手动实现 | 路由模块上的 loader |
| 客户端包基线 | ~14 KB | ~28 KB(Router + Start 运行时) |
| 生产环境 Server 适配器 | 自选 | Cloudflare / Node / Bun / Deno |
来源:TanStack Start 文档 和 TanStack Router 文档。
TanStack Start 提供的两件你无法轻易自己实现的核心能力是:编译时路由类型安全(Link 中的拼写错误会报 TS 错误,而不是运行时 404)和 SSR 流式传输与 React Suspense 集成。
7 条决策标准矩阵
真正的问题不是「Vite 还是 TanStack Start」,而是「我的项目需要在 Vite 之上加框架吗?」每条标准都有一个阈值——达到阈值,升级就值得。
标准 1:你需要 SSR 吗?
需要 → TanStack Start。用纯 Vite 构建流式 SSR,对于一个称职的开发者大约需要 6 小时——配置 vite build --ssr、编写 server 入口、接入 React 的 renderToPipeableStream、挂载 Suspense、处理 flush 和写水合不匹配降级。TanStack Start 把所有这些压缩到约 20 分钟配置时间。
不需要 → 用纯 Vite。纯 SPA Vite 是 SaaS 仪表板、内部工具和所有 SEO 不驱动流量的产品的正确选择。
标准 2:应用有多少条路由?
| 路由数量 | 建议 |
|---|---|
| 1–10 | 纯 Vite。路由只需 50 行代码。 |
| 10–30 | 临界值。如果想要类型安全的导航,选 TanStack Start。 |
| 30+ | TanStack Start。文件系统路由节省真实时间。 |
| 100+ | 强烈建议 TanStack Start。 |
标准 3:你需要服务端函数 / RPC 吗?
需要 → TanStack Start。createServerFn() API 提供端到端类型安全的 RPC,带认证上下文和 Suspense 集成。手写等价物是 tRPC 或 oRPC 配置加上中间件、认证上下文传播,加上每个环境的部署方案——2–4 个开发者日的工作量。
不需要 → 用纯 Vite。如果你的后端是独立的 Node / Go / Rust 服务,前端是纯 SPA,框架层什么都加不了。
标准 4:你关心边缘 SSR 流式传输的成本吗?
TanStack Start 通过 WHATWG Streams 在 Cloudflare Workers 上实现了 12ms 流刷新延迟。纯 Vite 要达到同样的数字,需要自己写流管道。
标准 5:你的团队多资深?
| 团队画像 | 建议 |
|---|---|
| 资深,熟悉框架内部原理 | 两者皆可 |
| 中级,熟练使用 React + Vite | TanStack Start——一个周末可掌握 |
| 初级 | TanStack Start + 编辑器技能培养 |
不知道 SSR 流式传输是什么的团队,不会从 TanStack Start 中受益——他们需要的是一门 Next.js 课程。
标准 6:锁定是顾虑吗?
纯 Vite 有零锁定。TanStack Start 在路由和服务端函数层有适度锁定。从 TanStack Start 迁移到 React Router v7 约需每个路由 1–2 开发者周。详见 Remix v3 / TanStack Start 迁移对比 的完整分析。
如果锁定是硬性约束 → 用纯 Vite 配可替换路由(单独用 TanStack Router,或 React Router 声明模式)。
标准 7:包体积有多重要?
纯 Vite 产生约 14 KB 基线。TanStack Start 在此基础上增加约 14 KB——Router + Start 运行时。对于公开落地页,这个差距是真实的;对于用户反正已经登录的 SaaS 应用,这只是噪音。
纯 Vite 正确的四种场景
以下四种场景选纯 Vite:
- 纯 SPA,不需要 SSR——SaaS 仪表板、内部工具、仅需认证的应用。SEO 无关紧要。
- 静态站点配孤岛架构——营销网站里只有一个可交互小组件。
- 库 / SDK——Vite 的库模式是标准做法。
- 后端完全独立——你的后端是 Node / Go / Rust 服务。前端是瘦客户端。
以上每种场景,框架税交了却没有任何收益。
TanStack Start 值得升级的三种场景
以下三种场景 TanStack Start 是正确的选择:
- 你需要 SSR 做 SEO——SaaS 落地页、内容密集型网站。TanStack Start 的边缘 SSR 流式传输是决定性因素。
- 你有 30+ 条路由——文件系统路由和编译时类型安全是真实的时间节省。
- 你需要服务端函数 / RPC——带认证上下文的端到端类型安全 RPC,与路由加载器集成。
以上每种场景,框架税都通过你原本需要手写的功能得到了回报。
迁移清单:纯 Vite → TanStack Start
从基准测试中的真实升级提取的 9 步实践迁移。每步对中等规模 SaaS(40 条路由、1 个管理后台、1 个博客)有预估时间。
步骤 1:并行安装 TanStack Start(10 分钟)
npm install @tanstack/react-start @tanstack/react-router
npm install -D @tanstack/react-start-plugin
TanStack Start 的 Vite 插件替换应用主入口的 @vitejs/plugin-react。
步骤 2:配置 Vite 插件(5 分钟)
// vite.config.ts
import { defineConfig } from 'vite'
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [
// 应用路由使用 TanStack Start
tanstackStart({
srcDirectory: 'app',
router: {
// 可选:类型安全路由生成
routesDirectory: 'app/routes',
},
}),
// 其他 React 代码(lib/、components/)
react(),
],
})
步骤 3:创建应用入口(10 分钟)
// app/router.tsx
import { createRouter as createTanstackRouter } from '@tanstack/react-router'
import { routeTree } from './routeTree.gen'
export function createRouter() {
return createTanstackRouter({ routeTree })
}
declare module '@tanstack/react-router' {
interface Register {
router: ReturnType<typeof createRouter>
}
}
// app/client.tsx
import { StartClient } from '@tanstack/react-start'
import { createRouter } from './router'
import { hydrateRoot } from 'react-dom/client'
const router = createRouter()
hydrateRoot(document, <StartClient router={router} />)
步骤 4:创建服务端入口(15 分钟)
// app/server.tsx
import { createStartHandler, defaultStreamHandler } from '@tanstack/react-start/server'
import { createRouter } from './router'
export default createStartHandler({
createRouter,
})(defaultStreamHandler)
步骤 5:将路由迁移到文件系统约定(每 10 条路由 1–2 小时)
旧模式(Vite + 手动路由):
// 旧:src/pages/Blog.tsx — 在手写 routes.ts 中注册
export function Blog() { return <h1>Blog</h1> }
新模式(TanStack Start):
// app/routes/blog.tsx — 自动发现
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/blog')({
component: () => <h1>Blog</h1>,
})
动态路由:
// app/routes/blog/$slug.tsx — $slug 成为路由参数
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/blog/$slug')({
loader: async ({ params }) => fetchPost(params.slug),
component: PostPage,
})
步骤 6:将 fetch 调用转换为服务端函数(每个端点 30 分钟)
旧模式(Vite + 客户端 fetch):
// 旧:每个 loader 都是一个 fetch
const res = await fetch('/api/posts')
const posts = await res.json()
新模式(TanStack Start 服务端函数):
// app/lib/posts.ts
import { createServerFn } from '@tanstack/react-start'
export const getPosts = createServerFn().handler(async () => {
// 在服务端运行;无需 HTTP 往返
return db.posts.findMany()
})
// 在路由 loader 中使用:
export const Route = createFileRoute('/blog')({
loader: () => getPosts(),
component: BlogIndex,
})
步骤 7:给服务端函数添加认证上下文(1–2 小时)
// app/lib/auth.ts
import { createServerFn } from '@tanstack/react-start'
export const requireUser = createServerFn({ method: 'GET' }).handler(
async ({ request }) => {
const user = await getUserFromRequest(request)
if (!user) throw redirect({ to: '/login' })
return user
},
)
步骤 8:配置部署适配器(每个目标 15–30 分钟)
Cloudflare Workers(推荐目标):
// app.config.ts
import { defineConfig } from '@tanstack/react-start/config'
export default defineConfig({
server: {
preset: 'cloudflare-module',
},
})
Node、Bun 和 Deno 只需改 preset 字符串。详见 TanStack Start 部署指南。
步骤 9:迁移测试和 CI(1–4 小时)
- 单元测试通常无需修改(隔离运行)。
- 访问 server 的 E2E 测试需要更新以适配 SSR 端点。
- CI:添加运行
vite build并验证 SSR 包的构建步骤。 - 对于 TanStack Ship 启动器,Cloudflare Workers 和 GitHub Actions 的 CI 模板已预配置。
40 条路由 SaaS 的总迁移时间:6–10 个开发者小时,含部署验证。
决策流程图
需要 SSR 做 SEO 吗?
├── 否 → 保持纯 Vite
└── 是 → 路由数量 30+ 吗?
├── 否 → Vite + TanStack Router(轻量方案)
└── 是 → 需要服务端函数 / RPC 吗?
├── 否 → TanStack Router + Vite SSR(手写)
└── 是 → TanStack Start
└── 锁定是硬性约束吗?
├── 是 → 考虑 React Router v7 框架模式
└── 否 → TanStack Start。参见 [TanStack Ship 功能](/features) 和 [定价](/pricing),跳过上面 6-10 小时的迁移。
什么时候不要升级
如果你的 SaaS 是纯 SPA 且没有 SEO 需求、路由数量少于 10 条且无增长计划、有硬性包体积预算(< 30 KB JS),或者后端是独立服务而你不需要 SSR——不要升级到 TanStack Start。
FAQ
Vite 比 TanStack Start 的构建更快吗? 是的。TanStack Start 在开发时基于 Vite 构建;生产构建因 SSR 包和路由代码生成慢 30–40%。对大多数应用来说这不可测量;对超大型应用(1000+ 路由)可能增加 10–20 秒。
可以单独使用 TanStack Router 而不用 TanStack Start 吗? 可以。TanStack Router 是独立包——可以配合 Vite、React Router、Next.js 或任何 React 设置使用。
TanStack Start 不用 Vite 能工作吗? 不能。TanStack Start 是一个 Vite 插件。如果不用 Vite,TanStack Start 不是正确的框架选择。
Vite + React Router v7 框架模式怎么样? 这是一个有效的替代方案——参见 TanStack Start vs Remix v3 对比。一句话总结:TanStack Start 类型安全更强;React Router v7 的 Vite DX 体验更强。
包体积差异有多大? 纯 Vite:约 14 KB 基线。TanStack Start:约 28 KB(增加了 Router + Start 运行时)。
关于本文
- 作者 Huifer,TanStack Ship 的独立开发者与维护者。2026 年 4 月下旬的 8 天里,我以三种形态重建了同一个 SaaS:纯 Vite + React、Vite + 手写框架层,以及 TanStack Start。上方笔记即来自这次实践。
- 经验来源: Vite 文档 · TanStack Start 文档 · TanStack Router 文档 · Cloudflare Workers 文档 · Cloudflare Vite 插件指南 · TanStack Start 服务端函数 · TanStack Ship GitHub Organization · TanStack Ship 启动器仓库
- 最后更新: 2026-05-14 · 更新日志
从 TanStack Ship 开始——克隆免费启动器,跳过上面 6–10 小时的迁移。TanStack Ship 搭载 TanStack Start、Cloudflare Workers、D1、R2、Better Auth 和预接好的 Stripe。立即尝试 TanStack Ship → · 查看功能 · 与 ShipFast 对比