クイックリンクで React のナビゲーションを高速化

React のシングルページ アプリケーションのクイックリンクを使用して、ビューポート内のリンクを自動的にプリフェッチします。

プリフェッチとは、次のページのリソースを事前にダウンロードして、ナビゲーションを高速化する手法です。Quicklink は、ビューに表示されるリンクを自動的にプリフェッチすることで、この手法を大規模に実装できるライブラリです。

複数ページのアプリでは、ライブラリはビューポート内のリンクのドキュメント(/article.html など)をプリフェッチします。これにより、ユーザーがリンクをクリックしたときに、HTTP キャッシュから取得できます。

シングルページ アプリでは、ルートベースのコード分割と呼ばれる手法が一般的に使用されます。これにより、ユーザーが特定のルートに移動したときにのみ、そのルートのコードを読み込むことができます。これらのファイル(JS、CSS)は一般に「チャンク」と呼ばれます。

ただし、このようなサイトでは、ドキュメントをプリフェッチするのではなく、ページで必要になる前にこれらのチャンクをプリフェッチすることで、パフォーマンスが大幅に向上します。

これを実現するには、いくつかの課題があります。

  • 特定のルート(/article など)に到達する前に、そのルートに関連付けられているチャンク(article.chunk.js など)を特定することは簡単ではありません。
  • 最新のモジュール バンドラでは通常、バージョニングに長期ハッシュ(article.chunk.46e51.js など)が使用されるため、これらのチャンクの最終的な URL 名は予測できません。

このガイドでは、Quicklink がこれらの課題を解決し、React シングルページ アプリで大規模なプリフェッチを実現する方法について説明します。

各ルートに関連付けられているチャンクを特定する

quicklink のコア コンポーネントの 1 つが webpack-route-manifest です。これは、ルートとチャンクからなる JSON 辞書を生成できる webpack プラグインです。これにより、ライブラリはアプリケーションの各ルートで必要となるファイルを認識し、ルートが表示されたときにプリフェッチできます。

プロジェクトにプラグインを統合すると、各ルートと対応するチャンクを関連付ける 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',
    },
  ],
}

このマニフェスト ファイルは、次の 2 つの方法でリクエストできます。

  • URL(例: https://site_url/rmanifest.json)。
  • window.__rmanifest の window オブジェクトを使用。

ビューポート内のルートのチャンクをプリフェッチする

マニフェスト ファイルが利用可能になったら、次は npm install quicklink を実行して Quicklink をインストールします。

次に、高次コンポーネント(HOC)withQuicklink() を使用して、リンクがビューに入ったときに特定のルートをプリフェッチする必要があることを示すことができます。

次のコードは、4 つのリンクを含むトップメニューをレンダリングする 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 でラップし、ページ コンポーネントとオプション パラメータを渡します。
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 分間保持されます。5 分経過すると、リソースの cache-control ルールが適用されます。その結果、ユーザーがリンクをクリックして特定のルートに移動すると、チャンクがキャッシュから取得されるため、そのルートのレンダリング時間が大幅に短縮されます。

まとめ

プリフェッチを行うと、今後のナビゲーションの読み込み時間が大幅に短縮されます。React シングルページ アプリでは、ユーザーが各ルートに移動する前に、各ルートに関連付けられたチャンクを読み込むことで、この処理を行うことができます。React SPA 向けの Quicklink ソリューションは、webpack-route-manifest を使用してルートとチャンクのマップを作成し、リンクがビューに表示されたときにプリフェッチするファイルを決定します。この手法をサイト全体に実装すると、ナビゲーションを大幅に改善し、瞬時に移動しているように見せることができます。