重要なサブリソースに関するヒントをサーバーがブラウザに送信する仕組みについて説明します。
早期ヒントとは
ウェブサイトは時間の経過とともに高度化しています。そのため、リクエストされたページの HTML を生成するためにサーバーが重要な作業(データベースへのアクセス、配信元サーバーにアクセスする CDN など)が必要になることは珍しくありません。残念ながら、この「サーバーの思考時間」はブラウザがページのレンダリングを開始するまでに、余分なレイテンシが発生します。実際、サーバーがレスポンスを準備する間、接続は実質的にアイドル状態になります。
<ph type="x-smartling-placeholder">早期ヒントは HTTP ステータス コード(103 Early Hints
)で、最終レスポンスに先立って予備 HTTP レスポンスを送信するために使用されます。これにより、サーバーがメインリソースの生成でビジー状態になっている間に、重要なサブリソース(ページのスタイルシート、重要な JavaScript など)やページで使用される可能性の高いオリジンに関する情報をブラウザに送信できます。ブラウザは、メインリソースを待機している間に、これらのヒントを使用して接続をウォームアップし、サブリソースをリクエストできます。言い換えれば、Early Hints はブラウザがこのような「サーバーの思考時間」を活用するのに役立ちます。事前に作業を行っておくことで
ページの読み込みを高速化できます
Largest Contentful Paint のパフォーマンス向上は、Shopify と Cloudflare で観察されている数百ミリ秒から最大 1 秒速くなることもあります(前後の比較を参照)。
<ph type="x-smartling-placeholder">早期ヒントの使用方法
早期ヒントを活用するための最初のステップは、上位のランディング ページ、つまりユーザーがウェブサイトにアクセスしたときに通常最初に開始するページを特定することです。他のウェブサイトからアクセスしているユーザーが多い場合は、ホームページか、人気の商品リスティング ページを参考にします。これらのエントリ ポイントが他のページよりも重要であるのは、ユーザーがウェブサイト内を移動するにつれて初期ヒントの有用性が低下するためです(つまり、ブラウザは 2 回目または 3 回目のナビゲーションで必要なサブリソースをすべて確保する可能性が高くなります)。また、良い第一印象を与えることも重要です。
ランディング ページの優先順位リストを用意できたら、次は preconnect
または preload
のヒントの候補となるオリジンまたはサブリソースを特定します。これらは通常、Largest Contentful Paint や First Contentful Paint などの主要なユーザー指標に最も大きく影響するオリジンとサブリソースです。具体的には、同期 JavaScript、スタイルシート、さらにはウェブフォントなど、レンダリングをブロックするサブリソースを探します。同様に、ユーザーに関する主要な指標に大きく貢献するサブリソースをホストするオリジンを探します。
また、メインリソースで preconnect
または preload
をすでに使用している場合は、早期ヒントの候補としてこれらのオリジンやリソースを検討できます。詳しくは、LCP を最適化する方法をご覧ください。ただし、preconnect
ディレクティブと preload
ディレクティブを HTML から Early Hints に単純にコピーすることは、最適ではない場合があります。
これらを HTML で使用する場合は、通常、プリロード スキャナが HTML から検出できない preconnect
や preload
のリソース(たとえば、後で検出されるフォントや背景画像など)が必要になります。早期ヒントの場合、HTML は利用できないため、代わりに、HTML の早い段階で発見できる重要なリソースに対して preconnect
を行うことをおすすめします。たとえば、main.css
や app.js
をプリロードできます。また、すべてのブラウザが早期ヒントの preload
をサポートしているわけではありません。ブラウザのサポートをご覧ください。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
が必要になると予測し、Early Hints を使用してプリロードすることを提案します。
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">
最後に、サーバーサイドで、早期ヒントをサポートすることがわかっているブラウザから送信されたメインリソース リクエストを探し、103 個の早期ヒントで即座に応答します。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 早期ヒントは主要なブラウザすべてでサポートされていますが、早期ヒントで送信できるディレクティブはブラウザによって異なります。
Preconnect サポート:
対応ブラウザ
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
プリロードのサポート:
対応ブラウザ
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
Chrome DevTools では、103 早期ヒントをサポートしており、Link
ヘッダーはドキュメント リソースで確認できます。
Early Hints リソースを使用する際の注意事項。Early Hints はブラウザ キャッシュを使用するため、DevTools で Disable cache
をオンにしないでください。プリロードされたリソースの場合、イニシエータは early-hints
、サイズは (Disk cache)
と表示されます。
HTTPS テスト用の信頼できる証明書も必要です。
Firefox(v126 時点)では DevTools での 103 早期ヒントの明示的なサポートはありませんが、早期ヒントを使用して読み込まれたリソースには、初期ヒントを通じて読み込まれたインジケーターの 1 つである HTTP ヘッダー情報が表示されません。
サーバー サポート
一般的なオープンソース ソフトウェアの HTTP サーバー ソフトウェアにおける Early Hints のサポートレベルの概要を次に示します。
- Apache: mod_http2 を使用する場合はサポートされます。
- H2O: サポート対象。
- NGINX: 試験運用版モジュール。
- Node: 18.11.0 以降、http および http2 でサポート
早期ヒントを有効にする
次のいずれかの CDN またはプラットフォームを使用している場合は、早期ヒントを手動で実装する必要はありません。ソリューション プロバイダのオンライン ドキュメントで早期ヒントがサポートされているかどうかを確認するには、次のリストをご覧ください(すべてを網羅しているわけではありません)。
早期ヒントをサポートしていないお客様の問題を回避する方法
100 の範囲の情報 HTTP レスポンスは HTTP 標準の一部ですが、103 Early Hints のリリース前は一般的なウェブ ブラウジングではほとんど使用されなかったため、一部の古いクライアントや bot では苦労するかもしれません。
sec-fetch-mode: navigate
HTTP リクエスト ヘッダーを送信するクライアントへのレスポンスで 103 個の早期ヒントを出力する場合にのみ、後続のレスポンスを待つことを理解している新しいクライアントにのみ、このようなヒントが送信されるようにする必要があります。また、早期ヒントはナビゲーション リクエストでのみサポートされているため(現在の制限事項をご覧ください)、他のリクエストで不必要に送信しなくて済むというメリットもあります。
また、早期ヒントは HTTP/2 または HTTP/3 接続でのみ送信することをおすすめします。ほとんどのブラウザでは、これらのプロトコルでしか受信できません。
高度なパターン
主要なランディング ページに早期ヒントを全面的に適用していて、最適化案をさらに見つけようとしている場合は、次の高度なパターンが適しているかもしれません。
一般的なユーザー ジャーニーの一環として n 番目のページ リクエストを行っている訪問者に対しては、早期ヒントのレスポンスをページ内の下の方の深いコンテンツ、つまり優先度の低いリソースで早期ヒントを使用するのに合わせることができます。優先度が高く、レンダリングをブロックするサブリソースまたはオリジンに注力することをおすすめしたことを考えると、直感に反するかもしれません。ただし、ユーザーがしばらく操作した時点までに、ブラウザには重要なリソースがすでにすべて割り当てられている可能性が高くなります。そこから、優先度の低いリソースに注意を向けるのが合理的です。たとえば、Early Hints を使用して商品画像を読み込む場合や、あまり一般的でないユーザー操作にのみ必要となる追加の JS/CSS を使用する場合などです。
現在の制限事項
Chrome に実装されている早期ヒントの制限事項は次のとおりです。
- ナビゲーション リクエスト(トップレベル ドキュメントのメインリソース)でのみ使用できます。
preconnect
とpreload
のみをサポートします(つまり、prefetch
はサポートされません)。- 早期ヒントの後、最終的なレスポンスでクロスオリジン リダイレクトが行われると、Chrome は早期ヒントを使用して取得したリソースと接続が切断されます。
- 早期ヒントを使用してプリロードされたリソースは HTTP キャッシュに保存され、後でページによって HTTP キャッシュから取得されます。したがって、早期ヒントを使用してプリロードできるのは、キャッシュ可能なリソースのみです。あるいは、リソースは二重取得されます(早期ヒントで 1 回、ドキュメントで再び)。Chrome では、信頼できない HTTPS 証明書に対する HTTP キャッシュは無効になります(ページの読み込みを続行しても)。
- ドキュメントが作成されるまでビューポートは定義されないため、レスポンシブ画像のプリロード(
imagesrcset
、imagesizes
、media
を使用)は、HTTP<link>
ヘッダーを使用したサポートには対応していません。つまり、103 Early Hints を使用してレスポンシブ画像をプリロードすることはできず、これを使用すると誤った画像が読み込まれる可能性があります。こちらの対応方法の提案に関するディスカッションをご覧ください。
他のブラウザにも同様の制限があり、前述のように、さらに一部のブラウザでは 103 早期ヒントを preconnect
のみに制限しています。
次のステップ
コミュニティからの関心に応じて、次のような機能で早期ヒントの実装を補強する場合があります。
- HTTP キャッシュではなくメモリ キャッシュを使用するキャッシュ不可リソースの早期ヒント。
- サブリソース リクエストで送信される早期ヒント。
- iframe メインリソース リクエストで送信される早期ヒント。
- 早期ヒントでのプリフェッチのサポート。
優先すべき点や早期ヒントの改善方法について、皆様からのご意見をお待ちしております。
H2/push との関係
非推奨になった HTTP2/push 機能をご存じであれば、Early Hints との違いをご存じでしょうか。Early Hints では、ブラウザが重要なサブリソースの取得を開始するためにラウンド トリップが必要になりますが、HTTP2/Push では、サーバーがレスポンスとともにサブリソースのプッシュを開始できます。これは驚くべきことのように聞こえますが、結果的に重要な構造上の欠点が生じました。HTTP2/Push では、ブラウザにすでに備わっているサブリソースのプッシュを回避することが非常に困難でした。この「過剰な」ネットワーク帯域幅の使用効率が低下し、パフォーマンス上のメリットが大幅に阻害されました。全体として、Chrome のデータによると、HTTP2/Push は実際にウェブ全体のパフォーマンスにおいて実質的にマイナスになっています。
対照的に、Early Hints は実際にはより優れたパフォーマンスを発揮します。事前応答を送信する機能と、実際に必要なものの取得や接続をブラウザが行うヒントを組み合わせたものだからです。Early Hints は HTTP2/Push で理論上対処できるすべてのユースケースを網羅しているわけではありませんが、早期ヒントの方がナビゲーションを高速化するためのより実用的なソリューションであると考えられます。
Pierre Bamin さんのサムネイル画像。