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

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

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

このガイドでは、プリフェッチを簡単かつ効率的に実装できるリソースヒントである <link 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 バンドルをコード分割すると、最初にアプリの一部のみを読み込み、残りは遅延読み込みできます。この手法を使用する場合は、すぐに必要ではないが、近い将来リクエストされる可能性が高いルートまたはコンポーネントにプリフェッチを適用できます。

たとえば、絵文字選択ツールを含むダイアログ ボックスを開くボタンを含むページがある場合、そのページを home、dialog、picker の 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) });
});

この機能を読み込むために「送信」イベントが発生するのを待つのではなく、このリソースをプリフェッチして、ユーザーがフォームを送信するまでにキャッシュに保存される可能性を高めることができます。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 は、アナリティクス レポートを使用して予測モデルを構築し、ユーザーが必要とする可能性が高いコンテンツのみをスマートにプリフェッチします。

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

プリフェッチの仕組み

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

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

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

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

まとめ

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