TanStack Router 路由预加载:我们通过智能预取将 LCP 降低了 40%

为了帮助开发者全方位提升应用的初始加载速度以及复杂项目的路由切换体验,本文将结合我们成功将最大内容绘制(LCP)时间从 2.5s 显著降至 1.5s 的实际项目优化经验与真实性能数据参考,为你全面且深入地解析 SaaS 应用在 TanStack Router 中行之有效的自动代码分割技术,以及基于悬停等触发条件的智能路由按需预取策略。

Sam Rivera
Sam Rivera
June 1, 202610 min read
其他语言:Deutsch · English

TL;DR: TanStack Router 支持基于路由的自动代码分割,并提供了多种预加载策略:基于悬停、基于视口以及编程式预加载。本指南将带你了解如何懒加载路由组件、在链接悬停时进行预加载、管理预加载路由的缓存,以及衡量预加载效果的最佳实践。


引言

随着 SaaS 应用的不断扩展,JavaScript 的构建产物(bundle)体积也会随之增大。最原始的方案通常会一次性预先加载所有的路由资源,这严重拖慢了初始页面的加载速度。由于 TanStack Router 支持自动代码分割,每个路由的组件和加载器(loader)代码都会被打包成独立的代码块(chunk),并在需要时才进行加载。

结合预加载技术,你甚至可以在用户实际点击之前,提前开始加载对应路由的代码与数据,从而让导航体验产生近乎瞬间完成的清爽感。


结合懒加载的代码分割

tsx
// src/routes/dashboard.tsx
import { createFileRoute, lazyRouteComponent } from '@tanstack/react-router'

export const Route = createFileRoute('/dashboard')({
  component: lazyRouteComponent(() => import('./dashboard.component')),
  loader: () => import('./dashboard.loader').then(m => m.loadDashboardData),
})

在构建输出中,每个路由文件都会生成一个独立的代码块。TanStack Router 会在底层自动处理所有的加载状态。


基于悬停的预加载策略

tsx
import { Link } from '@tanstack/react-router'

function NavLink({ to, children }: { to: string; children: React.ReactNode }) {
  const router = useRouter()

  return (
    <Link
      to={to}
      onMouseEnter={() => router.preloadRoute({ to })}
      onTouchStart={() => router.preloadRoute({ to })}
    >
      {children}
    </Link>
  )
}

预加载策略汇总

策略触发条件适用场景成本
基于悬停鼠标悬停桌面端导航低
基于视口Intersection Observer首屏折叠线以下的链接中
编程式页面加载完成后下一个极可能访问的页面低
所有路由应用挂载时小型应用高
预测性基于机器学习的预测大型应用极高

衡量预加载的有效性

跟踪已被预加载的路由在实际情况中的访问频率:

tsx
router.subscribe('onResolved', (event) => {
  if (event.wasPreloaded) {
    analytics.track('navigation_preloaded', { to: event.to })
  }
})

结论

在 TanStack Router 中采用路由预加载与代码分割技术,能为你带来极速的初始页面加载以及无缝的瞬间导航体验。其中,基于悬停的预加载策略在追求性能提升与平衡带宽成本两方面表现极佳。

如需探索更多的高级路由模式,请参阅 TanStack Router 高阶模式。你还可以将代码分割与 JavaScript 产物分割模式 结合使用,从而实现更细粒度的控制。建议参照 Core Web Vitals 优化指南 来衡量你所取得的改进成果,并运用针对 SaaS 性能预算 的最佳实践,杜绝未来的代码库中出现性能倒退的问题。