クイックリンクを使用した create-react-app でのプリフェッチ

この Codelab では、React SPA のデモで Quicklink ライブラリを実装し、プリフェッチによって後続のナビゲーションがどのように高速化されるかを説明します。

測定

最適化を追加する前に、まずアプリケーションの現在の状態を分析することをおすすめします。

  • [Remix to Edit] をクリックしてプロジェクトを編集可能にします。
  • サイトをプレビューするには、[アプリを表示] を押してから、全画面表示 全画面表示 を押します。

ウェブサイトは、create-react-app で構築されたシンプルなデモです。

開いた新しいタブで、次の手順を行います。

  1. Ctrl+Shift+J キー(Mac の場合は Command+Option+J キー)を押して DevTools を開きます。
  2. [Network] タブをクリックします。
  3. [キャッシュを無効にする] チェックボックスをオンにします。
  4. [Throttling] プルダウン リストで [Fast 3G] を選択して、低速な接続タイプをシミュレートします。
  5. アプリを再読み込みします。
  6. [フィルタ テキスト] に「chunk」と入力して、名前に chunk を含まないリソースを非表示にします。

ホームページのチャンクが表示されている [Network] パネル。

このサイトではルートベースのコード分割を使用しているため、最初に必要なコードのみがリクエストされます。

  1. DevTools でネットワーク リクエストを消去します。
  2. アプリ内で、[ブログ] リンクをクリックしてそのページに移動します。

新しいルートの JS チャンクと CSS チャンクが読み込まれて、ページがレンダリングされます。

ブログページのチャンクが表示されている [Network] パネル。

次に、このサイトに 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 を開いて編集します。

まず、Quicklink 高注文コンポーネント(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 変数宣言の後に、quicklink を呼び出すときに引数として使用する options オブジェクトを作成します。

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 つのステップを繰り返します。まだブログページに移動しないでください。

ホームページがそのルートのチャンクを読み込むと、その後、クイックリンクはビューポート内リンクのルートのチャンクをプリフェッチします。

ホームページのチャンクのプリフェッチが表示されている [Network] パネル。

これらのチャンクは、ページをブロックせずに、最も低い優先度でリクエストされます。

次のステップ:

  1. ネットワーク ログを再度クリアします。
  2. [キャッシュを無効にする] チェックボックスをオフにします。
  3. [ブログ] リンクをクリックして、そのページに移動します。

キャッシュからチャンクが取得されたブログページが表示されている [Network] パネル。

[Size] 列は、これらのチャンクがネットワークではなく「プリフェッチ キャッシュ」から取得されたことを示します。クイックリンクを使用せずにこれらのチャンクの読み込みには、約 580 ミリ秒かかりました。ライブラリを使用した場合、所要時間は 2 ミリ秒になりました。これは 99% 削減に相当します。