テキストベースのアセットのエンコードと転送サイズを最適化する

不要なリソースのダウンロードをなくす以外に、ページの読み込み速度を改善する最善策は、残りのリソースを最適化して圧縮し、全体のダウンロード サイズを最小限に抑えることです。

データ圧縮 101

未使用のリソースをダウンロードしないようにウェブサイトを設定したら、ブラウザがダウンロードする必要がある残りの対象リソースを圧縮します。リソースの種類(テキスト、画像、フォントなど)に応じて、ウェブサーバーで有効にできる汎用ツール、特定のコンテンツ タイプの前処理の最適化、デベロッパーによる入力を必要とするリソース固有の最適化など、さまざまな手法から選択できます。

最高のパフォーマンスを実現するには、次のすべての手法を組み合わせる必要があります。

  • 圧縮とは、より少ないビットで情報をエンコードするプロセスです。
  • 不要なデータを排除することが、常に最良の結果をもたらします。
  • 圧縮の手法とアルゴリズムは多種多様です。
  • 最適な圧縮を実現するには、さまざまな手法が必要になります。

データサイズを小さくするプロセスはデータ圧縮です。多くの人々がアルゴリズム、技術、最適化に貢献し、さまざまな圧縮アルゴリズムに必要な圧縮率、圧縮速度、メモリを改善してきました。

データ圧縮の詳細については、このガイドの範囲外です。ただし、圧縮の仕組みと、ページに必要なさまざまなアセットのサイズを削減するために使用できる手法を大まかに理解することが重要です。

これらの手法の基本原則を説明するために、この例のために作成した単純なテキスト メッセージ形式を最適化するプロセスについて考えてみましょう。

# Below is a secret message, which consists of a set of headers in
# key-value format followed by a newline and the encrypted message.
format: secret-cipher
date: 08/25/16
AAAZZBBBBEEEMMM EEETTTAAA
  1. メッセージには、接頭辞「#」で示される任意のアノテーション(コメントと呼ばれることもあります)が含まれる場合があります。アノテーションは、メッセージの意味や動作には影響しません。
  2. メッセージにはヘッダーheadersが含まれている場合があります。ヘッダーはメッセージの先頭に表示される Key-Value ペア(上記の例では ":" で区切られています)です。
  3. メッセージはテキスト ペイロードを伝送します。

前のメッセージのサイズ(200 文字から始まる)を減らすにはどうすればよいですか。

  1. コメントは興味深いものですが、メッセージの意味には影響しません。メッセージの送信時に除外します。
  2. ヘッダーを効率的にエンコードするための優れた手法があります。たとえば、すべてのメッセージに「format」と「date」があることがわかっている場合、それらを短い整数 ID に変換して送信できます。ただし、そうではないかもしれないので、とりあえずそのままにしておくことをおすすめします。
  3. ペイロードはテキストのみです。その中身が実際に何であるかはわかりませんが(明らかに、"secret-cipher" を使用しています)、テキストを見ると、多くの冗長性があることがわかります。おそらく、同じ文字を繰り返すのではなく、繰り返されている文字の数を数えて、より効率的にエンコードできます。たとえば、"AAA""3A" になります。これは、3 つの A のシーケンスを表します。

これらの手法を組み合わせると、次のような結果が得られます。

format: secret-cipher
date: 08/25/16
3A2Z4B3E3M 3E3T3A

新しいメッセージの長さは 56 文字です。これは、元のメッセージが 72% 圧縮されたことを意味します。これは大幅に削減されました。

これは、テキストベースのリソースの転送サイズを削減するのに圧縮アルゴリズムがいかに効果的であるかを示す簡単な例です。実際には、圧縮アルゴリズムは前の例よりもはるかに洗練されています。ウェブでは、圧縮アルゴリズムを使用してリソースのダウンロード時間を大幅に短縮できます。テキストベースのアセットに圧縮を適用すると、ウェブページでのリソースの読み込みに要する時間が短縮され、圧縮しない場合よりも早くリソースの効果を確認できます。

圧縮: 前処理、コンテキスト固有の最適化

ここで説明する最初の手法は圧縮です。圧縮は厳密には圧縮アルゴリズムではありませんが、ソースコードで使用されている不要な冗長な文字を削除して、人間がリソースを読みやすくする方法です。ただし、本番環境のウェブサイトでソースコードの機能を維持するには、可読性を高める必要はありません。また、ウェブ上のリソースの読み込みが遅れる可能性もあります。

圧縮はコンテンツ固有の最適化の一種で、配信されるリソースのサイズを大幅に削減できます。最適化はビルドとデプロイのプロセスの一部として適用するのが最も効果的です。たとえば、バンドラはよく使われるソフトウェアの一種で、新しい本番環境用コードをウェブサイトにデプロイする直前に自動的にリソースを圧縮できます。

冗長なデータや不要なデータを圧縮する最善の方法は、それを削除することです。ただし、任意のデータを削除することはできません。ただし、データ形式とそのプロパティについてコンテンツ固有の知識がある場合は、実際の意味や機能に影響を与えることなくペイロードのサイズを大幅に削減できます。

<html>
  <head>
    <style>
      /* awesome-container is only used on the landing page */
      .awesome-container {
        font-size: 120%;
      }

      .awesome-container {
        width: 50%;
      }
    </style>
  </head>
  <body>
    <!-- awesome container content: START -->
    <div>
      This is my awesome container, and it is <em>so</em> awesome.
    </div>
    <!-- awesome container content: END -->
    <script>
      awesomeAnalytics(); // Beacon conversion metrics
    </script>
  </body>
</html>

前述の HTML スニペットと、それに含まれる 3 種類のコンテンツについて考えてみましょう。

  1. 使用します。
  2. ページの表示形式をカスタマイズする CSS です。
  3. インタラクションやその他の高度なページ機能を強化する JavaScript。

これらのコンテンツ タイプごとに、有効なコンテンツを構成するルールやコメントを指定するルールなどが異なります。残る問題は、「このページのサイズを小さくするにはどうすればよいか」です。

  • コードコメントはデベロッパーにとっては大切なものですが、ブラウザでは必要ありません。CSS(/* ... */)、HTML(<!-- ... -->)、JavaScript(// ...)のコメントを削除すると、ページとそのサブリソースの合計転送サイズが減少します。
  • 「スマートな」CSS コンプレッサーでは、.awesome-container のルールを定義する方法が非効率的であることに気付き、他のスタイルに影響を与えることなく 2 つの宣言を 1 つにまとめ、バイト数をさらに削減できます。大規模な CSS ルールセットでは、このような重複をなくすことが積み重なる可能性がありますが、メディアクエリ内など、異なるコンテキストでセレクタが必然的に重複することが多いため、積極的には適用できない可能性があります。
  • スペースとタブは、HTML、CSS、JavaScript でデベロッパーにとって便利なものです。コンプレッサーを追加すると、タブとスペースがすべて削除されます。他の重複除去手法とは異なり、この種の最適化は、ページの表示にそのようなスペースやタブが不要である限り、積極的に適用できます。たとえば、HTML ドキュメント内のテキスト実行内のスペースを保持し、ユーザーに表示されるコンテンツの可読性を確保します。
<html><head><style>.awesome-container{font-size:120%;width:50%}</style></head><body><div>This is my awesome container, and it is <em>so</em> awesome.</div><script>awesomeAnalytics()</script></body></html>

上記の手順を適用すると、ページは 516 文字から 204 文字になり、約 60% 削減されます。確かにあまり読み取りやすくはありませんが、使用するために必須ではありません。最新の開発手法では、適切にフォーマットされた読みやすいソースコードのバージョンを、本番環境に配布する十分に最適化されたコードと分離しておくこともできます。変換後の本番環境コードを読み取り可能なソースマップと組み合わせることで、本番環境のバグをより簡単にトラブルシューティングできます。これにより、優れたデベロッパー エクスペリエンスと、ユーザー エクスペリエンスを目的としたパフォーマンスの両方を実現できます。

上記の例では、汎用の圧縮ツール(任意のテキストを圧縮する設計の圧縮ツールなど)でページを圧縮できますが、コメントの削除、CSS ルールの折りたたみなど、コンテンツ固有のさまざまな最適化が行われることは決してわかりません。前述の例は、重要なポイントを示しています。このため、前処理、圧縮、その他のコンテキストアウェア最適化が重要です。

同様に、前述の手法は、テキストベースのアセット以外にも拡張できます。画像、動画、その他のコンテンツ タイプには、すべて独自の形式のメタデータとさまざまなペイロードが含まれています。たとえば、カメラで写真を撮るたびに、通常、そのファイルにはカメラの設定や位置情報など、多くの追加情報が埋め込まれています。アプリケーションによっては、このデータは重要(写真共有サイトなど)になる場合もあれば、まったく役に立たない場合もあります。削除する価値があるかどうかを検討する必要があります。実際には、このメタデータは画像ごとに最大数十 KB になる場合があります。

要するに、アセットの効率を最適化する最初のステップとして、さまざまなコンテンツ タイプのインベントリを作成し、どのようなコンテンツ固有の最適化を適用してサイズを縮小できるかを検討します。最適化の内容を把握したら、その最適化をビルドとリリースのステップに追加して自動化します。これにより、本番環境へのすべての新しいリリースで一貫して最適化が適用されるようになります。

圧縮アルゴリズムによるテキスト圧縮

テキストベースのアセットのサイズを縮小する次のステップは、それらに圧縮アルゴリズムを適用することです。さらに一歩進めて、ユーザーに送信する前にテキストベースのペイロードで繰り返し可能なパターンを積極的に検索し、ユーザーのブラウザに到着したら解凍します。その結果、これらのリソースがさらに大幅に削減され、ダウンロード時間が短縮されます。

  • gzip と Brotli は一般的に使用されている圧縮アルゴリズムで、テキストベースのアセット(CSS、JavaScript、HTML)で最高のパフォーマンスを発揮します。
  • 最新のブラウザはすべて gzip 圧縮と Brotli 圧縮をサポートしており、Accept-Encoding HTTP リクエスト ヘッダーで両方のサポートをアドバタイズします。
  • 圧縮を有効にできるようにサーバーを構成する必要があります。多くの場合、ウェブサーバー ソフトウェアはデフォルトで、モジュールでテキストベースのリソースを圧縮できるようにします。
  • gzip と Brotli はどちらも、圧縮レベルを調整することで圧縮率を高めるために微調整できます。gzip の場合、圧縮設定の範囲は 1 ~ 9 で、9 が最適です。Brotli の場合、この範囲は 0 ~ 11 で、11 が最適です。ただし、圧縮率の設定が高いほど時間がかかります。動的に圧縮されるリソース(つまり、リクエストの実行時)では、圧縮率と速度の間で最適なトレードオフを範囲の中間に設定する傾向にあります。ただし、静的圧縮も可能です。この場合、レスポンスが事前に圧縮されるため、各圧縮アルゴリズムで利用可能な最も積極的な圧縮設定を使用できます。
  • コンテンツ配信ネットワーク(CDN)では通常、条件を満たすリソースを自動的に圧縮します。CDN は動的圧縮と静的圧縮を管理できるため、懸念される圧縮の側面が 1 つ減ります。

gzipBrotli は、あらゆるバイト ストリームに適用できる一般的な圧縮ツールです。内部的には、これまでに確認したファイルの内容の一部を記憶し、その後、重複するデータ フラグメントを効率的に検出して置換しようとします。

実際には、gzip と Brotli はどちらもテキストベースのコンテンツで最高のパフォーマンスを発揮し、多くの場合、サイズの大きいファイルでは 70 ~ 90% もの圧縮率を達成します。ただし、可逆圧縮または非可逆圧縮技術を使用するほとんどの画像形式など、すでに代替アルゴリズムを使用して圧縮されているこれらのアルゴリズム アセットを実行しても、ほとんど改善されません。

最新のブラウザはすべて、Accept-Encoding HTTP リクエスト ヘッダーで gzip と Brotli のサポートをアドバタイズします。ただし、クライアントがリクエストしたときに圧縮リソースを提供するようにウェブサーバーを適切に構成することは、ホスティング プロバイダの責任になります。

File アルゴリズム 非圧縮サイズ 圧縮後のサイズ 圧縮比
angular-1.8.3.js ブロトリ 1,346 KiB 256 KiB 81%
angular-1.8.3.js gzip 1,346 KiB 329 KiB 76%
angular-1.8.3.min.js ブロトリ 173 KiB 53 KiB 69%
angular-1.8.3.min.js gzip 173 KiB 60 KiB 65%
jquery-3.7.1.js ブロトリ 302 KiB 69 KiB 77%
jquery-3.7.1.js gzip 302 KiB 83 KiB 73%
jquery-3.7.1.min.js ブロトリ 85 KiB 27 KiB 68%
jquery-3.7.1.min.js gzip 85 KiB 30 KiB 65%
lodash-4.17.21.js ブロトリ 531 KiB 73 KiB 86%
lodash-4.17.21.js gzip 531 KiB 94 KiB 82%
lodash-4.17.21.min.js ブロトリ 71 KiB 23 KiB 68%
lodash-4.17.21.min.js gzip 71 KiB 25 KiB 65%

上記の表は、Brotli 圧縮と gzip 圧縮により、いくつかの有名な JavaScript ライブラリで節約できる費用を示しています。削減率はファイルやアルゴリズムに応じて 65 ~ 86% です。参考までに、最大圧縮レベルは Brotli と gzip の両方の各ファイルに適用されています。可能な限り、gzip よりも Brotli を優先してください。

圧縮の有効化は、実装が最も簡単で効果的な最適化の 1 つです。ウェブサイトでこの機能を活用していないと、ユーザーのパフォーマンスを向上させる大きなチャンスを逃しています。幸いなことに、多くのウェブサーバーは、この重要な最適化を可能にするデフォルト構成を提供しています。CDN は、圧縮速度と圧縮率のバランスが取れた方法で実装する場合に特に効果的です。

圧縮の動作を簡単に確認するには、Chrome DevTools を開いて [Network] パネルを開き、任意のページを読み込み、ネットワーク パネルの一番下を確認します。

DevTools による実際のサイズと転送サイズの測定結果。
Chrome DevTools のネットワーク パネルに表示されている、すべてのページリソースの転送サイズ(つまり圧縮)と実際のサイズの比較。

上の画像のように、次の内訳が表示されます。

  • リクエストの数。これは、ページに対して読み込まれたリソースの数です。
  • すべてのリクエストの転送サイズ。これは、ページのリソースに適用された圧縮の効果を反映しています。
  • すべてのリクエストのリソースサイズ。これは、解凍後のページのリソースのサイズを表します。

Core Web Vitals への影響

パフォーマンスの向上は、その改善を反映する指標がなければ測定できません。Core Web Vitals イニシアチブは、実際のユーザー エクスペリエンスを反映する指標を作成し、その認識を高めることを目的としています。これは、単にページの読み込み時間など、ユーザー エクスペリエンスの質に明確に左右されない指標とは対照的です。

このガイドで説明する最適化をウェブサイトのリソースに適用した場合、Core Web Vitals への影響は、最適化されたリソースと関連する指標によって異なります。ただし、次のような場合は、これらの最適化を適用することでウェブサイトの Core Web Vitals を改善できます。

  • HTML リソースを圧縮および圧縮すると、HTML の読み込みとサブリソースの検出可能性が向上し、その結果、サブリソースの読み込みが改善されます。これはページの Largest Contentful Paint(LCP)に役立ちます。rel="preload" などのリソースヒントを使用すると、リソースの検出可能性に影響を与える可能性がありますが、あまりにも多くのリソースヒントを使用すると、帯域幅の競合で問題が発生する可能性があります。ナビゲーション リクエストの HTML レスポンスを圧縮すると、プリロード スキャナによって、リソース内のリソースをできるだけ早く検出できます。
  • 一部の LCP 候補は、圧縮を使用してより早く読み込むこともできます。たとえば、LCP の候補である SVG 画像は、テキストベースの圧縮によってリソースの読み込み時間を短縮できます。これは、JPEG 画像で非可逆圧縮を使用する方法など、他の圧縮方法によって本質的に圧縮される他の画像タイプに対して行う最適化とは異なります。
  • また、テキストノードを LCP の候補にすることもできます。このガイドで説明する手法は、ウェブページのテキストにウェブフォントを使用しているかどうかによって異なります。ウェブフォントを使用している場合は、ウェブフォントの最適化に関するベスト プラクティスを参考にしてください。ただし、ウェブフォントではなく、リソースの読み込み時間なしで表示されるシステム フォントを使用している場合は、CSS を圧縮して圧縮すると読み込み時間が短縮されます。つまり、潜在的な LCP テキストノードのレンダリングが早くなります。

まとめ

テキストベースのアセットのエンコードと転送を最適化する方法は、基本的なパフォーマンス コンセプトですが、大きな影響を及ぼします。圧縮と圧縮の対象となるリソースで最適化のメリットを確実に得られるように、できる限りのことを行ってください。

さらに重要なのは、これらのプロセスが自動化されていることを確認することです。圧縮するには、バンドラを使用して対象のリソースに圧縮を適用します。ウェブサーバーの構成で圧縮がサポートされていることを確認しますが、それ以外にも、利用可能な最も効果的な圧縮方法を使用します。これをできるだけ簡単にするために、CDN を使用して圧縮を自動化します。CDN はリソースを圧縮できるだけでなく、非常に迅速に圧縮することもできます。

これらの基本的なパフォーマンス コンセプトをウェブサイトのアーキテクチャに組み込むことで、パフォーマンス最適化の取り組みが適切な基盤を成し、その後の最適化が適切なベースライン プラクティスの強固な基盤の上に成り立つようになります。