使用 Quicklink 在 create-react-app 中预提取

Addy Osmani
Addy Osmani
Anton Karlovskiy
Anton Karlovskiy
Demián Renzulli
Demián Renzulli

此 Codelab 介绍了如何在 React SPA 演示中实现 Quicklink 库,以演示预提取如何加快后续导航的速度。

测量

在添加优化措施之前,最好先分析应用的当前状态。

  • 点击 Remix to Edit 使项目可修改。
  • 如需预览网站,请按查看应用,然后按全屏 全屏

该网站是使用 create-react-app 构建的简单演示。

在刚刚打开的新标签页中完成以下操作:

  1. 按 `Control+Shift+J`(在 Mac 上,则按 `Command+Option+J`)打开开发者工具。
  2. 点击网络标签页。
  3. 选中停用缓存复选框。
  4. “节流”下拉列表中,选择 Fast 3G,以模拟慢速连接类型。
  5. 重新加载应用。
  6. 过滤条件文本框中输入 chunk,以隐藏名称中不包含 chunk 的所有资源。

显示首页分块的网络面板。

该网站采用基于路由的代码拆分方式,因此系统只会在开头请求必要的代码。

  1. 在开发者工具中清除网络请求
  2. 在该应用中,点击博客链接即可转到该页面。

系统会加载新路由的 JS 和 CSS 块,以呈现网页。

显示博客页面数据块的网络面板。

接下来,您将在此网站中实现 Quicklink,以便可以在首页中预提取这些分块,从而加快导航速度。

这样,您就可以结合利用这两种技术的优点:

  • 基于路由的代码拆分功能会指示浏览器在网页加载时仅以更高的优先级加载必要的区块。
  • 预提取会告知浏览器在浏览器的空闲时间内以最低优先级加载视口内链接的分块。

配置 webpack-route-manifest

第一步是安装并配置 webpack-route-manifest,这是一个 Webpack 插件,可让您生成将路由与其对应分块关联的清单文件。

通常情况下,您需要安装该库,不过我们已为您完成了安装。以下是您需要运行的命令:

npm install webpack-route-manifest --save-dev

config-overrides.js 是位于项目根目录下的文件,您可以在该文件中替换 webpack 配置的现有行为,而无需弹出项目

  • 要查看源代码,请按查看源代码

打开 config-overrides.js 进行修改,然后在文件开头添加 webpack-route-manifest 依赖项:

const path = require('path');
const RouteManifest = require('webpack-route-manifest');

接下来,将以下代码添加到 config-overrides.js 底部,以配置 webpack-route-manifest 插件:

module.exports = function override(config) {
  config.resolve = {
    ...config.resolve,
    alias: {
      '@assets': `${path.resolve(__dirname, 'src/assets')}`,
      '@pages': `${path.resolve(__dirname, 'src/pages')}`,
      '@components': `${path.resolve(__dirname, 'src/components')}`,
    },
  };

  config.plugins.push(
    new RouteManifest({
      minify: true,
      filename: 'rmanifest.json',
      routes(str) {
        let out = str.replace('@pages', '').toLowerCase();
        if (out === '/article') return '/blog/:title';
        if (out === '/home') return '/';
        return out;
      },
    }),
  );

  return config;
};

新代码将执行以下操作:

  • config.resolve 通过指向页面、资源和组件的内部路由声明变量。
  • config.plugins.push() 会创建一个 RouteManifest 对象并向其传递配置,以便系统根据网站的路由和分块生成 rmanifest.json 文件。

系统将生成 manifest.json 文件,并在 https://site_url/rmanifest.json 提供该文件。

此时,您需要在项目中安装 Quicklink 库。为简单起见,我们已将其添加到项目中。以下是您需要运行的命令:

npm install --save quicklink

打开 src/components/App/index.js 进行修改。

首先,导入快速链接高阶组件 (HOC):

import React, { lazy, Suspense } from 'react';
import { Route } from 'react-router-dom';

import Footer from '@components/Footer';
import Hero from '@components/Hero';
import style from './index.module.css';
import { withQuicklink } from 'quicklink/dist/react/hoc.js';

const Home = lazy(() => import(/* webpackChunkName: "home" */ '@pages/Home'));
const About = lazy(() => import(/* webpackChunkName: "about" */ '@pages/About'));
const Article = lazy(() => import(/* webpackChunkName: "article" */ '@pages/Article'));
const Blog = lazy(() => import(/* webpackChunkName: "blog" */ '@pages/Blog'));

接下来,在 Blog 变量声明后面创建一个 options 对象,以便在调用 quicklink 时用作参数:

const options = {
    origins: []
};

最后,使用高阶 withQuicklink() 组件封装每条路线,并向其传递 options 形参以及该路线的目标组件:

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() 封装的路由预提取分块。

再次测量

重复测量中的前 6 个步骤。先不要转到博客页面。

在首页加载该路由的分块时。之后,Quicklink 会为视口内链接预提取路线的分块:

显示首页预提取分块的网络面板。

这些分块以最低优先级请求,且不会阻塞网页。

下一个:

  1. 再次清除网络日志。
  2. 取消选中停用缓存复选框。
  3. 点击博客链接以转到该页面。

“网络”面板,其中显示了博客页面,以及从缓存中提取的数据块。

Size 列指示这些区块是从“预提取缓存”而不是网络检索的。在没有快速链接的情况下,加载这些分块大约需要 580 毫秒。使用此库时,现在只需 2 毫秒,表示减少了 99%