通过快速链接为 React 单页应用自动预提取视口内链接。
预提取是一种通过提前下载下一页资源来加快导航速度的技术。借助 Quicklink 库,您可以在链接进入视图时自动预提取链接,从而大规模实现此技术。
在多页应用中,该库会为视口内链接预提取文档(例如 /article.html
),以便在用户点击这些链接时,从 HTTP 缓存中提取它们。
单页应用通常使用一种称为“基于路由的代码拆分”的技术。这样一来,网站仅在用户导航到指定路线时加载该路线的代码。这些文件(JS、CSS)通常称为“区块”。
话虽如此,在这些网站中,在网页需要它们之前预提取这些块,而不是预提取文档,性能提升才是最大的。
实现这一目标存在一些挑战:
- 在到达给定路线之前确定哪些数据块(例如
article.chunk.js
)与路线关联(例如/article
)并非易事。 - 这些区块的最终到达网址名称无法预测,因为新型模块打包器通常使用长期哈希处理来进行版本控制(例如
article.chunk.46e51.js
)。
本指南介绍了 Quicklink 如何解决这些难题,并能让您在 React 单页应用中实现大规模预提取。
确定与每个路由关联的分块
quicklink
的核心组件之一是 webpack-route-manifest,这是一个 webpack 插件,可让您生成路线和区块的 JSON 字典。这样一来,库就能知道应用的每个路由需要哪些文件,并在路由进入视图时预提取这些文件。
将该插件与项目集成后,它会生成一个 JSON 清单文件,将每条路线与其对应的区块关联起来:
{
'/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',
},
],
}
可以通过以下两种方式请求此清单文件:
- 通过网址(例如
https://site_url/rmanifest.json
)。 - 通过 window 对象,在
window.__rmanifest
处通过。
预提取视口内路由的分块
清单文件可用后,下一步是通过运行 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 这些路线在视图中显示时应进行预提取,请执行以下操作:
- 在组件开头导入
quicklink
HOC。 - 使用
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
获取其关联分块。在后台,当链接进入视图中时,该库会在页面中为每个分块注入一个 <link rel="prefetch">
标记,以便预提取分块。浏览器将以最低优先级请求预提取的资源,并在 HTTP 缓存中保留 5 分钟,之后系统将应用资源的 cache-control
规则。因此,当用户点击某个链接并转到指定路线时,系统会从缓存中检索区块,从而极大地缩短呈现该路线所需的时间。
总结
预提取可以极大地缩短未来导航的加载时间。在 React 单页应用中,可通过在用户进入这些路线之前加载与每条路线关联的区块来实现。Quicklink 的 React SPA 解决方案使用 webpack-route-manifest
创建路线和分块的映射,以便在链接进入视图时确定要预提取的文件。
在整个网站中采用这种方法可以极大地改进导航,使导航能够即时显示。