sprocketsを使っているアセットは半ば自動的にgzip圧縮版ファイルが用意されるのでそれをnginxのgzip_staticなどでサーブすればいいわけですが、JSのビルドをwebpck化したときにそういえばgzipされたファイルを用意しなくなったなと。それでもまあ、nginxが圧縮はしてくれますが、nginx自身が行うon-the-flyよりも事前に時間をかけて圧縮するほうが圧縮効率はいいので、やらない手はありません。
というわけでcompression-webpack-pluginです。これはデフォルトだとgzip圧縮しますが、圧縮ルーチンをカスタマイズできるのでnode-zopfli *1を使うこともできます。こんな感じに:
const CompressionPlugin = require("compression-webpack-plugin"); const zopfli = require('node-zopfli'); // ... webpack.plugins.push( // ... new CompressionPlugin({ test: /\.js$/, algorithm: (content, options, fn) => { zopfli.gzip(content, options, fn); }, }), // ... );
これを自動でやってくれる zopfli-webpack-plugin というのもありますが、compression-webpack-pluginとメンテナが同じなわりにあまりメンテされてない様子なのでcwpにしました。
ちなみに元サイズ909kbのJSファイルは次のようになりました:
- nginx on-the-fly: 331kb
- zlib: 281kb
- zopfli: 271kb
zopfliはわりと効果ありますね。なお node-zopfli
は環境によってはインストールが難しいため、 WebAssemblyをNodeJS Native Addonの配布形式として使う - Islands in the byte stream で紹介したwasm版の @gfx/zopfli
を使うほうが運用は楽かもしれません。
gzipよりも更に高い圧縮率をほこるbrotliもやりたいですが、nginxの設定をしないといけないのでまた後ほど。
cf. Brotli を用いた静的コンテンツ配信最適化と Accept-Encoding: br について | blog.jxck.io
*1:zopfliはzlibよりも高い圧縮率をほこるgzip実装です。