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

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

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

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

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

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

これを実現するには、次のような課題があります。

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

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

各ルートに関連付けられたチャンクの特定

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

プロジェクトにプラグインを統合すると、各ルートを対応するチャンクと関連付けた 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 分間保持されます。その後、リソースの cache-control ルールが適用されます。その結果、ユーザーがリンクをクリックして特定のルートに移動すると、キャッシュからチャンクが取得され、そのルートのレンダリングにかかる時間が大幅に短縮されます。

おわりに

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