最佳实践

快速决策

不确定选哪个? 回答以下问题:

  1. 🔍 需要 SEO / 首屏性能?→ Next.js
  2. 📦 需要 RSC 减少客户端 bundle?→ Next.js
  3. 追求极致开发体验 / HMR 速度?→ Vite + TanStack
  4. 🖥️ 纯 SPA / 后台管理系统?→ Vite + TanStack
  5. 👥 团队熟悉 Next.js 生态?→ Next.js
  6. 🔄 需要渐进式从 SPA 迁移到 SSR?→ TanStack Start

都不确定? 选 Next.js —— 社区更大、文档更全、招人更容易。

栈选择指南

React 应用在进入生产阶段通常会在「全栈框架」与「前端优先」两类方案之间抉择:

  • Next.js Stack 借助 App Router 与 RSC 打通服务端与客户端的数据流,适合强调 BFF、SEO、全局缓存的团队。
  • Vite + TanStack Stack 聚焦于极致的开发体验与客户端渲染,凭借 Vite 构建链得到更快的启动与按需扩展能力。

React Server Components 支持

  • Next.js:原生支持 RSC,可在下列场景发挥优势:
    • 页面需要依赖敏感后端凭证读取数据,且不希望在客户端暴露。
    • 页面结构复杂、组件层级深,希望利用服务器端渲染减少客户端 bundle 大小。
    • 需要 ISR/SSG/SSR 混合策略,或借助 cache(), revalidatePath() 等能力管理数据失效。
  • Vite + TanStack:暂不支持 RSC,更适合以下场景:
    • 业务核心在客户端交互,对 SEO 要求不高。
    • 数据请求可通过 edge function / BFF 服务自行封装。
    • 团队希望保持完全的客户端状态管理模型(TanStack Query、zustand 等)。

性能与扩展性

维度Next.js StackVite + TanStack Stack
开发速度Turbopack HMR,大型项目初次启动稍慢Vite 原生 HMR,超快启动
构建速度Turbopack (beta) / webpackVite + esbuild/Rollup,更快冷/热构建
扩展性Route Handlers、Middleware、Edge RuntimeServer Functions、Middleware、Selective SSR

全面对比

维度Next.jsTanStack Start
🧩 RSC 支持✅ 原生支持❌ 不支持
🌐 SSR/SSG/ISR✅ 全支持⚡ SSR + SPA 模式切换
📚 学习曲线🟡 中等(RSC 概念较新)🟢 较低(纯客户端思维)
👥 社区规模🟢 大,生态成熟🟡 小但活跃,快速成长
☁️ 部署平台Vercel 原生、各云平台Netlify/Vercel/任意 Node
📦 Bundle 大小🟢 RSC 可显著减少🟡 依赖客户端拆分策略
🔒 类型安全🟡 需额外配置🟢 路由级类型推断开箱即用
🔄 数据获取fetch + cache() + Server ActionsTanStack Query 集成
🗃️ 状态管理服务端 + 客户端分离统一客户端模型
⚠️ 错误边界error.tsx 约定Router 内置 ErrorComponent
👔 招聘难度🟢 容易🔴 较难(需培养)

共通能力对照

无论选择 Next.js 还是 Vite + TanStack Start,团队都可以复用大量一致的工程能力,并依据项目需求挑选最合适的实现形式:

  • 文件路由与动态段:Next.js App Router 的 app/**/[slug]/page.tsx 与 TanStack Start 的 createFileRoute('/:slug') 都支持动态与捕获式路由组织。1
  • 数据获取与预渲染:Next.js 借助 Server Components、fetch 缓存与 ISR;TanStack Start 提供 Loader、Selective SSR 与 SPA 模式开关,均可在渲染前获取数据并控制缓存策略。12
  • 服务函数 & 中间层:Next.js 的 Server Actions、Route Handlers、Middleware,可对应到 TanStack Start 的 createServerFn()、Server Routes 以及 Middleware 管线,满足鉴权、日志与 API 代理等需求。1
  • SEO 与 Head 管理:Next.js generateMetadata 支持异步生成 meta 信息;TanStack Start 通过 Loader + Head 配置同样可以动态注入 SEO 数据。1
  • 脚手架与模板生态:Next.js 有 create-next-app 与丰富的官方示例;TanStack Start CLI 也提供一键脚手架与多种示例(React Query、Auth、Convex 等),并可直连 Netlify 等平台快速部署。2
  • Tailwind 等周边集成:两者都原生支持 Tailwind CSS、环境变量体系、代码拆分与懒加载,Registry 的 Theme、UI、Hook、Item 也可在两种栈中无缝复用。12

选择栈时先确认是否需要 RSC 与一体化部署;若主要诉求是快速迭代与轻量构建,则可优先考虑 Vite + TanStack 方案。

场景决策树

选 Next.js 的场景 ▲

场景原因
🏠 营销落地页 / 官网SEO 强需求,ISR/SSG 优势明显
🛒 电商详情页首屏性能 + SEO + 动态数据
📝 博客 / 文档站MDX + SSG 生态成熟
📦 需要 RSC 优化 bundle复杂页面减少客户端代码
👥 团队已有 Next.js 经验降低学习成本
☁️ 需要 Vercel 一键部署官方支持最完善

选 TanStack Start 的场景 ⚡

场景原因
🖥️ 后台管理系统纯 SPA,无 SEO 需求
📊 数据密集型仪表盘TanStack Query 缓存优势
🔄 从 CRA/Vite SPA 迁移渐进式引入 SSR
⚡ 追求极致 DXVite HMR + 类型安全路由
🎛️ 需要精细控制 SSRSelective SSR 灵活度高
🚀 小团队快速迭代构建快、配置少

都可以的场景 🤝

  • 中后台 + 少量 C 端页面混合
  • API 驱动的 CRUD 应用
  • 内部工具平台

安全风险 🔐

SSR/RSC 相关

Server Components 数据泄露:RSC 中直接查询数据库时,确保敏感字段不会序列化到客户端。使用 server-only 包标记纯服务端模块。

// ❌ 危险:整个 user 对象可能包含敏感字段
const user = await db.user.findUnique({ where: { id } })
return <Profile user={user} />

// ✅ 安全:显式选择暴露的字段
const user = await db.user.findUnique({
  where: { id },
  select: { name: true, avatar: true }
})
return <Profile user={user} />

Server Actions / Server Functions

  • 🛡️ CSRF 防护:Next.js Server Actions 内置 CSRF token;TanStack createServerFn 需自行配置
  • 输入验证:始终使用 Zod 等库验证输入,不信任客户端数据
  • 🔑 权限检查:每个 Action/Function 内部独立验证用户权限
// ✅ 始终验证
export async function updateProfile(input: unknown) {
  const session = await getSession()
  if (!session) throw new Error('Unauthorized')

  const data = profileSchema.parse(input) // Zod 验证
  // ...
}

环境变量

前缀暴露范围用途
NEXT_PUBLIC_🌐 客户端 + 服务端公开配置
无前缀🔒 仅服务端密钥、凭证
VITE_🌐 客户端 + 服务端Vite 公开配置

🚨 永远不要NEXT_PUBLIC_VITE_ 前缀变量中存放 API 密钥、数据库连接串等敏感信息。

案例入口

Footnotes

  1. TanStack Start · Migrate from Next.js 2 3 4 5

  2. TanStack Start · SPA Mode 2 3

目录