クイックリンクで 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 を使用してルートとチャンクのマップを作成し、リンクがビューに表示されたときにプリフェッチするファイルを決定します。この手法をサイト全体に実装すると、ナビゲーションの速度が大幅に向上し、瞬時に移動しているように見えるようになります。