最近作ったRollup.jsの設定詳細 (2019年7月版)


こんちには。
@otolabです。

[Rollup.js](https://rollupjs.org/)使ってますか？

一言で言うとES6 Modules準拠のbundlerで、素直な挙動と出力の綺麗さが個人的に好きなんですが、用途としてはライブラリ作成時に強みのあると言われるものの、Webpack一強の感は否めない昨今です。

あまり情報がないと言われてしまったので、ちょっと情報を出していこうと思います。

オプション設定の詳細などは[公式の情報](https://rollupjs.org/guide/en/#big-list-of-options)にあたっていただくとして、今回は実際の利用例での設定サンプルを解説する形を採っています。



code
----------------------

作成したコードを一部省略したもの。このコードを解説していきます。

少々長いですが、ほぼそのまま掲載します。

```js:rolleup.config.js
import babel          from 'rollup-plugin-babel'
import {terser}       from 'rollup-plugin-terser'
import commonjs       from 'rollup-plugin-commonjs'
import nodeResolve    from 'rollup-plugin-node-resolve'
import nodeBuiltins   from 'rollup-plugin-node-builtins'
import nodeGlobals    from 'rollup-plugin-node-globals'
import {sizeSnapshot} from "rollup-plugin-size-snapshot"
import analyze        from 'rollup-plugin-analyzer'
import visualizer     from 'rollup-plugin-visualizer'
import replace        from 'rollup-plugin-replace'
import importAlias    from 'rollup-plugin-import-alias'
import vue            from 'rollup-plugin-vue'

import fs from 'fs'

const settings = ({name, format}) => {
  return {

    input: `src/index.${name}.js`,

    output: [
      {
        file: `dest/build.${name}.js`,
        format,
        name: `__${name}`,
        sourcemap: true,
      }
    ],

    plugins: [
      vue({
        include: ['**/*.vue', '/**/*.vue']
      }),

      commonjs({
        extensions: [ '.js', '.vue' ],
      }),

      nodeGlobals({
        buffer: false // falseにできると容量を削れる
      }),

      nodeBuiltins(),

      nodeResolve(),

      importAlias({
        Paths: {
          "lodash-custom": `${__dirname}/src/verdors/lodash.custom.js`, // esm版使おうという話はありつつも
          "libs": `${__dirname}/src/libs`,
        },
        Extensions: ['js', 'vue']
      }),

      replace({
        'process.env.NODE_ENV': JSON.stringify('production'),
      }),

      babel({
        exclude: 'node_modules/**',
        runtimeHelpers: true,
        babelrc: false,
        presets: [
          [
            '@babel/env',
            {
              modules: false,
              "targets": {
                "ie": 11,
              }
            }
          ]
        ],
        "plugins": [
          // 必要があればいろいろ
        ]
      }),

      analyze({
        writeTo: (analysisString) => fs.writeFileSync(`dest/analysis.${name}.txt`, analysisString)
      }),

      sizeSnapshot(),

      visualizer({
        filename: `dest/stats.${name}.html`
      }),

      terser()
    ],
  }
}


export default [
  settings({name: 'core', format: 'iife'}),
  settings({name: 'plugin', format: 'cjs'}),
]
```



rollup.config.js
-----------------

rollupの設定を行うファイルで、jsファイルになっています。export defaultしたオブジェクトが実行時の設定になる仕組み。

（ちょっと特殊な例ですが）複数の設定を配列で返すことができるので、エントリファイルごとに設定を組んで一度に処理することができます。共通の設定部分を切り出して、プログラムしつつ設定を書くことが出来て便利。

JavaScript APIもあるので、複雑なことをやりたい場合はそちらを。


input / output
-----------------

### input

entryとなるファイル名を書いておくだけです。

複数のエントリ指定からの共通部分のchunk切り出しなどもできますが、あまり使ったことがないので割愛します。

### output

出力フォーマット別などで、複数の出力先を指定することが出来ます。

フォーマットは`esm`, `cjs`, `iife`がよく使うところで、「ライブラリ作成に強い」のはこの辺りに起因します。

なお、iifeは`name`が必須で、この名前のグローバル変数にentryファイルのexport defaultが代入されます。


plugins
------------------------

[プラグインの一覧](https://github.com/rollup/awesome)としてまとまっているので、基本的にはここから探します。


### [babel](https://github.com/rollup/rollup-plugin-babel)

ご存知babelです。

個人的には`.babelrc`を使わず設定ファイル内に閉じるのが好きですが、その辺は調整できます。

イマドキはbabel/envを使うのが推奨されているので、サポート対象に合わせて調整しましょう。


### [commonjs](https://github.com/rollup/rollup-plugin-commonjs)

cjs(commonjs)形式のモジュールをimport可能にし、またその中で`require()`を使えるようにします。小さな変換用の仮ファイルを追加することで扱えるように変換しているようです。

オプションについてですが、`.vue`を使いたいときはextensionsに`.vue`を含めましょう。extensionsに含まれない拡張子のファイルにはcommonjs => ES6化の処理が掛かりません。

### [node-resolve](https://github.com/rollup/rollup-plugin-node-resolve), [node-builtins](https://github.com/calvinmetcalf/rollup-plugin-node-builtins), [node-globals](https://github.com/calvinmetcalf/rollup-plugin-node-globals)

resolveが`node_modules`の検索を、builtinsがNode特有の機能のpolyfillを、globalsが`process`などのグローバル変数を再現します。

基本的にcommonjsを含めてたこの4つはセットで使うことが多いと思います。

それぞれオプションを意識することは少ないですが、ファイルサイズにシビアな場合には、globalsの`buffer: false`などを検討する価値があるかもしれません。


### [terser](https://github.com/TrySound/rollup-plugin-terser)

minifyします。

uglifyよりES6に対応しているterserを使うほうが便利じゃないかと思います。機能はほぼほぼ同じ。

普通の用途だと特にオプションを使うことはない気がしますが、細かく設定もできるようです。


### [visualizer](https://github.com/btd/rollup-plugin-visualizer), [size-snapshot](https://github.com/TrySound/rollup-plugin-size-snapshot), [analyze](https://github.com/doesdev/rollup-plugin-analyzer)

ファイルサイズや依存関係をうまく表現してくれるプラグイン。

visualizerは特に、グラフィカルな表示をするhtmlを出してくれるのでおすすめです。browserifyのdiscというツールを使っていたのですが、それと同じ表現をしてくれるのがなかなかにくい。表現方法は選択できるようです。

sizeSnapshotはサイズ計算特化で、minifyした場合やgzした場合のサイズなどをシンプルに表示してくれるので便利。

analyzeはファイルの依存関係などをファイルに書き出してくれます。自分で処理したい場合向け？

いずれも書き出し先指定などを持っているので、環境に合わせて設定しましょう。


### [vue](https://github.com/vuejs/rollup-plugin-vue)

`.vue`でお馴染みのVue.jsのSFC（単一ファイルコンポーネント）をimport可能にします。

内部ではvueifyやwebpackのvue-loaderなどと同じ(たぶん)`vue-template-compiler`が使われているので使用感も同じです。

vueのモジュールとバージョン合わせが必要になるので（最近のは違う？）その辺りは注意です。


### [replace](https://github.com/rollup/rollup-plugin-replace)

最終的に出力する内容にたいしてreplaceをかけてくれます。原始的ですが強い。

おもな用途としては`process.env.NODE_ENV`の置換です。node-globalsで対応してくれよと思わなくもないんですが、node-globalsもcore-jsのprocess実装に依存している（？）らしく、そのへんは現状対応してくれていないみたいです。


### [import-alias](https://github.com/Hedzer/rollup-plugin-import-alias)

aliasを設定します。`import a from 'libs/a'`や`import _ from 'lodash-custom'`などの名前でポロッとファイルを置いたケースなどで使います。

変換先は`${__dirname}/path/file`で統一したほうが良いのかな？というのが最近得た知見です。commonjsと併用したとき、どうも多重にバンドルされるケースがあるようなのです。（この辺は要調査）


まとめ？
--------------

rollup.jsはシンプルなバンドルツールです。ほとんど全ての機能はプラグインとして提供されており、要・不要にあわせて自分で組み合わせていくスタイルになっています。

というわけで、実例のコードと、よく使うプラグインの解説をしてみました。

出力もきれいなのでちょっと実験してみると面白いですよ。