重要なサブリソースに関するヒントをサーバーがブラウザに送信する方法について説明します。
早期ヒントとは
ウェブサイトは年々複雑になっています。そのため、リクエストされたページの HTML を生成するためにサーバーが重要な作業(データベースへのアクセス、配信元サーバーにアクセスする CDN など)が必要になることは珍しくありません。残念ながら、この「サーバー思考時間」により、ブラウザがページのレンダリングを開始するまでに余分な遅延が発生します。実際、サーバーがレスポンスを準備する間、接続は実質的にアイドル状態になります。
早期ヒントは HTTP ステータス コード(103 Early Hints
)で、最終レスポンスに先立って予備 HTTP レスポンスを送信するために使用されます。これにより、サーバーがメインリソースの生成に忙しい間に、重要なサブリソース(ページのスタイルシート、重要な JavaScript など)や、ページで使用される可能性が高いオリジンに関するヒントをブラウザに送信できます。ブラウザは、これらのヒントを使用して接続をウォームアップし、メイン リソースを待機しながらサブリソースをリクエストできます。つまり、Early Hints は、ブラウザが事前に一部の処理を行うことで、このような「サーバー思考時間」を活用し、ページの読み込みを高速化できるようにします。
Largest Contentful Paint のパフォーマンスが、Shopify や Cloudflare で観測された数百ミリ秒から、以下の前後比較に示すように最大 1 秒まで短縮される場合があります。
早期ヒントの使用方法
早期ヒントを活用する最初のステップは、上位のランディング ページ(ユーザーがウェブサイトにアクセスしたときに最初に表示されるページ)を特定することです。他のウェブサイトからアクセスしているユーザーが多い場合は、ホームページか、人気の商品リスティング ページを使用します。これらのエントリ ポイントが他のページよりも重要であるのは、ユーザーがウェブサイト内を移動するにつれて初期ヒントの有用性が低下するためです(つまり、ブラウザは 2 回目または 3 回目のナビゲーションで必要なサブリソースをすべて確保する可能性が高くなります)。また、良い第一印象を与えることも重要です。
優先順位付けされたランディング ページのリストが作成されたら、次は preconnect
ヒントまたは preload
ヒントの候補となるオリジンまたはサブリソースを特定します。通常、これらは、Largest Contentful Paint や First Contentful Paint などの主要なユーザー指標に最も貢献するオリジンとサブリソースです。具体的には、同期 JavaScript、スタイルシート、ウェブフォントなど、レンダリングをブロックするサブリソースを探します。同様に、主要なユーザー指標に大きく貢献しているサブリソースをホストするオリジンを探します。
また、メインのリソースですでに preconnect
または preload
を使用している場合は、これらのオリジンまたはリソースを早期ヒントの候補として検討できます。詳しくは、LCP を最適化する方法をご覧ください。ただし、preconnect
ディレクティブと preload
ディレクティブを HTML から早期ヒントに単純にコピーすることは最適ではない可能性があります。
これらを HTML で使用する場合は、通常、プリロード スキャナが HTML から検出できない preconnect
や preload
のリソース(たとえば、後で検出されるフォントや背景画像など)が必要になります。早期ヒントでは HTML がないため、代わりに、HTML の早い段階で検出される可能性がある重要なドメインまたは重要なリソースに preconnect
を設定することをおすすめします。たとえば、main.css
や app.js
をプリロードします。また、すべてのブラウザが早期ヒントの preload
をサポートしているわけではありません。ブラウザのサポートをご覧ください。
2 つ目のステップは、古くなったリソースやメインリソースで使用されなくなったリソースやオリジンで早期ヒントを使用するリスクを最小限に抑えることです。たとえば、頻繁に更新とバージョン管理が行われるリソース(example.com/css/main.fa231e9c.css
など)は、最適な選択ではない場合があります。この懸念は、早期ヒントに固有のものではなく、preload
または preconnect
が存在するすべての場所に適用されます。このような詳細は、自動化またはテンプレート化に最も適しています(たとえば、手動プロセスでは、リソースを使用する実際の HTML タグと preload
の間でハッシュ URL またはバージョン URL の不一致が生じる可能性が高くなります)。
たとえば、次のフローについて考えてみましょう。
GET /main.html
Host: example.com
User-Agent: [....] Chrome/103.0.0.0 [...]
サーバーは main.abcd100.css
が必要になると予測し、早期ヒントを使用してプリロードすることを提案します。
103 Early Hints
Link: </main.abcd100.css>; rel=preload; as=style
[...]
しばらくすると、リンクされた CSS を含むウェブページが提供されます。この CSS リソースは頻繁に更新されており、メインリソースはすでに予測される CSS リソース(abcd100
)の 5 バージョン(abcd105
)更新されています。
200 OK
[...]
<HTML>
<head>
<title>Example</title>
<link rel="stylesheet" href="/main.abcd105.css">
一般的には、かなり安定しており、メインリソースの結果からおおむね独立したリソースとオリジンを目指します。必要に応じて、主要なリソースを 2 つに分割することを検討してください。早期ヒントで使用するように設計された安定した部分と、メイン リソースがブラウザによって受信された後にフェッチされるより動的部分です。
<HTML>
<head>
<title>Example</title>
<link rel="stylesheet" href="/main.css">
<link rel="stylesheet" href="/experimental.3eab3290.css">
最後に、サーバー側で、Early Hints をサポートしていることが判明しているブラウザから送信されたメイン リソース リクエストを探し、103 Early Hints ですぐに応答します。103 レスポンスには、関連するプリコネクトとプリロードのヒントを含めます。メインリソースの準備ができたら、通常のレスポンス(成功した場合は 200 OK など)でフォローアップします。下位互換性を確保するために、最終的なレスポンスに Link
HTTP ヘッダーを含めることをおすすめします。たとえば、メインリソースの生成の一環として明らかになった重要なリソース(「2 つに分割」の提案に従った場合のキーリソースの動的部分など)で補うこともできます。コードは次のようになります。
GET /main.html
Host: example.com
User-Agent: [....] Chrome/103.0.0.0 [...]
103 Early Hints
Link: <https://fonts.google.com>; rel=preconnect
Link: </main.css>; rel=preload; as=style
Link: </common.js>; rel=preload; as=script
しばらくすると、
200 OK
Content-Length: 7531
Content-Type: text/html; charset=UTF-8
Content-encoding: br
Link: <https://fonts.google.com>; rel=preconnect
Link: </main.css>; rel=preload; as=style
Link: </common.js>; rel=preload; as=script
Link: </experimental.3eab3290.css>; rel=preload; as=style
<HTML>
<head>
<title>Example</title>
<link rel="stylesheet" href="/main.css">
<link rel="stylesheet" href="/experimental.3eab3290.css">
<script src="/common.js"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
ブラウザ サポート
103 早期ヒントはすべての主要なブラウザでサポートされていますが、早期ヒントで送信できるディレクティブはブラウザによって異なります。
プリコネクトのサポート:
対応ブラウザ
プリロードのサポート:
対応ブラウザ
Chrome DevTools では、103 早期ヒントをサポートしており、Link
ヘッダーはドキュメント リソースで確認できます。
なお、Early Hints リソースを使用するには、Early Hints がブラウザ キャッシュを使用するため、DevTools で Disable cache
をオンにしないでください。プリロードされたリソースの場合、イニシエーターは early-hints
、サイズは (Disk cache)
と表示されます。
また、HTTPS テスト用の信頼できる証明書も必要です。
Firefox(v126 時点)では、DevTools で 103 早期ヒントを明示的にサポートしていませんが、早期ヒントを使用して読み込まれたリソースには HTTP ヘッダー情報が表示されません。これは、早期ヒントによって読み込まれたことを示す 1 つの指標です。
サーバー サポート
一般的なオープンソース ソフトウェアの HTTP サーバー ソフトウェアにおける早期ヒントのサポートレベルの概要は次のとおりです。
- Apache: mod_http2 を使用してサポートされています。
- H2O: サポート対象。
- NGINX: 試験運用版モジュール。
- Node: 18.11.0 以降、http と http2 でサポート
早期ヒントを簡単に有効にする
次のいずれかの CDN またはプラットフォームを使用している場合は、早期ヒントを手動で実装する必要がない場合があります。ソリューション プロバイダのオンライン ドキュメントで、早期ヒントがサポートされているかどうかを確認するか、こちらに記載されている一覧(ただし、網羅的なものではありません)をご覧ください。
早期ヒントをサポートしていないクライアントで問題を回避する方法
100 番台の情報提供用の HTTP レスポンスは HTTP 標準の一部ですが、103 早期ヒントのリリース前は一般的なウェブ ブラウジングで使用されることがほとんどなかったため、古いクライアントやボットでは対応できない場合があります。
sec-fetch-mode: navigate
HTTP リクエスト ヘッダーを送信するクライアントへのレスポンスで 103 個の早期ヒントを出力する場合にのみ、後続のレスポンスを待つことを理解している新しいクライアントにのみ、このようなヒントが送信されるようにする必要があります。また、早期ヒントはナビゲーション リクエストでのみサポートされているため(現在の制限事項を参照)、他のリクエストで不要に送信されるというデメリットを回避できます。
また、早期ヒントは HTTP/2 接続または HTTP/3 接続でのみ送信することをおすすめします。ほとんどのブラウザでは、これらのプロトコルでのみ早期ヒントを受け入れます。
高度なパターン
主要なランディング ページに早期ヒントをすべて適用し、さらに機会を探している場合は、次の高度なパターンを検討してください。
典型的なユーザー ジャーニーの一環としてn 回目のページ リクエストを行っている訪問者に対しては、ページ内の下位のコンテンツに Early Hints レスポンスを適応させ、優先度の低いリソースで Early Hints を使用することをおすすめします。優先度が高く、レンダリングをブロックするサブリソースやオリジンに重点を置くことを推奨しているため、これは直感に反するように思えます。ただし、ユーザーがサイトを閲覧しているうちに、重要なリソースはすべてブラウザに読み込まれている可能性が高いです。その後は、優先度の低いリソースに注意を向けることが考えられます。たとえば、Early Hints を使用して商品画像を読み込む場合や、あまり一般的でないユーザー操作でのみ必要な追加の JS / CSS などです。
現在の制限事項
Chrome に実装されている早期ヒントの制限事項は次のとおりです。
- ナビゲーション リクエスト(最上位ドキュメントのメイン リソース)でのみ使用できます。
preconnect
とpreload
のみをサポートします(つまり、prefetch
はサポートされません)。- 早期ヒントの後、最終的なレスポンスでクロスオリジン リダイレクトが行われると、Chrome は早期ヒントを使用して取得したリソースと接続が切断されます。
- 早期ヒントを使用してプリロードされたリソースは HTTP キャッシュに保存され、後でページから取得されます。したがって、キャッシュに保存できるリソースのみを早期ヒントを使用してプリロードできます。そうしないと、リソースが(早期ヒントとドキュメントによって)2 回取得されます。Chrome では、信頼できない HTTPS 証明書に対する HTTP キャッシュは無効になります(ページの読み込みを続行しても)。
- ドキュメントが作成されるまでビューポートが定義されないため、レスポンシブ画像(
imagesrcset
、imagesizes
、media
を使用)のプリロードは、HTTP<link>
ヘッダーではサポートされていません。つまり、103 早期ヒントはレスポンシブ画像のプリロードには使用できず、この目的で使用すると間違った画像が読み込まれる可能性があります。こちらの対応方法の提案に関するディスカッションをご覧ください。
他のブラウザにも同様の制限があり、前述のように、さらに一部のブラウザでは 103 早期ヒントを preconnect
のみに制限しています。
次のステップ
コミュニティからの関心によっては、Early Hints の実装に次の機能を追加する可能性があります。
- HTTP キャッシュではなくメモリキャッシュを使用するキャッシュに保存できないリソースの早期ヒント。
- サブリソース リクエストで送信される早期ヒント。
- iframe メインリソース リクエストで送信される早期ヒント。
- 早期ヒントのプリフェッチをサポート。
優先すべき点や、早期ヒントをさらに改善する方法について、ご意見をお寄せください。
H2 / プッシュとの関係
非推奨の HTTP2/Push 機能に精通している場合は、Early Hints とどう違うのか疑問に思うかもしれません。Early Hints では、ブラウザが重要なサブリソースの取得を開始するためにラウンドトリップが必要になりますが、HTTP2 / Push では、サーバーがレスポンスとともにサブリソースのプッシュを開始できます。これは素晴らしいように聞こえますが、構造的な大きな欠点がありました。HTTP2 / Push では、ブラウザにすでに存在するサブリソースをプッシュしないようにすることは非常に困難でした。この「過剰プッシュ」効果により、ネットワーク帯域幅の使用効率が低下し、パフォーマンスの向上が大幅に妨げられました。全体的に、Chrome のデータでは、HTTP2 / Push がウェブ全体のパフォーマンスに悪影響を及ぼしていることが示されました。
一方、Early Hints は、事前レスポンスの送信機能と、実際に必要なものの取得や接続をブラウザに任せるヒントを組み合わせているため、実際にはパフォーマンスが向上します。Early Hints は HTTP2/Push で理論上対処できるすべてのユースケースに対応しているわけではありませんが、早期ヒントの方がナビゲーションを高速化するためのより実用的なソリューションであると考えています。
サムネイル画像: Pierre Bamin