compression
JavaScriptのGzipおよびBrotli圧縮技術を解説します。ネットワーク転送時間の最適化や、本番ビルドに向けたサーバーサイド圧縮の設定を行う際に活用してください。
description の原文を見る
Teaches JavaScript compression techniques including Gzip and Brotli. Use when optimizing network transfer times or configuring server-side compression for production builds.
SKILL.md 本文
JavaScriptの圧縮
目次
JavaScriptは、画像に次ぐページサイズの第2の原因であり、インターネット上で最もリクエストされるウェブリソースの第2位です。JavaScriptの転送、読み込み、実行時間を削減するパターンを使用して、ウェブサイトのパフォーマンスを向上させます。圧縮はスクリプトをネットワーク経由で転送するのに必要な時間を削減するのに役立ちます。
使用時期
- JavaScriptペイロードサイズを削減してページ読み込みを高速化する必要がある場合に使用してください
- ネットワーク転送時間を最適化する場合に特に役立ちます。特に低速接続のユーザー向けです
- ミニファイ、コード分割、キャッシング戦略と組み合わせて使用してください
説明
- Gzipより優れた圧縮率を提供するため、Brotli圧縮を優先してください
- 頻繁に変更されないアセットには静的圧縮を使用し、頻繁に変更されるコンテンツには動的圧縮を使用してください
- サーバーまたはCDNレベルで圧縮を有効にしてください(例: Nginx、Vercel、Netlify)
- 圧縮を適用する前にJavaScriptをミニファイしてください
- 粒度のトレードオフに注意してください。より大きなバンドルはより圧縮されやすいですが、より小さなチャンクはキャッシュされやすいです
詳細
ミニファイ、コード分割、バンドル、キャッシング、遅延読み込みなどの他のテクニックと組み合わせて圧縮を使用し、大量のJavaScriptのパフォーマンスへの影響を削減できます。ただし、これらのテクニックの目的が相互に矛盾することがあります。このセクションではJavaScript圧縮テクニックを探索し、コード分割と圧縮戦略を決定するときに考慮すべきニュアンスについて説明します。
- GzipとBrotliは、JavaScriptを圧縮する最も一般的な方法であり、最新のブラウザで広くサポートされています。
- Brotliは同様の圧縮レベルでより良い圧縮率を提供します。
- Next.jsはデフォルトでGzip圧縮を提供しますが、NginxなどのHTTPプロキシで有効にすることをお勧めします。
- Webpackを使用してコードをバンドルする場合、Gzip圧縮には**CompressionPlugin**を使用するか、Brotli圧縮にはBrotliWebpackPluginを使用できます。
- OyoはGzipの代わりにBrotli圧縮に切り替えた後、ファイルサイズで15~20%の削減を見た、Wixは21~25%の削減を見ました。
- compress(a + b) <= compress(a) + compress(b) - 1つの大きなバンドルは複数の小さなバンドルより優れた圧縮を提供します。これは重複排除とキャッシングがブラウザパフォーマンスと圧縮に対立する粒度トレードオフを引き起こします。粒度の細かいチャンク分割はこのトレードオフに対処するのに役立ちます。
HTTP圧縮
圧縮はドキュメントやファイルのサイズを削減し、元のサイズより少ないディスク領域を使用します。より小さなドキュメントはより低い帯域幅を消費し、ネットワーク経由で迅速に転送できます。HTTP圧縮はこの単純な概念を使用してウェブサイトコンテンツを圧縮し、ページの重さを削減し、帯域幅要件を下げ、パフォーマンスを向上させます。
HTTPデータ圧縮はさまざまな方法で分類できます。その1つは非可逆圧縮対可逆圧縮です。
非可逆圧縮とは、圧縮・解凍サイクルの結果、ドキュメントがわずかに変更されつつその使用可能性は保持されることを意味します。変更はエンドユーザーにはほぼ認識できません。非可逆圧縮の最も一般的な例は、画像のJPEG圧縮です。
可逆圧縮では、圧縮の後の解凍後に回復されるデータは元のデータと正確に一致します。PNG画像は可逆圧縮の例です。可逆圧縮はテキスト転送に関連し、HTML、CSS、JavaScriptなどのテキストベースの形式に適用する必要があります。
ブラウザで有効なすべてのJSコードを必要とするため、JavaScriptコードに対して可逆圧縮アルゴリズムを使用する必要があります。JSを圧縮する前に、ミニファイは不要な構文を排除し、実行に必要なコードのみに削減するのに役立ちます。
ミニファイ
ペイロードサイズを削減するために、圧縮前にJavaScriptをミニファイできます。ミニファイは、空白と不要なコードを削除して、より小さいが完全に有効なコードファイルを作成することで圧縮を補完します。コードを書くときは、改行、インデント、スペース、適切に名前付けされた変数、およびコメントを使用して、コード可読性とメンテナンス性を向上させます。ただし、これらの要素はJavaScriptの全体的なサイズに寄与し、ブラウザでの実行に必要ではありません。ミニファイはJavaScriptコードを成功した実行に必要な最小限に削減します。
ミニファイはJSとCSSの最適化の標準的な慣行です。JavaScriptライブラリ開発者は、本番展開用のファイルのミニファイされたバージョンを提供することが一般的です。通常、min.js名拡張子で表示されます。(例: jquery.jsとjquery.min.js)
HTML、CSS、JSリソースのミニファイには複数のツールが利用可能です。TerserはES6+向けの一般的なJavaScript圧縮ツールであり、Webpack v4にはこのライブラリのプラグインがデフォルトで含まれています。古いバージョンのWebpackでTerserWebpackPluginを使用するか、モジュールバンドラーなしでTerserをCLIツールとして使用することもできます。
静的圧縮と動的圧縮
ミニファイはファイルサイズを大幅に削減するのに役立ちますが、JSの圧縮はさらに大きな利益を提供できます。サーバー側の圧縮は2つの方法で実装できます。
静的圧縮: 静的圧縮を使用して、リソースを事前に圧縮し、ビルドプロセスの一部として事前に保存できます。この場合、より高い圧縮レベルを使用できるため、コードのダウンロード時間を改善できます。高いビルド時間はウェブサイトのパフォーマンスに影響しません。頻繁に変更されないファイルに静的圧縮を使用することをお勧めします。
動的圧縮: このプロセスでは、ブラウザがリソースをリクエストするときに圧縮がその場で行われます。動的圧縮は実装が容易ですが、より低い圧縮レベルの使用に制限されます。より高い圧縮レベルはより多くの時間が必要になり、より小さいコンテンツサイズから得られる利点を失うことになります。頻繁に変更されるか、アプリケーションで生成されるコンテンツに動的圧縮を使用することが役立ちます。
アプリケーションコンテンツのタイプに応じて、静的または動的圧縮を使用できます。一般的な圧縮アルゴリズムを使用して、静的と動的の両方の圧縮を有効にできますが、推奨される圧縮レベルは各ケースで異なります。
圧縮アルゴリズム
GzipとBrotliは、今日のHTTPデータ圧縮に使用される2つの最も一般的なアルゴリズムです。
Gzip
Gzip圧縮形式は約30年前から存在し、Deflateアルゴリズムに基づく可逆アルゴリズムです。Deflateアルゴリズム自体は、入力データストリーム内のデータブロックに対してLZ77アルゴリズムとハフマン符号化の組み合わせを使用します。
LZ77アルゴリズムは重複する文字列を識別し、以前に出現した場所へのポインタであるバックリファレンスと文字列の長さで置き換えます。その後、ハフマン符号化は一般的に使用されるリファレンスを識別し、それらをより短いビットシーケンスを持つリファレンスに置き換えます。より長いビットシーケンスは使用頻度の低いリファレンスを表すために使用されます。
すべての主要ブラウザはGzipをサポートしています。Zopfli圧縮アルゴリズムはDeflate/Gzipのより遅いが改善されたバージョンであり、より小さいGZip互換ファイルを生成します。静的圧縮に最適で、より大きな利益を提供できます。
Brotli
2015年に、GoogleはBrotliアルゴリズムとBrotli圧縮データ形式を導入しました。Gzipと同様に、BrotliもLZ77アルゴリズムとハフマン符号化に基づく可逆アルゴリズムです。さらに、2次コンテキストモデリングを使用して、同様の速度でより密度の高い圧縮を生成します。コンテキストモデリングは、同じブロック内の同じアルファベットに対して複数のハフマン木を使用できる機能です。Brotliは、バックリファレンス用により大きなウィンドウサイズをサポートし、静的辞書を備えています。これらの機能は圧縮アルゴリズムとしての効率を高めるのに役立ちます。
Brotliは今日すべての主要なサーバーとブラウザによってサポートされており、ますます人気が高まっています。また、Netlify、AWS、Vercelを含むホスティングプロバイダーとミドルウェアによってサポートされ、簡単に有効にできます。
OYOやWixなどの大規模なユーザーベースを持つウェブサイトは、GzipをBrotliに置き換えた後、パフォーマンスをかなり向上させました。
GzipとBrotliの比較
以下は、GzipとBrotliを使用したJS圧縮に関するChromeの研究からのいくつかの見解です。
- Gzip 9は優れた圧縮速度で最良の圧縮率を持ち、他のGzipレベルの前に使用を検討してください。
- Brotliでは、レベル6~11を検討してください。そうでなければ、Gzipでより高速な同様の圧縮率を達成できます。
- すべてのサイズ範囲でBrotli 9~11はGzipよりはるかに優れていますが、非常に遅いです。
- バンドルが大きいほど、圧縮率と速度が向上します。
- アルゴリズム間の関係はすべてのバンドルサイズで同様です(例えば、Brotli 7はすべてのバンドルサイズに対してGzip 9より優れており、Gzip 9はすべてのサイズ範囲でBrotli 5より高速です)。
圧縮の有効化
ビルドの一部として静的圧縮を有効にできます。Webpackを使用してコードをバンドルする場合、Gzip圧縮にはCompressionPluginを使用するか、Brotli圧縮にはBrotliWebpackPluginを使用できます。プラグインはWebpack設定ファイルに次のように含めることができます。
module.exports = {
//...
plugins: [
//...
new CompressionPlugin(),
],
};
Next.jsはデフォルトでGzip圧縮を提供しますが、NginxなどのHTTPプロキシで有効にすることをお勧めします。GzipとBrotliの両方はVercelプラットフォームでプロキシレベルでサポートされています。
異なる圧縮アルゴリズムをサポートするサーバー(Node.jsを含む)で動的な可逆圧縮を有効にできます。ブラウザはリクエストでAccept-Encoding HTTPヘッダーを通じて、サポートする圧縮アルゴリズムを通信します。例えば、Accept-Encoding: gzip, brです。
これはブラウザがGzipとBrotliをサポートすることを示しています。サーバーの特定のタイプの手順に従うことで、異なるタイプの圧縮をサーバーで有効にできます。例えば、ApacheサーバーでここでBrotliを有効にする手順を見つけることができます。ExpressはNodeの一般的なウェブフレームワークであり、圧縮ミドルウェアライブラリを提供しています。リクエストされたアセットを圧縮するために使用してください。
Brotliはより小さいファイルサイズを生成するため、他の圧縮アルゴリズムより推奨されます。BrotliをサポートしないブラウザのフォールバックとしてGzipを有効にできます。正常に設定されている場合、サーバーはContent-Encoding HTTPレスポンスヘッダーを返して、レスポンスで使用される圧縮アルゴリズムを示します。例: Content-Encoding: br。
圧縮の監査
Chrome DevTools → Network → Headersでサーバーがダウンロードされたスクリプトまたはテキストを圧縮したかどうかを確認できます。DevToolsはレスポンスで使用されるコンテンツエンコーディングを表示します。
Lighthouse レポートには、content-encodingヘッダーが「br」、「gzip」、または「deflate」に設定されていないテキストベースのリソースタイプを確認する「テキスト圧縮の有効化」のパフォーマンス監査が含まれています。Lighthouseはリソースの潜在的な節約を計算するためにGzipを使用します。
JavaScriptの圧縮とロード粒度
JavaScriptの圧縮の効果を完全に理解するには、ルートベースの分割、コード分割、バンドルなどのJavaScript最適化の他の側面も考慮する必要があります。
大量のJavaScriptコードを含む最新のウェブアプリケーションは、コードを効率的に読み込むために異なるコード分割とバンドルテクニックを使用することが多いです。アプリケーションは論理的な境界を使用してコードを分割します。シングルページアプリケーションのルートレベルの分割、またはインタラクションやビューポート可視性で段階的にJavaScriptを提供するなど、バンドラーがこれらの境界を認識するように設定できます。
バンドル用語
以下は、議論に関連するいくつかの主要な用語です。
- モジュール: モジュールは、堅牢な抽象化とカプセル化を提供するように設計された機能の離散的なチャンクです。詳細については、モジュールパターンを参照してください。
- バンドル: 最終的なソースファイルのバージョンを含む個別のモジュールのグループであり、バンドラーで読み込みと一口過程を既に経ています。
- バンドル分割: バンドラーが使用するプロセスであり、アプリケーションを複数のバンドルに分割して、各バンドルを独立して分離、公開、ダウンロード、またはキャッシュできます。
- チャンク: Webpack用語から採用されており、チャンクはバンドルとコード分割プロセスの最終的な出力です。Webpackは、エントリ設定、SplitChunksPlugin、または動的インポートに基づいてバンドルをチャンクに分割できます。
モジュールがソースファイルに含まれている場合、コードまたはバンドル分割後のビルドプロセスの最終的な出力はチャンクとして知られています。ソースファイルとチャンクの両方が相互に依存している可能性があることに注意してください。
JavaScriptの出力サイズは、JavaScriptバンドラーまたはコンパイラによる最適化後のチャンクまたは未処理サイズのサイズを指します。大規模なJSアプリケーションは、独立して読み込み可能なJavaScriptファイルのチャンクに分解できます。読み込み粒度は出力チャンク数を指します。チャンク数が多いほど、各チャンクのサイズは小さくなり、粒度は高くなります。
いくつかのチャンクは、より頻繁に読み込まれるか、より影響的なコードパスの一部であるため、他のチャンクより重要です(例えば、「チェックアウト」ウィジェットの読み込み)。どのチャンクが最も重要かを知るにはアプリケーション知識が必要ですが、「ベース」チャンクが常に不可欠であると仮定するのは安全です。
ページに必要なチャンクのすべてのバイトは、ユーザーデバイスによってダウンロードされ、解析/実行される必要があります。これはアプリケーションパフォーマンスに直接影響するコードです。チャンクは最終的にダウンロードされるコードであるため、チャンクを圧縮することはダウンロード速度を向上させることができます。
粒度トレードオフ
理想的な世界では、粒度とチャンク分割戦略は、以下に互いに対立する目標を達成することを目指すべきです。
- ダウンロード速度を改善する: 前のセクションで見られているように、ダウンロード速度は圧縮を使用することで改善できます。ただし、1つの大きなチャンクを圧縮するとより良い結果またはより小さなファイルサイズが得られます。同じコードを含む複数の小さなチャンクを圧縮するよりも。
compress(a + b) <= compress(a) + compress(b)
- キャッシュヒットとキャッシング効率を改善する: より小さいサイズのチャンクは、特にJSを段階的に読み込むアプリケーションにおいて、より良いキャッシング効率をもたらします。
-
変更がより少ないチャンクで、より小さいチャンクで分離されます。コード変更がある場合、影響を受けたチャンクのみを再ダウンロードする必要があり、このコードのサイズは小さい可能性があります。残りのチャンクはキャッシュにあるため、キャッシュヒット数が増加します。
-
より大きなチャンクの場合、多くのコードが影響を受けてコード変更後に再ダウンロードが必要になる可能性があります。
したがって、キャッシングメカニズムを利用するにはより小さいチャンクが望ましいです。
- 高速実行 - コードを高速に実行するには、以下を満たす必要があります。
- 必要な依存関係すべてが容易に利用可能です。これらはまとめてダウンロードされているか、キャッシュで利用可能です。これはすべての関連コードをより大きなチャンクとしてバンドルすべきことを意味します。
- ページ/ルートで必要なコードのみを実行する必要があります。これは追加コードがダウンロードまたは実行されていないことが必要です。ほとんどのページで必要な依存関係を含む「commons」チャンクは、すべてのページではなくほとんどのページで必要な依存関係を含む可能性があります。コード重複排除は、より小さな独立したチャンクが必要です。
- メインスレッドの長いタスクは長時間ブロックされる可能性があります。そのため、これらを小さなチャンクに分割する必要があります。
上記の目標の1つを最適化しようとする読み込み粒度は、他の目標から遠ざかる可能性があります。これが粒度トレードオフの問題です。
重複排除とキャッシングはブラウザパフォーマンスと圧縮に対立しています。
このトレードオフの結果として、今日ほとんどの本番アプリケーションで使用される最大チャンク数は約10です。大量のJavaScriptを含むアプリケーションのより良いキャッシングと重複排除をサポートするには、この限度を増やす必要があります。
SplitChunksPluginと粒度の細かいチャンク分割
粒度トレードオフの潜在的な解決策は、以下の要件に対処します。
- パフォーマンスに影響せずに、より好いキャッシングと重複排除のために、より多くのチャンク(40~100)とより小さいチャンクサイズを許可します。
- IPC、I/O、多くのスクリプトタグの処理コストによる複数の小さなチャンクのパフォーマンスオーバーヘッドに対処します。
- 複数の小さなチャンクの場合の圧縮損失に対処します。
これらの要件に対処する潜在的な解決策はまだ進行中です。ただし、Webpack v4のSplitChunksPluginと粒度の細かいチャンク分割戦略は、読み込み粒度をある程度増やすのに役立ちます。
以前のバージョンのWebpackは、共通の依存関係または共有モジュールを単一のチャンクにバンドルするためにCommonsChunkPluginを使用していました。これにより、これらの共通モジュールを使用しないページのダウンロードと実行時間が不要に増加する可能性があります。そのようなページのより好い最適化を許可するために、Webpackはv4でSplitChunksPluginを導入しました。複数の分割チャンクは、デフォルトまたは設定に基づいて作成され、さまざまなルート間でコードが重複されるのを防ぎます。
Next.jsはSplitChunksPluginを採用し、粒度トレードオフに対処するWebpackチャンクを生成する次の粒度の細かいチャンク分割戦略を実装しました。
- 十分に大きなサードパーティモジュール(160 KBより大きい)は個別のチャンクに分割されます。
- フレームワーク依存関係(react、react-domなど)に対して個別のフレームワークチャンクが作成されます。
- 必要に応じて多くの共有チャンクが作成されます。(最大25)
- チャンクを生成する最小サイズは20 KBに変更されます。
1つの代わりに複数の共有チャンクを出力すると、異なるページで不要な(または重複された)コードのダウンロードまたは実行の量を最小化します。大規模なサードパーティライブラリの独立したチャンクを生成することで、それらは頻繁に変わる可能性が低いため、キャッシングを改善します。最小チャンクサイズ20 kBを使用すると、圧縮損失が合理的に低いことが確保されます。
粒度の細かいチャンク分割戦略は、いくつかのNext JSアプリケーションがサイトで使用されるJavaScriptの合計を削減するのに役立ちました。粒度の細かいチャンク分割戦略もGatsbyで実装され、同様の利点が観察されました。
結論
圧縮だけではすべてのJavaScriptパフォーマンスの問題を解決できませんが、ブラウザとバンドラーがバックグラウンドでどのように機能するかを理解すると、より優れた圧縮をサポートするより好いバンドル戦略を作成するのに役立ちます。読み込み粒度の問題は、エコシステム全体の異なるプラットフォーム間で対処する必要があります。粒度の細かいチャンク分割はその方向への1つのステップかもしれませんが、私たちはまだ遠くまで行く必要があります。
出典
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- patternsdev
- リポジトリ
- patternsdev/skills
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/patternsdev/skills / ライセンス: MIT
関連スキル
doubt-driven-development
重要な判断はすべて、本番環境への展開前に新しい視点から対抗的レビューを実施します。速度より正確性が重要な場合、不慣れなコードを扱う場合、本番環境・セキュリティに関わるロジック・取り消し不可の操作など影響度が高い場合、または後でバグを修正するよりも今検証する方が効率的な場合に活用してください。
apprun-skills
TypeScriptを使用したAppRunアプリケーションのMVU設計に関する総合的なガイダンスが得られます。コンポーネントパターン、イベントハンドリング、状態管理(非同期ジェネレータを含む)、パラメータと保護機能を備えたルーティング・ナビゲーション、vistestを使用したテストに対応しています。AppRunコンポーネントの設計・レビュー、ルートの配線、状態フローの管理、AppRunテストの作成時に活用してください。
desloppify
コードベースのヘルスチェックと技術負債の追跡ツールです。コード品質、技術負債、デッドコード、大規模ファイル、ゴッドクラス、重複関数、コードスメル、命名規則の問題、インポートサイクル、結合度の問題についてユーザーが質問した場合に使用してください。また、ヘルススコアの確認、次の改善項目の提案、クリーンアップ計画の作成をリクエストされた際にも対応します。29言語に対応しています。
debugging-and-error-recovery
テストが失敗したり、ビルドが壊れたり、動作が期待と異なったり、予期しないエラーが発生したりした場合に、体系的な根本原因デバッグをガイドします。推測ではなく、根本原因を見つけて修正するための体系的なアプローチが必要な場合に使用してください。
test-driven-development
テスト駆動開発により実装を進めます。ロジックの実装、バグの修正、動作の変更など、あらゆる場面で活用できます。コードが正常に動作することを証明する必要がある場合、バグ報告を受けた場合、既存機能を修正する予定がある場合に使用してください。
incremental-implementation
変更を段階的に実施します。複数のファイルに影響する機能や変更を実装する場合に使用してください。大量のコードを一度に書こうとしている場合や、タスクが一度では完結できないほど大きい場合に活用します。