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

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 をプリフェッチします。そのおかげで、今後のナビゲーションのために操作可能になるまでの時間を 30% 短縮しました。

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

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

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

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

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

rel=prefetch の実装方法

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

<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) });
});

これにより、<link rel="prefetch"> タグを HTML ドキュメントに挿入するよう Webpack に指示できます。

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

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

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

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

  • Quicklink は、Intersection Observer API を使用して、リンクがビューポートに入るタイミングを検出し、リンクされたリソースをアイドル時間にプリフェッチします。参考: クイックリンクの重量は 1 KB 未満です。
  • Guess.js は、アナリティクス レポートを使用して予測モデルを構築します。このモデルを使って、ユーザーが必要とすると思われるものだけをスマートにプリフェッチします。

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

内部でのプリフェッチ

リソースヒントは必須の手順ではなく、いつ実行するかはブラウザが決定します。

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

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

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

まとめ

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