今後のナビゲーションを高速化するためにリソースをプリフェッチする

rel=prefetch リソースヒントとその使用方法について説明します。

調査によると、読み込み時間が短くなるとコンバージョン率が高まり、ユーザー エクスペリエンスも向上します。ユーザーがウェブサイトをどのように移動しているか、どのページが次にアクセスする可能性が高いかを把握している場合は、これらのページのリソースを事前にダウンロードすることで、今後の読み込み時間を改善できます。

このガイドでは、プリフェッチを簡単かつ効率的に実装できるリソースヒントである <link rel=prefetch> を使用して、この目標を達成する方法について説明します。

rel=prefetch によるナビゲーションの改善

ウェブページに <link rel=prefetch> を追加すると、ユーザーが今後必要とする可能性のあるページ全体、または一部のリソース(スクリプトや CSS ファイルなど)をダウンロードするようブラウザに指示します。

<link rel="prefetch" href="/articles/" as="document">

リンク プリフェッチの仕組みを示す図。

prefetch ヒントは、すぐに必要でないリソースに余分なバイト数を消費するため、この手法は慎重に適用する必要があります。ユーザーが必要と確信している場合にのみ、リソースをプリフェッチしてください。ユーザーが低速な接続を使用している場合は、プリフェッチを行わないことを検討してください。これは Network Information API で検出できます。

プリフェッチするリンクを決定する方法はいくつかあります。最も簡単なのは、現在のページの最初のリンクまたは最初の数個のリンクをプリフェッチすることです。より高度なアプローチを使用するライブラリもあります。この投稿の後半で説明します。

ユースケース

後続のページのプリフェッチ

後続のページが予測可能な場合は HTML ドキュメントをプリフェッチし、リンクがクリックされたときにページが即座に読み込まれるようにします。

たとえば、商品リスティング ページでは、リスト内の最も人気のある商品のページをプリフェッチできます。次のナビゲーションの方が予測しやすい場合もあります。ショッピング カート ページでは、ユーザーが購入手続きページにアクセスする可能性が通常高いため、プリフェッチの候補になります。

リソースのプリフェッチによって追加の帯域幅が使用されますが、ほとんどのパフォーマンス指標が改善されます。ドキュメント リクエストがキャッシュヒットすると、最初のバイトまでの時間(TTFB)は大幅に短縮されます。TTFB が短くなるため、Largest Contentful Paint(LCP)First Contentful Paint(FCP)など、その後の時間ベースの指標も短くなることがよくあります。

静的アセットのプリフェッチ

ユーザーがアクセスする可能性のある後続のセクションを予測できる場合は、スクリプトやスタイルシートなどの静的アセットをプリフェッチします。これは、これらのアセットが複数のページで共有される場合に特に便利です。

たとえば、Netflix は、ユーザーがログアウトしたページに滞在している時間を利用し、ユーザーがログインしたときに使用される React をプリフェッチします。これにより、今後のナビゲーションの Time to Interactive を 30% 短縮できました。

静的アセットのプリフェッチがパフォーマンス指標に与える影響は、プリフェッチされるリソースによって異なります。

  • 画像をプリフェッチすると、LCP 画像要素の LCP 時間を大幅に短縮できます。
  • スタイルシートをプリフェッチすると、スタイルシートのダウンロードにかかるネットワーク時間が不要になるため、FCP と LCP の両方を改善できます。スタイルシートはレンダリング ブロックであるため、プリフェッチすると LCP が低下する可能性があります。後続のページの LCP 要素が background-image プロパティを介してリクエストされた CSS 背景画像である場合、その画像はプリフェッチされたスタイルシートの依存リソースとしてプリフェッチされます。
  • JavaScript をプリフェッチすると、ナビゲーション中にネットワークから最初にフェッチする必要がある場合よりも、プリフェッチされたスクリプトの処理をはるかに早く行うことができます。これにより、ページの Interaction to Next Paint(INP)に影響する可能性があります。マークアップが JavaScript を介してクライアントでレンダリングされる場合、リソース読み込みの遅延を短縮することで LCP を改善できます。また、ページの LCP 要素を含むマークアップのクライアントサイド レンダリングをより早く行うことができます。
  • 現在のページでまだ使用されていないウェブフォントをプリフェッチすると、レイアウトのずれを回避できます。font-display: swap; が使用されている場合、フォントのスワップ期間が不要になるため、テキストのレンダリングが高速化され、レイアウト シフトが解消されます。プリフェッチされたフォントが後続のページで使用され、そのページの LCP 要素がウェブフォントを使用したテキスト ブロックである場合、その要素の LCP も速くなります。

オンデマンドの JavaScript チャンクのプリフェッチ

JavaScript バンドルをコード分割すると、最初にアプリの一部のみを読み込み、残りは遅延読み込みできます。この手法を使用している場合、すぐに必要ではないもののすぐにリクエストされる可能性が高いルートやコンポーネントにプリフェッチを適用できます。

たとえば、絵文字選択ツールを含むダイアログ ボックスを開くボタンを含むページがある場合、これを 3 つの JavaScript チャンク(ホーム、ダイアログ、選択ツール)に分割できます。ホームとダイアログは最初に読み込むことができ、選択ツールはオンデマンドで読み込むことができます。webpack などのツールを使用すると、これらのオンデマンド チャンクをプリフェッチするようにブラウザに指示できます。

rel=prefetch の実装方法

prefetch を実装する最も簡単な方法は、ドキュメントの <head><link> タグを追加することです。

<head>
  ...
  <link rel="prefetch" href="/articles/" as="document">
  ...
</head>

as 属性を使用すると、ブラウザは適切なヘッダーを設定し、リソースがすでにキャッシュ内にあるかどうかを判断できます。この属性の値の例: documentscriptstylefontimageその他

Link HTTP ヘッダーを使用してプリフェッチを開始することもできます。

Link: </css/style.css>; rel=prefetch

HTTP ヘッダーでプリフェッチ ヒントを指定する利点は、ブラウザがリソースヒントを見つけるためにドキュメントを解析する必要がないことです。これにより、場合によってはわずかな改善を実現できます。

webpack マジック コメントによる JavaScript モジュールのプリフェッチ

webpack を使用すると、ある程度のユーザーがアクセスするか使用する可能性が高いルートや機能のスクリプトをプリフェッチできます。

次のコード スニペットは、lodash ライブラリから並べ替え機能を遅延読み込みして、フォームから送信される一連の数値を並べ替えます。

form.addEventListener("submit", e => {
  e.preventDefault()
  import('lodash.sortby')
    .then(module => module.default)
    .then(sortInput())
    .catch(err => { alert(err) });
});

この機能を読み込むために「submit」イベントが発生するのを待つのではなく、このリソースをプリフェッチすることで、ユーザーがフォームを送信するまでにキャッシュで利用できる確率を高めることができます。webpack では、import() 内でマジック コメントを使用できます。

form.addEventListener("submit", e => {
   e.preventDefault()
   import(/* webpackPrefetch: true */ 'lodash.sortby')
         .then(module => module.default)
         .then(sortInput())
         .catch(err => { alert(err) });
});

これにより、webpack は HTML ドキュメントに <link rel="prefetch"> タグを挿入します。

<link rel="prefetch" as="script" href="1.bundle.js">

オンデマンド チャンクのプリフェッチによるパフォーマンス上のメリットは微妙ですが、一般に、オンデマンド チャンクがすぐに利用可能になるため、オンデマンド チャンクに依存するインタラクションへのレスポンスが速くなることが期待できます。インタラクションの性質によっては、ページの INP にメリットをもたらす可能性があります。

プリフェッチは通常、全体的なリソースの優先順位にも影響します。リソースのプリフェッチは、可能な限り低い優先度で実行されます。したがって、プリフェッチされたリソースは、現在のページに必要なリソースの帯域幅を競合しません。

prefetch を内部で使用するライブラリを使用して、よりスマートなプリフェッチを実装することもできます。

  • quicklinkIntersection Observer API を使用して、リンクがビューポートに表示されたタイミングを検出し、アイドル状態中にリンクされたリソースをプリフェッチします。ボーナス: クイックリンクの重量は 1 KB 未満です。
  • Guess.js は、アナリティクス レポートを使用して予測モデルを構築し、ユーザーが必要とする可能性が高いコンテンツのみをスマートにプリフェッチします。

クイックリンクと Guess.js はどちらも、Network Information API を使用して、ユーザーが低速なネットワークに接続している場合や Save-Data を有効にしている場合に、プリフェッチを回避します。

プリフェッチの仕組み

リソースヒントは必須の指示ではなく、実行するかどうか、実行するタイミングはブラウザによって異なります。

プリフェッチは同じページで複数回使用できます。ブラウザはすべてのヒントをキューに追加し、アイドル状態のときに各リソースをリクエストします。Chrome では、プリフェッチの読み込みが完了しておらず、ユーザーが目的のプリフェッチ リソースに移動した場合、ブラウザによって、進行中の読み込みがナビゲーションとして認識されます(他のブラウザ ベンダーでは、この実装が異なる場合があります)。

プリフェッチは「低」優先度で行われるため、プリフェッチされたリソースは、現在のページで必要なリソースと帯域幅を競合しません。

プリフェッチされたファイルは、リソースがキャッシュ可能かどうかに応じて、HTTP キャッシュまたはメモリ キャッシュに一定期間保存されます。たとえば、Chrome ではリソースは 5 分間保持され、その後はリソースの通常の Cache-Control ルールが適用されます。

まとめ

prefetch を使用すると、今後のナビゲーションの読み込み時間が大幅に短縮され、ページが瞬時に読み込まれているように見えることもできます。prefetch は最新のブラウザで広くサポートされているため、多くのユーザーのナビゲーション エクスペリエンスを向上させる魅力的な手法です。この手法では、使用されない可能性のある追加バイトの読み込みが必要になるため、使用時には注意が必要です。必要に応じてのみ使用し、高速なネットワークでのみ使用することをおすすめします。