使用 Quicklink 加速 React 中的导航

使用 quicklink 为 React 单页应用程序自动预取视口内链接。

预取是一种通过提前下载下一页面的资源来加速导航的技术。Quicklink 是一个库,允许您大规模实施此技术,通过在链接进入视图时自动预取链接。

在多页应用程序中,该库会预取文档(例如 /article.html)以用于视口内的链接,以便当用户单击这些链接时,可以从 HTTP 缓存中获取它们。

单页应用程序通常使用一种称为 基于路由的代码拆分的技术。 这允许站点仅在用户导航到给定路由时才加载该路由的代码。 这些文件(JS、CSS)通常被称为“chunks”。

话虽如此,在这些站点中,最大的性能提升不是预取文档,而是来自在页面需要它们之前预取这些 chunks。

实现这一点存在一些挑战

  • 在着陆之前,确定哪些 chunks(例如 article.chunk.js)与给定路由(例如 /article)相关联并非易事。
  • 这些 chunks 的最终 URL 名称无法预测,因为现代模块打包器通常使用长期哈希进行版本控制(例如 article.chunk.46e51.js)。

本指南解释了 Quicklink 如何解决这些挑战,并允许您在 React 单页应用程序中实现大规模预取。

确定与每个路由关联的 chunks

quicklink 的核心组件之一是 webpack-route-manifest,这是一个 webpack 插件,可让您生成路由和 chunks 的 JSON 字典。 这允许库知道应用程序的每个路由将需要哪些文件,并在路由进入视图时预取它们。

将插件集成到项目中后,它将生成一个 JSON 清单文件,将每个路由与其对应的 chunks 相关联

{
  '/about': [
    {
      type: 'style',
      href: '/static/css/about.f6fd7d80.chunk.css',
    },
    {
      type: 'script',
      href: '/static/js/about.1cdfef3b.chunk.js',
    },
  ],
  '/blog': [
    {
      type: 'style',
      href: '/static/css/blog.85e80e75.chunk.css',
    },
    {
      type: 'script',
      href: '/static/js/blog.35421503.chunk.js',
    },
  ],
}

可以通过两种方式请求此清单文件

  • 通过 URL,例如 https://site_url/rmanifest.json
  • 通过 window 对象,在 window.__rmanifest

预取视口内路由的 chunks

一旦清单文件可用,下一步是通过运行 npm install quicklink 来安装 Quicklink。

然后,可以使用 高阶组件 (HOC) withQuicklink() 来指示当链接进入视图时应预取给定的路由。

以下代码属于一个 React 应用程序的 App 组件,该组件呈现一个带有四个链接的顶部菜单

const App = () => (
  <div className={style.app}>
    <Hero />
    <main className={style.wrapper}>
      <Suspense fallback={<div>Loading</div>}>
        <Route path="/" exact component={Home} />
        <Route path="/blog" exact component={Blog} />
        <Route path="/blog/:title" component={Article} />
        <Route path="/about" exact component={About} />
      </Suspense>
    </main>
    <Footer />
  </div>
);

告诉 Quicklink 当这些路由进入视图时应预取它们

  1. 在组件的开头导入 quicklink HOC。
  2. 使用 withQuicklink() HOC 包装每个路由,并将页面组件和 options 参数传递给它。
const options = {
  origins: [],
};
const App = () => (
  <div className={style.app}>
    <Hero />
    <main className={style.wrapper}>
      <Suspense fallback={<div>Loading…</div>}>
        <Route path="/" exact component={withQuicklink(Home, options)} />
        <Route path="/blog" exact component={withQuicklink(Blog, options)} />
        <Route
          path="/blog/:title"
          component={withQuicklink(Article, options)}
        />
        <Route path="/about" exact component={withQuicklink(About, options)} />
      </Suspense>
    </main>
    <Footer />
  </div>
);

withQuicklink() HOC 使用路由的路径作为键,从 rmanifest.json 中获取其关联的 chunks。 在底层,当链接进入视图时,该库会在页面中为每个 chunk 注入一个 <link rel="prefetch"> 标签,以便可以预取它们。 预取的资源将由浏览器以最低优先级请求,并保留在 HTTP 缓存中 5 分钟,之后,资源 cache-control 规则将适用。 因此,当用户单击链接并移动到给定路由时,chunks 将从缓存中检索,从而大大缩短呈现该路由所需的时间。

结论

预取可以大大缩短未来导航的加载时间。 在 React 单页应用程序中,可以通过在用户进入每个路由之前加载与其关联的 chunks 来实现这一点。 Quicklink 的 React SPA 解决方案使用 webpack-route-manifest 创建路由和 chunks 的映射,以便确定在链接进入视图时要预取哪些文件。 在整个站点中实施此技术可以大大改善导航,使其看起来近乎即时。