compression-webpack-plugin + zopfli でgzip圧縮ファイルを用意する

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実装です。