三套路由器,同一个 History
很多开发者以为前端路由很复杂。
但如果你读过 vue-router、react-router、tanstack-router 的源码,你会发现:
底层都是同一套东西:
window.history.pushState()+popstate事件监听。
区别只在上层。
这篇文章从设计哲学层面对比三大路由库的差异,帮你理解它们的核心理念,以及如何选择。
如果你想深入了解每个路由器的源码细节,请阅读本系列的后续文章。
一、底层:惊人相似
三家都在调用同一个浏览器 API:
window.history.pushState(state, '', url)
window.history.replaceState(state, '', url)
window.addEventListener('popstate', handler)
但在 history.state 的存储结构上,设计完全不同:
| 路由器 | State 结构 | 设计思路 |
|---|---|---|
| vue-router | {back, current, forward, position, scroll} | 记录前后关系,方便导航 |
| react-router | {usr, key, idx, masked} | 简洁索引,支持 UI 路由 |
| tanstack-router | {__TSR_key, __TSR_index} | 前缀避免冲突,用于 blocker |
二、上层:三种设计哲学
vue-router:渐进式、够用就好
- History 更新:同步调用
- 守卫模型:6 层队列(beforeRouteLeave → beforeEach → beforeRouteUpdate → beforeEnter → beforeRouteEnter → beforeResolve → afterEach)
- 缓存策略:无内置缓存,依赖 Pinia/Vuex
- 类型安全:基础支持
哲学:Vue 的核心理念是「渐进式」——你可以只用你需要的功能,不需要的可以忽略。6 层守卫看起来复杂,但大多数场景只需要 beforeEach。
react-router:Web 标准优先、Remix 融合
- History 更新:同步调用
- 数据模型:loader/action(Request/Response)
- 守卫模型:middleware + next() 模式
- 并发控制:AbortController
- 类型安全:中等推断
哲学:与 Web 标准对齐。loader/action 都接收 Request 对象,返回 Response,让 SSR 变得简单——服务端和客户端用同一套 API。从 Remix 借鉴的设计正在向全栈框架演进。
tanstack-router:性能优先、类型安全极致
- History 更新:microtask 队列节流 + 猴子补丁拦截原生 API
- 数据模型:beforeLoad + loader + loaderDeps
- 缓存策略:LRU Cache + WeakMap + 结构化共享
- 类型安全:极致推导(ParseRoute 递归类型)
哲学:不惜牺牲代码可读性来换取性能和类型安全。用 Uint16Array 代替对象、用 Trie 代替正则、用猴子补丁拦截原生 API。这种优化在大型应用中效果显著。
三、设计哲学总结
| 维度 | vue-router | react-router | tanstack-router |
|---|---|---|---|
| 核心理念 | 渐进式、够用就好 | Web 标准优先、Remix 融合 | 性能优先、类型安全极致 |
| History 更新 | 同步 | 同步 | microtask 队列节流 |
| API 拦截 | 不拦截 | 不拦截 | 猴子补丁拦截 |
| 守卫模型 | 6层队列 | loader/action + middleware | beforeLoad + loader |
| 缓存策略 | 无 | shouldRevalidate | LRU + 结构化共享 |
| 类型安全 | 基础 | 中等 | 极致 |
| 代码风格 | 简洁直观 | 优雅抽象 | 性能优化导向 |
四、选型建议
| 场景 | 推荐 | 原因 |
|---|---|---|
| Vue 项目 | vue-router | 官方支持,生态最好 |
| React + 全栈框架 | react-router | Remix/Next.js 集成最好 |
| React + 大型应用 + 类型安全 | tanstack-router | 长期收益最高 |
| React + 复杂搜索参数 | tanstack-router | validateSearch + 类型推导 |
| 需要精细缓存控制 | tanstack-router | 结构化共享 + LRU |
我的建议:
-
vue-router 没有选择——Vue 项目只能用它,但它足够好用。
-
react-router 适合大多数 React 项目——Web 标准优先的设计让 SSR 变得简单,与 Remix 的融合也让它成为全栈框架的首选。
-
tanstack-router 适合长期维护的大型应用——类型安全和缓存优化在项目规模增长后会越来越有价值。但学习成本也最高。
五、造轮子启示录
如果你想自己写一个路由器,核心只需要:
function createRouter(routes) {
window.addEventListener('popstate', () => {
const location = parseLocation(window.location)
const match = matchRoutes(routes, location)
render(match)
})
function navigate(to) {
const url = buildURL(to)
history.pushState({}, '', url)
const match = matchRoutes(routes, parseLocation(url))
render(match)
}
return { navigate }
}
约 20 行代码就能工作。但要成为一个合格的路由库,还需要:
- 路由匹配算法(静态/动态/通配符)
- 嵌套路由支持
- 导航守卫系统
- 滚动行为恢复
- View Transitions 支持
- 并发控制(AbortController)
- URL 编码处理
- 搜索参数验证
- 预加载策略
- LRU 缓存优化
- Fog of War 懒发现
- 懒加载支持
- SSR 支持
- 类型安全
- 开发者工具
这三家在这些方面各有侧重,读它们的源码是理解前端路由最好的方式。
源码版本
- vue-router: v5.2.0 (packages/router/src/)
- react-router: v8.x (packages/react-router/lib/router/)
- tanstack-router: latest (packages/router-core/src/ + packages/history/src/)