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

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

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

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

rel=prefetch でナビゲーションを改善する

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

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

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

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

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

ユースケース

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

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

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

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

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

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

たとえば Netflix は、ユーザーがログアウトしたページで費やした時間を利用して、ユーザーがログインすると使用される React をプリフェッチします。そのおかげで、今後のナビゲーションに備えて、操作可能になるまでの時間を 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 は <link rel="prefetch"> タグを HTML ドキュメントに挿入します。

<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 は最新のブラウザで広くサポートされているため、多くのユーザーにとってナビゲーション エクスペリエンスを向上させるための魅力的な手法です。この手法では、使用されない可能性のある余分なバイトを読み込む必要があるため、使用する際には注意が必要です。この処理は必要な場合にのみ行い、高速ネットワークで行うのが理想的です。