この Codelab は、ネットワーク ペイロードを最小化して圧縮する Codelab の拡張版です。圧縮の基本コンセプトを理解していることを前提としています。このコードラボでは、gzip などの他の圧縮アルゴリズムと比較して、Brotli 圧縮(br)で圧縮率とアプリの全体的なサイズをさらに縮小する方法について説明します。

測定
最適化を追加する前に、アプリケーションの現在の状態を分析することをおすすめします。
- [Remix to Edit] をクリックして、プロジェクトを編集可能にします。
- サイトをプレビューするには、[アプリを表示] を押し、[全画面表示]
を押します。
前の ネットワーク ペイロードを縮小して圧縮する Codelab では、main.js のサイズを 225 KB から 61.6 KB に縮小しました。この Codelab では、Brotli 圧縮でこのバンドルサイズをさらに小さくする方法について説明します。
Brotli 圧縮
Brotli は、gzip よりも優れたテキスト圧縮結果が得られる新しい圧縮アルゴリズムです。CertSimple によると、Brotli のパフォーマンスは次のとおりです。
- JavaScript の
gzipより 14% 小さい - HTML の場合、
gzipより 21% 小さい - CSS の
gzipより 17% 小さい
Brotli を使用するには、サーバーが HTTPS をサポートしている必要があります。Brotli はすべての最新ブラウザでサポートされています。Brotli をサポートするブラウザは、Accept-Encoding ヘッダーに br を含みます。
Accept-Encoding: gzip, deflate, br
使用されている圧縮アルゴリズムは、Chrome デベロッパー ツールの [ネットワーク] タブの Content-Encoding フィールド(Command+Option+I または Ctrl+Alt+I)で確認できます。
Brotli を有効にする方法
Brotli でエンコードされたリソースを送信するようにウェブサーバーを設定する方法は、エンコード方法によって異なります。リクエスト時に Brotli でリソースを動的に圧縮するか(動的)、事前にエンコードしてユーザーがリクエストするまでに圧縮しておくか(静的)のいずれかを選択できます。
動的圧縮
動的圧縮では、ブラウザからリクエストされたアセットをその場で圧縮します。
メリット
- アセットの圧縮版を保存して更新する必要はありません。
- オンザフライ圧縮は、動的に生成されるウェブページに特に効果的です。
デメリット
- 圧縮率を高めるためにファイルをより高いレベルで圧縮すると、時間がかかります。ユーザーがサーバーから送信される前にアセットが圧縮されるのを待つため、パフォーマンスが低下する可能性があります。
Node と Express を使用した動的圧縮
server.js ファイルは、アプリケーションをホストする Node サーバーの設定を担当します。
const express = require('express');
const app = express();
app.use(express.static('public'));
const listener = app.listen(process.env.PORT, function() {
console.log(`Your app is listening on port ${listener.address().port}`);
});
このコードは、express をインポートし、express.static ミドルウェアを使用して public/directory 内のすべての静的 HTML、JS、CSS ファイルを読み込むだけです(これらのファイルはビルドごとに webpack によって作成されます)。
アセットがリクエストされるたびに brotli を使用して圧縮されるようにするには、shrink-ray モジュールを使用します。まず、package.json に devDependency として追加します。
"devDependencies": {
// ...
"shrink-ray": "^0.1.3"
},
そして、サーバー ファイル server.js にインポートします。
const express = require('express');
const shrinkRay = require('shrink-ray');
また、express.static がマウントされる前にミドルウェアとして追加します。
// ...
const app = express();
// Compress all requests
app.use(shrinkRay());
app.use(express.static('public'));
アプリを再読み込みして、[ネットワーク] パネルでバンドルサイズを確認します。
Content-Encoding ヘッダーの bz から brotli が適用されていることがわかります。main.bundle.js が 225 KB から 53.1 KB に削減されました。これは gzip(61.6 KB)と比較して約 14% 小さくなっています。
静的圧縮
静的圧縮の考え方は、アセットを事前に圧縮して保存することです。
メリット
- 圧縮レベルが高いことによるレイテンシは、もはや問題ではありません。ファイルを圧縮するためにオンザフライで処理する必要はありません。ファイルを直接取得できるようになったためです。
デメリット
- アセットはビルドごとに圧縮する必要があります。圧縮レベルが高い場合、ビルド時間が大幅に増加する可能性があります。
webpack を使用した Node と Express による静的圧縮
静的圧縮では、ファイルを事前に圧縮するため、webpack 設定を変更して、ビルドステップの一部としてアセットを圧縮できます。これには brotli-webpack-plugin を使用できます。
まず、package.json に devDependency として追加します。
"devDependencies": {
// ...
"brotli-webpack-plugin": "^1.1.0"
},
他の webpack プラグインと同様に、構成ファイル webpack.config.js でインポートします。
var path = require("path");
//...
var BrotliPlugin = require('brotli-webpack-plugin');
プラグイン配列内に含めます。
module.exports = {
// ...
plugins: [
// ...
new BrotliPlugin({
asset: '[file].br',
test: /\.(js)$/
})
]
},
プラグイン配列では、次の引数を使用します。
asset: ターゲット アセット名。[file]は、元のアセット ファイル名に置き換えられます。test: この RegExp に一致するすべてのアセット(つまり、.jsで終わる JavaScript アセット)が処理されます。
たとえば、main.js は main.js.br に名前変更されます。
アプリが再読み込みされて再ビルドされると、メインバンドルの圧縮バージョンが作成されるようになりました。Glitch Console を開いて、Node サーバーによって提供される最終的な public/ ディレクトリの中身を確認します。
- [ツール] ボタンをクリックします。
- [コンソール] ボタンをクリックします。
- コンソールで次のコマンドを実行して、
publicディレクトリに移動し、そのすべてのファイルを表示します。
cd public
ls -lh
バンドルの brotli 圧縮バージョン main.bundle.js.br もここに保存されるようになり、main.bundle.js よりもサイズが約 76% 小さくなりました(225 KB 対 53 KB)。
次に、元の JS バージョンがリクエストされたときに、これらの brotli 圧縮ファイルを送信するようにサーバーに指示します。これを行うには、express.static でファイルが提供される前に、server.js で新しいルートを定義します。
const express = require('express');
const app = express();
app.get('*.js', (req, res, next) => {
req.url = req.url + '.br';
res.set('Content-Encoding', 'br');
res.set('Content-Type', 'application/javascript; charset=UTF-8');
next();
});
app.use(express.static('public'));
app.get は、特定のエンドポイントに対する GET リクエストにサーバーがどのように応答するかをサーバーに伝えるために使用されます。コールバック関数を使用して、このリクエストの処理方法を定義します。このルートは次のように機能します。
- 最初の引数として
'*.js'を指定すると、JS ファイルを取得するために起動されるすべてのエンドポイントでこの関数が機能します。 - コールバック内で、
.brがリクエストの URL に付加され、Content-Encodingレスポンス ヘッダーがbrに設定されます。 - MIME タイプを指定するために、
Content-Typeヘッダーがapplication/javascript; charset=UTF-8に設定されます。 - 最後に、
next()は、シーケンスが次のコールバックに継続されるようにします。
一部のブラウザは brotli 圧縮をサポートしていない可能性があるため、Accept-Encoding リクエスト ヘッダーに br が含まれていることを確認して、brotli 圧縮ファイルを返す前に brotli がサポートされていることを確認します。
const express = require('express');
const app = express();
app.get('*.js', (req, res, next) => {
if (req.header('Accept-Encoding').includes('br')) {
req.url = req.url + '.br';
console.log(req.header('Accept-Encoding'));
res.set('Content-Encoding', 'br');
res.set('Content-Type', 'application/javascript; charset=UTF-8');
}
next();
});
app.use(express.static('public'));
アプリを再読み込みしたら、[ネットワーク] パネルをもう一度確認します。
完了しました。Brotli 圧縮を使用してアセットをさらに圧縮しました。
まとめ
このコードラボでは、brotli を使用してアプリの全体的なサイズをさらに縮小する方法について説明しました。brotli は、サポートされている場合、gzip よりも強力な圧縮アルゴリズムです。