ウェブ パフォーマンスを簡単に - Google I/O 2018 エディション

Google I/O 2018 では、ウェブ パフォーマンスの改善を容易にするツール、ライブラリ、最適化手法の概要を紹介しました。ここでは、Oodles Theater アプリを使用して、これらの手法について説明します。また、予測読み込みと新しい Guess.js イニシアチブに関するテストについても説明します。

Ewa Gasperowicz

この 1 年間、ウェブの高速化とパフォーマンスの向上を実現する方法を模索してきました。その結果、新しいツール、アプローチ、ライブラリが生まれました。この記事では、それらについてご紹介します。最初のパートでは、Oodles Theater アプリの開発時に実際に使用した最適化手法をいくつか紹介します。2 番目のパートでは、予測読み込みと新しい Guess.js イニシアチブに関するテストについて説明します。

パフォーマンスの必要性

インターネットは年々重くなっています。ウェブの状態を確認すると、モバイルのページの中央値は約 1.5 MB で、その大部分が JavaScript と画像であることがわかります。

ウェブサイトのサイズの増加は、ネットワーク レイテンシ、CPU の制限、レンダリングを妨げるパターン、不要なサードパーティ コードなどの他の要因とともに、パフォーマンスの複雑なパズルに寄与しています。

ほとんどのユーザーは、UX のニーズの最上位に速度を挙げています。これは、ページの読み込みが完了するまで、実際には多くのことができないため、それほど驚くことではありません。ページから価値を引き出すことも、その美しさを鑑賞することもできません。

UX 階層ピラミッド
図 1. ユーザーにとって速度はどの程度重要でしょうか。(Speed Matters、Vol. 3)

パフォーマンスがユーザーにとって重要であることはわかっていますが、最適化をどこから始めればよいかを見つけるのは、秘密を解き明かすようなものかもしれません。幸いなことに、その過程で役立つツールがあります。

Lighthouse - パフォーマンス ワークフローのベース

Lighthouse は Chrome DevTools の一部で、ウェブサイトの監査を行い、改善方法に関するヒントを提供します。

最近、日常の開発ワークフローで非常に役立つ新しいパフォーマンス監査を多数リリースしました。

新しい Lighthouse 監査
図 2. 新しい Lighthouse 監査

これらの機能をどのように活用できるか、実際の例で見てみましょう。Oodles Theater アプリは、インタラクティブな Google Doodle をいくつか試したり、ゲームをプレイしたりできる、小さなデモ ウェブアプリです。

アプリを構築するにあたり、できる限りパフォーマンスを向上させたいと考えました。最適化の出発点は Lighthouse レポートでした。

Oodles アプリの Lighthouse レポート
図 3. Oodles アプリの Lighthouse レポート

Lighthouse レポートに表示されたアプリの初期パフォーマンスは、かなりひどいものでした。3G ネットワークでは、ユーザーは First Meaningful Paint、またはアプリがインタラクティブになるまで 15 秒待つ必要がありました。Lighthouse は、サイトに関する多数の問題を指摘しました。全体的なパフォーマンス スコアは 23 で、まさにそのとおりの結果でした。

ページの重さは約 3.4 MB で、無駄を省くことがどうしても必要でした。

これが、最初のパフォーマンス上の課題となりました。つまり、全体的なエクスペリエンスに影響を与えずに簡単に削除できるものを見つけることです。

パフォーマンス最適化の機会

不要なリソースを削除する

空白やコメントなど、安全に削除できることが明らかなものもあります。

圧縮によるメリット
図 4. JavaScript と CSS を縮小して圧縮する

Lighthouse では、CSS と JavaScript の縮小化に関する監査で、この改善の機会が強調表示されます。ビルドプロセスに webpack を使用していたため、縮小化には Uglify JS プラグインを使用しました。

縮小は一般的なタスクであるため、使用するビルドプロセスに適した既製のソリューションを見つけることができます。

この分野で役立つもう 1 つの監査は、テキスト圧縮を有効にするです。非圧縮ファイルを送信する理由はなく、最近ではほとんどの CDN がこの機能を標準でサポートしています。

コードのホストには Firebase Hosting を使用していました。Firebase ではデフォルトで gzip 圧縮が有効になっているため、適切な CDN でコードをホストするだけで、この機能が無料で利用できました。

gzip は非常に一般的な圧縮方法ですが、Zopfli や Brotli などの他のメカニズムも注目を集めています。Brotli はほとんどのブラウザでサポートされており、バイナリを使用してアセットを事前に圧縮してからサーバーに送信できます。

効率的なキャッシュ ポリシーを使用する

次のステップは、不要なリソースを 2 回送信しないようにすることでした。

Lighthouse の非効率なキャッシュ ポリシーの監査により、キャッシュ戦略を最適化して、まさにそれを実現できることに気づきました。サーバーに max-age 有効期限ヘッダーを設定することで、ユーザーが繰り返しアクセスしたときに、以前にダウンロードしたリソースを再利用できるようにしました。

理想的には、できるだけ多くのリソースを、できるだけ安全に、できるだけ長い期間キャッシュに保存し、更新されたリソースを効率的に再検証するための確認トークンを提供することを目指すべきです。

使用されていないコードを削除する

ここまでは、不要なダウンロードの明らかな部分を削除してきましたが、それほど明らかでない部分はどうでしょうか。たとえば、使用されていないコードです。

DevTools のコード カバレッジ
図 5. コード カバレッジを確認する

アプリに、実際には必要のないコードが含まれていることがあります。これは、アプリの開発期間が長くなったり、チームや依存関係が変更されたりした場合に特に発生し、孤立したライブラリが残されることがあります。まさにそれが、私たちに起こったことです。

当初は、アプリのプロトタイプを迅速に作成するためにマテリアル コンポーネント ライブラリを使用していました。 その後、よりカスタムなルック アンド フィールに移行し、そのライブラリのことは完全に忘れていました。 幸いなことに、コード カバレッジ チェックにより、バンドル内でこのコードを再発見できました。

DevTools では、アプリケーションのランタイムと読み込み時間の両方について、コード カバレッジの統計情報を確認できます。下のスクリーンショットには、2 つの大きな赤いストライプが表示されています。CSS の 95% 以上が未使用で、JavaScript も大量に未使用です。

Lighthouse は、未使用の CSS ルールの監査でもこの問題を検出しました。400 KB 以上の削減が見込めることがわかりました。そこで、コードに戻り、そのライブラリの JavaScript と CSS の両方の部分を削除しました。

MVC アダプタを削除すると、スタイルは 10 KB に減少
図 6. MVC アダプターを削除すると、スタイルは 10 KB に減少します。

これにより、CSS バンドルが 20 分の 1 に削減されました。これは、2 行の小さな commit としては非常に優れた結果です。

もちろん、パフォーマンス スコアが向上し、Time to Interactive も大幅に改善されました。

しかし、このような変更では、指標やスコアを確認するだけでは不十分です。 実際のコードを削除すると、常にリスクが伴うため、潜在的な回帰に常に注意する必要があります。

コードの 95% は未使用ですが、残りの 5% がどこかにあります。どうやら、コンポーネントの 1 つ(落書きスライダーの小さな矢印)が、まだそのライブラリのスタイルを使用していたようです。ただし、非常に小さかったため、それらのスタイルを手動でボタンに組み込むことができました。

ライブラリがないためボタンが破損した
図 7. 1 つのコンポーネントが、削除されたライブラリをまだ使用していた

そのため、コードを削除する場合は、潜在的なビジュアル リグレッションを防ぐために、適切なテスト ワークフローを導入してください。

ネットワーク ペイロードのサイズを抑える

リソースが大きいと、ウェブページの読み込みが遅くなることがあります。ユーザーに費用がかかる可能性があり、データプランに大きな影響を与える可能性があるため、この点に注意することが重要です。

Lighthouse は、巨大なネットワーク ペイロード監査を使用して、ネットワーク ペイロードの一部に問題があることを検出できました。

巨大なネットワーク ペイロードを検出する
図 8. 過大なネットワーク ペイロードを検出する

この例では、3 MB を超えるコードが送信されていました。これは、特にモバイルではかなり大きなサイズです。

このリストの一番上で、Lighthouse は、2 MB の非圧縮コードを含む JavaScript ベンダー バンドルがあることを強調表示しました。これは webpack でも指摘されている問題です。

よく言われるように、最も速いリクエストは、行われないリクエストです。

理想的には、ユーザーに提供するすべてのアセットの価値を測定し、それらのアセットのパフォーマンスを測定して、初期エクスペリエンスで実際に提供する価値があるかどうかを判断する必要があります。これらのアセットは、遅延読み込みや遅延読み込み、アイドル時間中の処理が可能な場合があるためです。

今回のケースでは、多くの JavaScript バンドルを扱っていたため、JavaScript コミュニティに豊富な JavaScript バンドル監査ツールが用意されていたことは幸運でした。

JavaScript バンドルの監査
図 9. JavaScript バンドルの監査

まず webpack bundle analyzer を使用したところ、unicode という依存関係が含まれていることがわかりました。これは 1.6 MB の解析済み JavaScript で、かなり大きなものです。

次に、エディタに移動し、Visual Code の Import Cost プラグインを使用して、インポートするすべてのモジュールのコストを可視化しました。これにより、このモジュールを参照するコードを含むコンポーネントを特定できました。

そこで、別のツールである BundlePhobia に切り替えました。これは、任意の NPM パッケージの名前を入力すると、その縮小サイズと gzip 圧縮サイズが推定されるツールです。使用していた slug モジュールの優れた代替品が見つかりました。サイズはわずか 2.2 KB で、切り替えました。

これはパフォーマンスに大きな影響を与えました。この変更と、JavaScript バンドル サイズを削減する他の機会の発見により、2.1 MB のコードを削減できました。

これらのバンドルの gzip 圧縮サイズと縮小サイズを考慮すると、全体で 65% の改善が見られました。このプロセスは、実施する価値が非常に高いことがわかりました。

そのため、一般的には、サイトやアプリで不要なダウンロードを排除するようにしてください。アセットのインベントリを作成し、パフォーマンスへの影響を測定することで、大きな違いが生まれます。そのため、アセットの監査は定期的に行うようにしてください。

コード分割により JavaScript の起動時間を短縮する

ネットワーク ペイロードが大きいとアプリに大きな影響を与える可能性がありますが、それ以外にも大きな影響を与える可能性があるものがあります。それは JavaScript です。

JavaScript は最も高価なアセットです。モバイルでは、サイズの大きい JavaScript バンドルを送信すると、ユーザーがユーザー インターフェース コンポーネントを操作できるようになるまでの時間が遅くなる可能性があります。つまり、実際には意味のあることが何も起こらないのに、UI をタップしている可能性があります。そのため、JavaScript のコストがこれほど高い理由を理解することが重要です。

これは、ブラウザが JavaScript を処理する方法です。

JavaScript の処理
図 10. JavaScript 処理中

まず、そのスクリプトをダウンロードする必要があります。JavaScript エンジンは、そのコードを解析し、コンパイルして実行する必要があります。

これらのフェーズは、デスクトップ マシンやノートパソコン、ハイエンドのスマートフォンなどのハイエンド デバイスではそれほど時間がかかりません。しかし、平均的なスマートフォンでは、このプロセスに 5 ~ 10 倍の時間がかかることがあります。これがインタラクティブ性を遅らせる原因となるため、この部分を削減することが重要です。

アプリでこのような問題を発見できるように、Lighthouse に新しい JavaScript 起動時間監査を導入しました。

JavaScript の起動時間
図 11. JavaScript の起動時間の監査

Oodle アプリの場合、JavaScript の起動に 1.8 秒かかっていることがわかりました。何が起こっていたかというと、すべてのルートとコンポーネントを 1 つのモノリシックな JavaScript バンドルに静的にインポートしていたのです。

この問題を回避する手法の一つが、コード分割です。

コード分割はピザのようなもの

コード分割とは、ユーザーにピザ 1 枚分の JavaScript を提供するのではなく、必要に応じて 1 スライスずつ提供するという考え方です。

コード分割は、ルートレベルまたはコンポーネント レベルで適用できます。React、React Loadable、Vue.js、Angular、Polymer、Preact、その他の複数のライブラリと連携して動作します。

アプリにコード分割を組み込み、静的インポートから動的インポートに切り替えて、必要に応じてコードを非同期で遅延読み込みできるようにしました。

動的インポートによるコード分割
図 13. 動的インポートによるコード分割

これにより、バンドルのサイズが縮小されるだけでなく、JavaScript の起動時間も短縮されました。0.78 秒に短縮され、アプリの速度が 56% 向上しました。

一般に、JavaScript を多用するエクスペリエンスを構築する場合は、ユーザーが必要とするコードのみを送信するようにしてください。

コード分割などのコンセプトを活用し、ツリー シェイキングなどのアイデアを検討してください。webpack を使用している場合は、webpack-libs-optimizations リポジトリでライブラリのサイズを削減する方法に関するアイデアをいくつか確認してください。

画像を最適化する

画像の読み込みパフォーマンスに関するジョーク

Oodle アプリでは、多くの画像を使用しています。残念ながら、Lighthouse は私たちほど熱心ではありませんでした。実際、画像関連の 3 つの監査すべてに不合格となっています。

画像の最適化を忘れていました。画像のサイズが適切ではなく、他の画像形式を使用することで、さらに改善できる可能性がありました。

画像監査
図 14. Lighthouse の画像監査

まず、画像の最適化から始めました。

1 回限りの最適化ラウンドでは、ImageOptim や XNConvert などのビジュアル ツールを使用できます。

より自動化されたアプローチは、imagemin などのライブラリを使用して、ビルドプロセスに画像最適化ステップを追加することです。

これにより、今後追加される画像が自動的に最適化されます。Akamai などの一部の CDN や、Cloudinary、Fastly、Uploadcare などのサードパーティ ソリューションは、包括的な画像最適化ソリューションを提供しています。そのため、これらのサービスで画像をホストすることもできます。

費用やレイテンシの問題により、このようなサービスを利用したくない場合は、Thumbor や Imageflow などのプロジェクトで、セルフホスト型の代替サービスを利用できます。

最適化前と最適化後
図 15. 最適化前と最適化後

背景の PNG は webpack でサイズが大きいとフラグが付けられていましたが、これは当然のことです。ビューポートに合わせてサイズを正しく調整し、ImageOptim で処理したところ、100 KB まで縮小されました。これは許容範囲内です。

サイト上の複数の画像に対してこの処理を繰り返すことで、ページの重さを大幅に軽減できました。

アニメーション コンテンツに適切な形式を使用する

GIF は非常に高価になる可能性があります。意外なことに、GIF 形式はもともとアニメーション プラットフォームとして意図されたものではありませんでした。したがって、より適切な動画形式に切り替えることで、ファイルサイズを大幅に削減できます。

Oodle アプリでは、ホームページのイントロ シーケンスとして GIF を使用していました。Lighthouse によると、より効率的な動画形式に切り替えることで、7 MB 以上を節約できる可能性があります。このクリップのサイズは約 7.3 MB で、一般的なウェブサイトには大きすぎたため、代わりに 2 つのソースファイル(mp4 と WebM)を含む動画要素に変換して、より多くのブラウザをサポートできるようにしました。

GIF アニメーションを動画に置き換える
図 16. GIF アニメーションを動画に置き換える

FFmpeg ツールを使用して、GIF アニメーションを mp4 ファイルに変換しました。WebM 形式を使用すると、さらに大きな節約効果が得られます。ImageOptim API を使用すると、このような変換を行うことができます。

ffmpeg -i animation.gif -b:v 0 -crf 40 -vf scale=600:-1 video.mp4

この変換により、全体的な重量を 80% 以上削減できました。これにより、約 1 MB に削減されました。

それでも、1 MB はネットワーク経由でプッシュするには大きなリソースであり、特に帯域幅が制限されているユーザーにとっては大きな負担となります。幸い、Effective Type API を使用して、帯域幅が遅いことを認識し、代わりにサイズの小さい JPEG を提供できます。

このインターフェースは、有効なラウンドトリップ時間とダウンリンク値を使用して、ユーザーが使用しているネットワーク タイプを推定します。この API は、slow-2g、2g、3g、4g のいずれかの文字列を返します。この値に応じて、ユーザーが 4G 未満のネットワークを使用している場合は、動画要素を画像に置き換えることができます。

if (navigator.connection.effectiveType) { ... }

エクスペリエンスは少し損なわれますが、少なくとも低速な接続でもサイトを使用できます。

オフスクリーン画像の遅延読み込み

カルーセル、スライダー、非常に長いページでは、ユーザーがページですぐに画像を見ることができない場合でも、画像が読み込まれることがよくあります。

Lighthouse は、オフスクリーン画像の監査でこの動作にフラグを立てます。また、DevTools のネットワーク パネルでもこの動作を確認できます。ページに表示されている画像が少ないにもかかわらず、多くの画像が読み込まれている場合は、代わりに遅延読み込みを検討することをおすすめします。

遅延読み込みはブラウザでネイティブにサポートされていないため、JavaScript を使用してこの機能を追加する必要があります。Lazysizes ライブラリを使用して、Oodle カバーに遅延読み込み動作を追加しました。

<!-- Import library -->
import lazysizes from 'lazysizes'  <!-- or -->
<script src="lazysizes.min.js"></script>

<!-- Use it -->

<img data-src="image.jpg" class="lazyload"/>
<img class="lazyload"
    data-sizes="auto"
    data-src="image2.jpg"
    data-srcset="image1.jpg 300w,
    image2.jpg 600w,
    image3.jpg 900w"/>

Lazysizes は、要素の可視性の変化を追跡するだけでなく、最適なユーザー エクスペリエンスを実現するために、ビューに近い要素を事前にプリフェッチします。また、IntersectionObserver のオプションの統合も提供されます。これにより、非常に効率的な可視性ルックアップが可能になります。

この変更により、画像はオンデマンドで取得されるようになりました。このトピックについてさらに詳しく知りたい場合は、images.guide をご覧ください。非常に便利で包括的なリソースです。

ブラウザが重要なリソースを早期に配信できるようにする

ブラウザに送信されるすべてのバイトが同じ重要度を持つわけではありません。ブラウザはこれを認識しています。多くのブラウザには、最初にフェッチするものを決定するためのヒューリスティックがあります。そのため、画像やスクリプトよりも先に CSS を取得することがあります。

ページの作成者が、実際に重要な要素をブラウザに通知できれば便利です。幸いなことに、この数年間でブラウザ ベンダーは、この問題に対処するための機能を数多く追加してきました。たとえば、link rel=preconnect、preload、prefetch などのリソースヒントです。

ウェブ プラットフォームに導入されたこれらの機能は、ブラウザが適切なタイミングで適切なものを取得するのに役立ちます。また、スクリプトを使用して行われるカスタム読み込みやロジックベースのアプローチよりも効率的です。

Lighthouse がこれらの機能を効果的に使用するようどのようにガイドしているかを見てみましょう。

Lighthouse が最初に行うよう指示しているのは、オリジンへのコストのかかる往復を複数回行わないようにすることです。

オリジンへのコストのかかる往復を複数回行わない
図 17. オリジンへのコストのかかる往復を複数回行わないようにする

Oodle アプリでは、Google Fonts を多用しています。Google Fonts のスタイルシートをページにドロップすると、最大 2 つのサブドメインに接続されます。Lighthouse によると、その接続をウォームアップできれば、初期接続時間を最大 300 ミリ秒短縮できる可能性があります。

link rel preconnect を利用することで、接続のレイテンシを効果的に隠すことができます。

特に、Google Fonts のように、フォントフェイス CSS が googleapis.com でホストされ、フォント リソースが Gstatic でホストされている場合は、大きな影響を受ける可能性があります。この最適化を適用したところ、数百ミリ秒を短縮できました。

Lighthouse が次に提案しているのは、重要なリクエストをプリロードすることです。

キーリクエストのプリロード
図 18. キーリクエストをプリロードする

<link rel=preload> は非常に強力です。現在のナビゲーションの一部としてリソースが必要であることをブラウザに通知し、ブラウザが可能な限り早くリソースを取得できるようにします。

Lighthouse は、2 つのウェブフォントを読み込んでいるため、主要なウェブフォント リソースをプリロードする必要があることを示しています。

ウェブフォントのプリロードは、rel=preload を指定し、フォントの種類を指定して as を渡し、読み込むフォントの種類(woff2 など)を指定します。

これがページに与える影響は非常に大きいものです。

リソースのプリロードの影響
図 19. リソースのプリロードの影響

通常、link rel preload を使用しない場合、ウェブフォントがページにとって重要であれば、ブラウザはまず HTML を取得し、CSS を解析する必要があります。その後、かなり後になってようやくウェブフォントを取得します。

link rel preload を使用すると、ブラウザが HTML を解析するとすぐに、ウェブフォントの取得をかなり早い段階で開始できます。このアプリの場合、ウェブフォントを使用してテキストをレンダリングするのにかかる時間を 1 秒短縮できました。

Google Fonts を使用してフォントをプリロードしようとする場合、それほど簡単ではありません。1 つ注意点があります。

スタイルシートのフォントフェイスで指定した Google Fonts の URL は、フォントチームが定期的に更新するものでした。これらの URL は有効期限が切れたり、定期的に更新されたりすることがあります。そのため、フォントの読み込みを完全に制御したい場合は、ウェブフォントをセルフホストすることをおすすめします。これは、link rel preload などの機能にアクセスできるため、非常に便利です。

このケースでは、Google Web Fonts Helper というツールが、ウェブフォントの一部をオフラインにしてローカルに設定するのに非常に役立ちました。このツールをぜひチェックしてみてください。

重要なリソースの一部としてウェブフォントを使用している場合でも、JavaScript を使用している場合でも、ブラウザが重要なリソースをできるだけ早く配信できるようにしてください。

試験運用版: 優先度ヒント

本日は、特別な情報をお届けします。リソースヒントやプリロードなどの機能に加えて、Google は優先度ヒントと呼ばれる、まったく新しい試験運用版のブラウザ機能に取り組んでいます。

最初に表示されるコンテンツの優先度を設定する
図 20. 優先度ヒント

これは、リソースの重要度をブラウザにヒントとして伝えることができる新機能です。新しい属性 importance が公開され、値として low、high、auto を指定できます。

これにより、重要でないリソース(重要でないスタイル、画像、フェッチ API 呼び出しなど)の優先度を下げて、競合を減らすことができます。また、ヒーロー画像など、より重要なものの優先度を上げることもできます。

Oodle アプリの場合、このことが、最適化できる実用的な場所につながりました。

最初に表示されるコンテンツの優先度を設定する
図 21. 最初に表示されるコンテンツの優先度を設定する

画像に遅延読み込みを追加する前は、ブラウザはすべての Doodle を含む画像カルーセルを読み込んでいました。ブラウザは、カルーセルの最初の段階ですべての画像を高い優先度で取得していました。残念ながら、ユーザーにとって最も重要だったのは、カルーセルの真ん中にある画像でした。そこで、背景画像の重要度を非常に低く、前景画像の重要度を非常に高く設定しました。これにより、低速の 3G で 2 秒の影響があり、これらの画像をどれだけ迅速に取得してレンダリングできるかがわかりました。良い体験ができました。

この機能は、数週間以内に Canary に導入される予定です。

ウェブフォントの読み込み戦略を立てる

タイポグラフィは優れたデザインの基本です。ウェブフォントを使用している場合は、テキストのレンダリングをブロックしないことが理想的であり、不可視のテキストを表示しないことが不可欠です。

Lighthouse では、ウェブフォントの読み込み中に非表示のテキストを回避する監査で、この問題がハイライト表示されるようになりました。

ウェブフォントの読み込み中にテキストが表示されない
図 22. ウェブフォントの読み込み中にテキストが表示されない状態を回避する

フォントフェイス ブロックを使用してウェブフォントを読み込む場合、ウェブフォントの取得に時間がかかると、ブラウザが処理を決定します。一部のブラウザでは、システム フォントにフォールバックするまで最大 3 秒間待機し、ダウンロードが完了するとフォントをスワップします。

この不可視テキストを回避するため、ウェブフォントの読み込みに時間がかかりすぎた場合、今週のクラシックな Doodle は表示されなかったでしょう。幸いなことに、font-display という新機能を使用すると、このプロセスをより細かく制御できます。

    @font-face {
      font-family: 'Montserrat';
      font-style: normal;
      font-display: swap;
      font-weight: 400;
      src: local('Montserrat Regular'), local('Montserrat-Regular'),
          /* Chrome 26+, Opera 23+, Firefox 39+ */
          url('montserrat-v12-latin-regular.woff2') format('woff2'),
            /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
          url('montserrat-v12-latin-regular.woff') format('woff');
    }

フォント表示は、ウェブフォントの入れ替えにかかる時間に基づいて、ウェブフォントのレンダリング方法やフォールバック方法を決定するのに役立ちます。

この例では、font-display: swap を使用しています。swap を指定すると、フォントフェイスのブロック期間は 0 秒、スワップ期間は無限になります。つまり、フォントの読み込みに時間がかかる場合、ブラウザは代替フォントを使用してテキストをすぐに描画します。フォントフェイスが利用可能になると、スワップされます。

このアプリの場合、この方法が優れているのは、非常に早い段階で意味のあるテキストを表示し、準備ができたらウェブフォントに移行できる点です。

フォント表示の結果
図 23. フォント表示の結果

一般的に、ウェブの大部分がそうであるように、ウェブフォントを使用している場合は、適切なウェブフォント読み込み戦略を導入してください。

フォントの読み込みエクスペリエンスを最適化するために使用できるウェブ プラットフォーム機能はたくさんありますが、Zach Leatherman 氏の Web Font Recipes リポジトリも非常に優れているので、ぜひご覧ください。

レンダリングをブロックするスクリプトを減らす

ダウンロード チェーンの早い段階でプッシュして、少なくとも基本的なユーザー エクスペリエンスを少し早めに提供できるアプリケーションの他の部分があります。

Lighthouse のタイムライン ストリップを見ると、すべてのリソースが読み込まれる最初の数秒間は、ユーザーはコンテンツをまったく見ることができないことがわかります。

レンダリングを妨げるスタイルシートを減らす
図 24. レンダリングを妨げるスタイルシートを削減する

外部スタイルシートのダウンロードと処理により、レンダリング プロセスの進行が妨げられています。

一部のスタイルを少し早めに配信することで、クリティカル レンダリング パスの最適化を試みることができます。

この初期レンダリングを担当するスタイルを抽出し、HTML にインライン化すると、ブラウザは外部スタイルシートの到着を待たずにすぐにレンダリングできます。

この例では、Critical という NPM モジュールを使用して、ビルドステップ中に重要なコンテンツを index.html にインライン化しました。

このモジュールは、ほとんどの面倒な作業を代行してくれますが、異なるルート間でスムーズに動作させるには、少し工夫が必要でした。

注意を払わない場合や、サイトの構造が非常に複雑な場合は、最初からアプリケーション シェル アーキテクチャを計画していないと、このタイプのパターンを導入するのは非常に困難になる可能性があります。

そのため、早い段階でパフォーマンスを考慮することが重要です。最初からパフォーマンスを考慮して設計しないと、後で問題が発生する可能性が高くなります。

最終的に、このリスクは報われました。この方法がうまく機能し、アプリはコンテンツをはるかに早く配信するようになり、First Meaningful Paint の時間が大幅に改善されました。

結果

サイトに適用したパフォーマンス最適化のリストは長いものでした。結果を見てみましょう。これは、最適化の前後で、3G ネットワーク上のミディアム モバイル デバイスにアプリが読み込まれた方法です。

Lighthouse のパフォーマンス スコアが 23 から 91 に上昇しました。速度の点では、かなり進歩しています。すべての変更は、Lighthouse レポートを継続的に確認してフォローすることによって行われました。すべての改善を技術的に実装した方法を確認するには、Google のリポジトリ、特にそこに登録されている PR をご覧ください。

予測パフォーマンス - データドリブンのユーザー エクスペリエンス

Google は、機械学習が多くの分野で将来的に大きな可能性を秘めていると考えています。今後、さらに多くのテストが実施されることを期待しているアイデアの 1 つは、実際のデータが、作成しているユーザー エクスペリエンスを実際に導くことができるということです。

現在、ユーザーが何を望んでいるか、何を必要としているか、したがって、何をプリフェッチ、プリロード、プリキャッシュする価値があるかについて、多くの任意の決定を行っています。推測が正しければ、少数のリソースを優先できますが、ウェブサイト全体にスケーリングするのは非常に困難です。

実際、今日の最適化に役立つデータが利用可能です。Google アナリティクス Reporting API を使用すると、サイト上の任意の URL について、次にアクセスされた上位のページと離脱率を確認できるため、優先すべきリソースを判断できます。

これを適切な確率モデルと組み合わせることで、コンテンツを過剰にプリフェッチしてユーザーのデータを無駄にすることを回避できます。Google アナリティクスのデータを活用し、機械学習とマルコフ連鎖やニューラル ネットワークなどのモデルを使用して、このようなモデルを実装できます。

ウェブアプリのデータドリブン バンドル
図 25. ウェブアプリのデータドリブン バンドル

このテストを促進するため、Guess.js という新しい取り組みを発表いたします。

Guess.js
図 26. Guess.js

Guess.js は、ウェブのデータドリブンなユーザー エクスペリエンスに焦点を当てたプロジェクトです。このレポートが、データを使用してウェブ パフォーマンスを向上させる方法を模索するきっかけとなり、さらにその先へと進む一助となることを願っています。すべてオープンソースで、GitHub で今すぐ入手できます。これは、Minko Gechev、Gatsby の Kyle Matthews、Katie Hempenius、その他多くの人々がオープンソース コミュニティと協力して構築したものです。

Guess.js をぜひお試しいただき、ご意見をお聞かせください。

概要

スコアと指標はウェブの速度を向上させるのに役立ちますが、これらは手段にすぎず、目標そのものではありません。

外出先でページの読み込みが遅いという経験は誰にでもあると思いますが、今では、ユーザーに非常に高速に読み込まれる快適なエクスペリエンスを提供できるようになりました。

パフォーマンスの向上は、一朝一夕に実現できるものではありません。小さな変化を積み重ねることで、大きな成果につながります。適切な最適化ツールを使用し、Lighthouse レポートを注視することで、より優れた、より包括的なエクスペリエンスをユーザーに提供できます。

Ward Peeters、Minko Gechev、Kyle Mathews、Katie Hempenius、Dom Farolino、Yoav Weiss、Susie Lu、Yusuke Utsunomiya、Tom Ankers、Lighthouse、Google Doodles の各氏に感謝いたします。