◆ バンドルしたものを export できる
◆ 元ファイルごとにはっきりわかれず 一つのスコープにまとめられる

rollup 使ってみた

あるライブラリのコードを見ていて すごく規則的ではあるんだけど無駄が多くて こんなこと手動でするかなぁ?と思うのがありました
いかにも機械的って感じですが webpack みたいなバンドルされたものって感じでもなく普通に書いたようなコードです
それでも global$1 と global$2 とか人が書かないような部分も多く気になってました

その後色々あって rollup がもしかしたらこれかもと思うことがあって 試してみたら正解でした
webpack や parcel と違って rollup はライブラリ向いてるとか聞いたことはありましたがその意味はよくわかってませんでした
ですが バンドル結果をみればその理由は明らかでした

rollup の良いところ

webpack や parcel は元のファイルの import/export 処理だけを書き換えてそれぞれを関数にするなど異なるファイルははっきりと分割されています
さらに 外部にエクスポートはしないので バンドルしたコード中の関数を外部で使いたいなどの用途には向きません
プラグインとかでどうにかできるかもですが 普通にやるとできなそうなのでグローバルに配置するなどで対処してます
1 ファイルにまとめたいけど それを外部から import したいというのには向いていません

それに比べて rollup はバンドル時にそれぞれのファイルを別に分けず変数名を変えることで 1 つのスコープにうまくマージしています
さらにエントリポイントのファイル中の export を 指定したフォーマットで export できます
いかにもライブラリ向きって感じです

以前書いた npm ライブラリが import にライブラリ名を使っていて依存解決できないせいで ES Modules をそのまま使える機会があまりないという問題も npm ライブラリのみ rollup でバンドルしてしまえば ES Modules をメインに使っていけます

バンドル結果

バンドル部分は同じスコープにまとめられますが export のフォーマットは選ぶことができます

[index.js]
import x from "./x.js"

export default () => x() + 1

[x.js]
export default () => 100

[rollup.config.js]
const types = ["amd", "cjs", "esm", "system", "iife", "umd"]

module.exports = types.map(type => {
if (type === "iife" || type === "umd") {
return {
input: "index.js",
output: {
file: type + ".js",
format: type,
name: type + "_output",
},
}
} else {
return {
input: "index.js",
output: {
file: type + ".js",
format: type,
},
}
}
})

amd, cjs, esm, system, iife, umd のそれぞれを指定してバンドルしてみます
iife と umd は外側に配置するので名前も必要になります
名前は iife_output と umd_output にしてます

rollup では config ファイルを使う場合は明示的に -c を引数に設定しないといけません
名前が rollup.config.js だとパス指定は不要で -c だけでいいです

rollup -c

amd

define 関数は用意されないので このバンドルモジュールのロード前に自分で先にロードしておく必要があります

define(function () { 'use strict';

var x = () => 100;

var index = () => x() + 1;

return index;

});

cjs

Node.js で使える require/module.exports を使うフォーマットです

'use strict';

var x = () => 100;

var index = () => x() + 1;

module.exports = index;

esm

おなじみの ESModules です

var x = () => 100;

var index = () => x() + 1;

export default index;

system

聞いたことないですが system.js というものでロードするようのフォーマットらしいです

System.register([], function (exports) {
'use strict';
return {
execute: function () {

var x = () => 100;

var index = exports('default', () => x() + 1);

}
};
});

iife

即時関数実行を使って返り値を外側の変数に代入します
使う場所によって グローバルだったりローカルだったりです

var iife_output = (function () {
'use strict';

var x = () => 100;

var index = () => x() + 1;

return index;

}());

umd

環境に応じて適切に export してくれます

(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = global || self, global.umd_output = factory());
}(this, function () { 'use strict';

var x = () => 100;

var index = () => x() + 1;

return index;

}));

node_modules

rollup はデフォルトだとパッケージ名を node_modules 内から探してくれません
lit-element をバンドルしようとしたら

import { TemplateResult } from 'lit-html';

というコードが残っていました
また コンソールには未解決の dependencies があると警告が出ていました

(!) Unresolved dependencies
https://rollupjs.org/guide/en/#warning-treating-module-as-external-dependency
lit-html (imported by node_modules\lit-element\lit-element.js)
lit-html/lib/shady-render.js (imported by node_modules\lit-element\lit-element.js)
lit-html/lit-html.js (imported by node_modules\lit-element\lit-element.js)

node_modules のものをロードするには rollup-plugin-node-resolve というプラグインが必要です
こういう設定ファイルにするとバンドルできます

import resolve from "rollup-plugin-node-resolve"

module.exports = {
input: "node_modules/lit-element/lit-element.js",
output: {
file: "lit-element.js",
format: "esm",
},
plugins: [
resolve({
// pass custom options to the resolve plugin
customResolveOptions: {
moduleDirectory: "node_modules",
},
}),
],
}

出力された lit-element.js を使ってみます

[index.html]
<script type="module">
import { LitElement, html } from "./lit-element.js"

customElements.define("le-test", class extends LitElement {
render() {
return html`
<h1>lit-element is working</h1>
`
}
})
</script>

<le-test></le-test>

これを開くと h1 で lit-element is working というメッセージが表示されます

cjs

ここまでの例ではバンドル対象のファイルはすべて ES Modules でした
rollup は標準では ES Modules しか対応してません
あくまで JavaScript 標準の polyfill という立場だからみたいです
なので Node.js 用の cjs の require/module.exports を使ったファイルをバンドルしたいなら またプラグインが必要です

import commonjs from "rollup-plugin-commonjs"

module.exports = {
input: "index.js",
output: {
file: "index.bundle.js",
format: "cjs",
},
plugins: [commonjs()],
}