ウェブ パフォーマンスを簡単に - Google I/O 2018 版

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

Ewa Gasperowicz

Google は、ウェブをより高速でパフォーマンスの高いものにする方法を模索するため、この 1 年間、かなり忙しくしていました。この記事では、その結果として生まれた新しいツール、アプローチ、ライブラリをご紹介します。前半では、The Oodles Theater アプリの開発で実際に使用した最適化手法をいくつかご紹介します。後半では、予測読み込みに関するテストと、新しい Guess.js イニシアチブについて説明します。

パフォーマンスの必要性

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

ウェブサイトのサイズの増大は、ネットワーク レイテンシ、CPU の制限、レンダリング ブロック パターン、不要なサードパーティ コードなどの他の要因と相まって、パフォーマンスの複雑なパズルを構成しています。

ほとんどのユーザーは、ニーズの UX 階層の最上位に速度を挙げています。ページが読み込まれるまで、ユーザーはあまり操作できないため、これは当然の結果です。ページから価値を引き出すことも、その美学を称賛することもできません。

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

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

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

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

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

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

Oodles Theater アプリというデモ用ウェブアプリを例に、これらの API を活用する方法を見てみましょう。このアプリでは、お気に入りのインタラクティブな Google Doodle を試したり、ゲームをプレイしたりできます。

アプリの構築にあたっては、可能な限りパフォーマンスを高めることを目指しました。最適化の出発点は Lighthouse レポートでした。

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

Lighthouse レポートで確認したアプリの初期パフォーマンスは、かなりひどいものでした。3G ネットワークでは、ユーザーは最初の意味のあるペイント、またはアプリがインタラクティブになるまで 15 秒待つ必要がありました。Lighthouse はサイトに関する多くの問題をハイライト表示し、全体的なパフォーマンス スコアは 23 でした。

ページの重さは約 3.4 MB で、大幅な削減が必要でした。

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

パフォーマンスの最適化案

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

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

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

Lighthouse は、この機会を圧縮されていない CSS と JavaScript の監査でハイライト表示します。ビルドプロセスに webpack を使用していたため、縮小化を実現するために Uglify JS プラグインを使用しました。

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

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

コードのホスティングに Firebase Hosting を使用していました。Firebase ではデフォルトで gzipping が有効になっているため、妥当な CDN でコードをホストするだけで、無料で利用できました。

gzip は非常に一般的な圧縮方法ですが、ZopfliBrotli などの他のメカニズムも普及しつつあります。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 行の小さなコミットとしてはかなり良い結果です。

もちろん、パフォーマンス スコアも上がり、インタラクティブになるまでの時間も大幅に改善されました。

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

コードの 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 で、かなり大きなサイズです。

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

次に、別のツールである 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-libs-optimizations リポジトリで、webpack を使用している場合にライブラリのサイズを縮小する方法のアイデアを確認してください。

画像を最適化する

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

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

画像の最適化を忘れていたり、サイズを正しく設定していなかったり、他の画像形式を使用することでメリットが得られる場合もあります。

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

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

1 回限りの最適化には、ImageOptimXNConvert などの視覚的なツールを使用できます。

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

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

費用やレイテンシの問題でそうしたくない場合は、ThumborImageflow などのプロジェクトでセルフホスト型の代替手段を利用できます。

最適化前後の比較
図 15. 最適化前後の比較

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

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

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

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

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

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 を提供することができました。

このインターフェースは、実効往復時間とダウンニング値を使用して、ユーザーが使用しているネットワーク タイプを推定します。文字列「slow 2G」、「2G」、「3G」、「4G」を返すだけです。この値に応じて、ユーザーが 4G 未満のネットワークを使用している場合は、動画要素を画像に置き換えることができます。

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

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

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

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

Lighthouse は、この動作をオフスクリーン イメージ監査でフラグ設定します。また、デベロッパー ツールのネットワーク パネルで確認することもできます。ページに表示されている画像はわずかなのに、大量の画像が読み込まれている場合は、遅延読み込みを検討してください。

遅延読み込みはブラウザでネイティブにサポートされていないため、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=preconnectpreloadprefetch などのリソース ヒントがあります。

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

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. リソースのプリロードの影響

通常、リンク rel プリロードを使用しない場合、ウェブフォントがページにとって重要な場合、ブラウザはまず HTML を取得し、CSS を解析し、ずっと後になってからウェブフォントを取得します。

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

Google Fonts を使用してフォントをプリロードする場合は、注意点があります。

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

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

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

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

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

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

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

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

Oodle アプリの場合、これにより実際に最適化できる場所が 1 つ見つかりました。

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

画像を遅延読み込みする前は、ブラウザは、すべての落書きを含む画像カルーセルを読み込む際に、カルーセルの開始時にすべての画像を高い優先度で取得していました。残念ながら、ユーザーにとって最も重要なのはカルーセルの真ん中の画像でした。そこで、背景画像の重要度を非常に低く、前景画像の重要度を非常に高く設定しました。これにより、3G の遅い回線で 2 秒の差が生じ、画像をどれだけ早く取得してレンダリングできるかがわかりました。良い体験でした。

この機能は数週間以内に Canary に導入される予定です。ご期待ください。

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

タイポグラフィは優れたデザインの基本です。ウェブフォントを使用している場合、テキストのレンダリングをブロックしたくありません。また、テキストを非表示にしたくもありません。

Lighthouse では、Web フォントの読み込み中に不可視テキストを回避する監査でこの点を強調しています。

Web フォントの読み込み中にテキストが非表示にならないようにする
図 22. Web フォントの読み込み中にテキストが非表示にならないようにする

フォント フェイス ブロックを使用してウェブフォントを読み込むと、ウェブフォントの取得に時間がかかった場合の処理をブラウザに任せることになります。ブラウザによっては、システム フォントにフォールバックする前に最大 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');
    }

フォント表示を使用すると、ウェブフォントのレンダリング方法や、フォントの切り替えにかかる時間に基づいてフォールバックする方法を決定できます。

この例では、フォント表示の切り替えを使用しています。Swap は、フォント フェイスに 0 秒のブロック期間と無限のスワップ期間を与えます。つまり、フォントの読み込みに時間がかかる場合、ブラウザはフォールバック フォントを使用してテキストをすぐに描画します。フォントが利用可能になったら、それを入れ替えます。

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

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

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

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

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

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

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

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

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

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

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

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

このモジュールはほとんどの作業を代行してくれましたが、さまざまなルートでスムーズに動作させるのは少し難しいものでした。

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

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

最終的にリスクは報われ、この方法でアプリを動作させることができ、コンテンツの配信を大幅に早めることができ、ファースト コンテンツの表示時間を大幅に短縮することができました。

結果

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

Lighthouse のパフォーマンス スコアが 23 から 91 に向上しました。速度の面ではかなり良い進歩です。これらの変更はすべて、Lighthouse レポートを継続的に確認し、それに沿って行ったものです。技術的にどのように改善が実装されたかについては、リポジトリをご覧ください。特に、そこに反映された PR をご覧ください。

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

私たちは、機械学習が多くの分野で将来の大きな可能性を秘めていると考えています。今後、より多くの実験を促すアイデアの一つとして、実際のデータが作成するユーザー エクスペリエンスを導くことができるという考えがあります。

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

実際には、最適化に役立つデータがすでに利用可能です。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、宇都宮 佑介、Tom Ankers、Lighthouse、Google Doodle の皆様に感謝いたします。