Corredor

ウェブ、プログラミングの勉強メモ。

イマドキは Webpack じゃなくて Rollup だ!Terser とともに Rollup を使ってみる

Webpack なんかと同じビルド・バンドルツールの Rollup を使ってみる。

Rollup と Webpack の違い

同じバンドルツールである Webpack と Rollup の特徴を比べてみる。

Webpack は CommonJS で認識し、Rollup は ES Modules で扱う、というのが大きな違いか。ECMAScript のバージョンの違いだけでなく、コレが Tree-Shaking などに効いてくるので、バンドル効率に差が出てくるようだ。

Transpiler と Minifier との区別

Rollup や Webpack は Bundler であるが、Babel は Transpiler だし、後で使う Terser は Minifier だ。これらの区別をしっかり付けておこう。

  • Bundler
    • exportimport で複数に別れているファイルたちを1ファイルに束ねる
  • Transpiler
    • 新しい仕様のコードを古い仕様のコードに変換する
  • Minifier
    • コードを圧縮したり難読化したりする

素人考えだと「Bundler で束ねて → Transpiler で形式直して → Minifier で圧縮すればええんちゃうの?」と思ってしまうが、実際のところはそう簡単にもいかないようだ。

何を付け足し、何を取り除いていいか、という判断が複雑になり、Source Map を作るのが困難だったりするらしい。

その辺を解消するために、Webpack や Rollup はプラグインという形で、Babel や Terser を組み込めるようにしているようだ。

Rollup を試してみる

概念を整理したところで、Rollup を使ってみる。公式のガイドを参考に。

適当な作業用ディレクトリを作り、rollup コマンドがローカルで動くことを確認する。

$ npm init -y
$ npm install -D rollup
$ npx rollup

そしたら次のようなファイルを作ってみる。

  • src/index.mjs
import hoge from './hoge.mjs';
import fuga from './fuga.mjs';

new hoge().hello();
console.log(fuga);
  • src/hoge.mjs
export default class hoge {
  hello() {
    console.log('Hello');
  }
}
  • src/fuga.mjs
const fuga = {
  a: 'a',
  b: 'b'
};
export default fuga;

ES Modules の仕組みで実装しているので、拡張子は .mjs で、require ではなく import を使っている。

コレを Rollup で束ねてみる。

$ npx rollup src/index.mjs

src/index.mjs → stdout...
class hoge {
  hello() {
    console.log('Hello');
  }
}

const fuga = {
  a: 'a',
  b: 'b'
};

new hoge().hello();
console.log(fuga);

src/hoge.mjssrc/fuga.mjs の内容が混ぜ込まれて、1つになった。

続いて IIFE (Immediately Invoked Function Expression・即時実行関数式) の形式で出力してみる。

$ npx rollup src/index.mjs --format='iife'

src/index.mjs → stdout...
(function () {
  'use strict';

  class hoge {
    hello() {
      console.log('Hello');
    }
  }

  const fuga = {
    a: 'a',
    b: 'b'
  };

  new hoge().hello();
  console.log(fuga);

}());

コチラは即時関数の中にラップされていて、HTML に組み込みやすくなっている。

ファイルに出力する場合は --file オプションを使う。

$ npx rollup src/index.mjs --format='iife' --file='dist.js'

src/index.mjs → dist.js...
created dist.js in 55ms

こんな感じ。

Rollup の設定ファイルを作る

ここまでコマンドラインで Rollup を叩いていたが、オプションなどの内容を設定ファイルに書くこともできる。

  • rollup.config.js
    • module.exports で出力する Webpack と違い、ES Modules の export default を使うところが新しい
export default {
  input: 'src/index.mjs',
  output: {
    file: 'dist.js',
    format: 'iife'
  }
}

で、実行時に --config (-c) オプションを付ければ rollup.config.js が読み込まれる。

$ npx rollup --config

Terser を組み込む : rollup-plugin-terser

最後に、Rollup に Terser を組み込んで、コードを圧縮してみる。rollup-plugin-terser をインストールする。terser 本体はインストールしなくて良い。

$ npm install -D rollup-plugin-terser

設定ファイルはこうする。

  • rollup.config.js
import { terser } from 'rollup-plugin-terser';

export default {
  input: 'src/index.mjs',
  output: [
    // 非圧縮の通常版ファイル
    {
      file: 'dist.js',
      format: 'cjs'
    },
    // Terser による圧縮版ファイル
    {
      file: 'dist.min.js',
      format: 'cjs',
      plugins: [
        terser()
      ]
    }
  ]
}

コレでビルドしてみる。

# package.json に npm-scripts を書いてみた
$ npm run build

> practice-rollup@ build /Users/Neo/practice-rollup
> rollup --config

src/index.mjs → dist.js, dist.min.js...
created dist.js, dist.min.js in 207ms

設定ファイルに書いたとおり、2つのファイルが生成されたことが分かる。

それぞれ中身を見てみよう。

  • dist.js
    • Terser を組み込んでいない非圧縮版。Rollup 単体の成果
'use strict';

class hoge {
  hello() {
    console.log('Hello');
  }
}

const fuga = {
  a: 'a',
  b: 'b'
};

new hoge().hello();
console.log(fuga);
  • dist.min.js
    • Terser による圧縮が行われている。特に fuga 変数が消えていることが顕著であろう
"use strict";(new class{hello(){console.log("Hello")}}).hello(),console.log({a:"a",b:"b"});

こんな感じ。かなりシンプルに使えて良い感じ。