2022/01/20

CloudflareのEarly Hintsを試してみた

「Early Hints」はリソースを先読みするための新しい仕組みです。 今回は Cloudflare の機能を使って、自分たちのサイトを題材に Early Hints を試してみた件について紹介します。

Early Hints とは?

Early Hints とはリソースを先読みするための仕組みです。 Server Push が否応なしにリソースを「プッシュ」するのに対し、 Early Hints はリソースの URL だけを伝えるので、 ブラウザが賢くキャッシュ管理ができたりと効率がよいです。 例えば Web ページだと、サーバーから HTML を受け取る前にアセットの画像や CSS を優先的にダウンロードするといった使い方です。 HTML を生成するのに時間がかかる場合などは特に有効でしょう。

具体的には HTML がステータス「200」で返る前に、URL が書かれた「103」というレスポンスが返ってきます。その様子は Early Hints に対応したページにcurlすると分かりやすいです。Fastly のラボページにcurlした様子です。

残念ながら、現時点では対応しているサーバーも少なく、ブラウザも標準では対応していません。

実験をしたい

とはいえ Early Hints を使ってみたい! うまく使えば Web Vitals の向上に繋がります。 例えば LCP となっている画像を先読みすれば、当然ながらページは速くなりスコアは上がります。

…と、思っていたところ、Cloudflare がベータ版として Early Hints の機能を追加しました。

わざわざ自分で Early Hints を実装せずとも、Link ヘッダーにpreloadもしくはpreconnectでリソースの URL を指定すると、「103」として返却してくれるみたいです。

Early Hints は他にも Nginx の実装があったり、 トラベルブックが導入している Fasty でも 実験 していますが(以前簡単に試したことがあります)、今回はせっかくなので Cloudflare を使ってみます。

効果を測るのにサンプルページをでっちあげるのはありきたりになるので、 実際に動いているトラベルブックのページを抽出して実験してみます。

やり方

Cloudflare に関しては管理画面にあるトグルをオンにすればそれで設定完了です。 簡単!

さて、トラベルブックの本番サーバーをオリジンとしてバックエンドにするのは問題があります。そこで、以下のやり方をとりました。

  • 実験したいページをリソースも含め手元にダウンロード(ミラーリング)する。
  • とある VPS サーバー にコンテンツを配置。
  • VPS 内の Nginx に配信させる。
  • Nginx の設定で Link ヘッダを追加する。
  • 上記ホストを Cloudflare のオリジンにする。

また、Google などにインデックスされないように

x-robots-tag: noindex

というヘッダも追加しておきます。

ミラーリングするためには拙作のmirrorというコマンドラインツールを使いました。

さて、どのページで試すか。フロントのエンジニアに聞いたところ「ホテルページ」が良さそう。さらに先読みしたい画像(ヒーロー画像と呼びます)も教えてもらいました。

ホテルページをミラーリングして、Nginx のrootに指定。add_headerでヒーロー画像の URL を指定したLinkヘッダを追加。再起動したのち、Cloudflare のキャッシュもパージすればみごとに「103」を吐いてくれました。

HTTP/2 103
link: <https://ddohv6a7e62e4.cloudfront.net/image/4019808/ce020e2f973767eb54d506648d80c2db3ba3a5dc.jpeg?fit=cover&fm=auto&h=300&w=480>; rel=preload, </assets/common/img/favicon/service/favicon.ico>; rel=preload

これでサーバー側はできました。

確認をする

問題はクライントです。現在、主要ブラウザは Early Hints を標準でサポートしません。 唯一一定以上のバージョンの Chrome か「Chrome Canary」をフラグ付きで立ち上げると対応するとこのことです。

open /Applications/Google\ Chrome\ Canary.app --args --enable-features=EarlyHintsPreloadForNavigation

ただ、手元で試して Dev Tools を見るだけだと変化が分からない。 そこで WebPageTest を使います。 https://blog.cloudflare.com/early-hints/ を参考に以下の手順を踏みました。

  1. WebPageTest を開く。
  2. 試験したい URL を入れる。
  3. ユーザーエージェントに「Chrome Canary」を指定。
  4. 詳細設定の「Chromium」に行く。
  5. Early Hints を有効にするために--enable-features=EarlyHintsPreloadForNavigation のフラグを指定する。
  6. 上記のフラグを消せば「Early Hints なし」と比較ができる。

さて、いざ実験! 「ホテルページ」を「Early Hints なし」と「Early Hints あり」で比較してましょう。

フォームに URL を入れてからしばらくすると結果がでます。ででーん!なんとヒーロー画像の読み込みが明らかに速くなって、描画のパフォーマンスもわずかながら向上しました!

こちらが「Early Hints なし」。ヒーロー画像が「31 番目」に読み込まれています。

「Request Start」が「0.457 秒」です。

そして、「Early Hints あり」。なんと HTML ページの次「2 番目」に読み込まれています!

「Request Start」も「0.208 秒」と「Early Hints なし」と比べてだいぶ速い!

HTML のレンダリングの様子も比べてみましょう。

描画完了が 0.1 秒程度速いです!素晴らしい!

まとめ

正直こんな効果あるとは思っていなかったのでびっくりです。

今回はあくまで実験をしただけですが、将来的に Early Hints を活用しようと思いました。 サーバー側に実装が必要になるので、Cloudflare や Fastly といった CDN 側で対応してくれると助かります。また、どのリソースを対象にするかを指定するのに、Cloudflare ではLinkヘッダを使いましたが、他の方法もあるかと思います。 先日紹介した Fastly の Compute@Edge や Cloudflare Workers がよしなにヒーロー画像を検出して「103」を返す、なんて未来も想像できます。

理想的な結果になりましたが、もしかして僕の測り方、結果の見方が間違っているかもしれないので、その際は優しく教えて下さいね。

エンジニア募集中

さて、トラベルブックでは一緒に新しいことにチャレンジしてくれるエンジニアを募集中です。 一緒に Web を速くしましょう!