目標
moduleのimportを使用したjavascriptを、Babelとrollup.jsを利用して、es3相当にトランスパイルします。
前提とする環境
本記事で前提とする環境は以下の通りです。
バージョンが異なる場合、この記事の内容は適用できない場合があります。
記事を読む前にバージョンをご確認ください。
▼package.json
{
"devDependencies": {
"@babel/cli": "^7.22.5",
"@babel/core": "^7.22.5",
"@babel/plugin-transform-member-expression-literals": "^7.22.5",
"@babel/plugin-transform-property-literals": "^7.22.5",
"@babel/plugin-transform-property-mutators": "^7.22.5",
"@babel/plugin-transform-reserved-words": "^7.22.5",
"@babel/preset-env": "^7.22.5",
"@rollup/plugin-babel": "^6.0.3",
"glob": "^10.3.1",
"rollup": "^3.26.0"
}
}
なぜそんな古い規格を?
es3はブラウザ上からはすっかり消滅しましたが、アプリケーションに組み込まれた独自のjavascriptエンジンではまだ存在します。
私の場合、Adobe CCアプリのバッチ処理のためjsを使用しています。このjsエンジンが非常に古いため、es3相当のコードしか実行できません。
importを利用できれば、共通処理をくくり出せるため、バッチの生産性が高くなります。
どうにかしてimportを使用できる状況でコードを書き、Adobe CC上で実行できるようにトランスパイルします。
なぜrollup.js?
以前は同様の目的のため、モジュールバンドラーにwebpackを利用していました。
webpackは高機能な反面、バンドル先のファイルに独自の関数を追加します。これはwebpack自身の機能を実現するためです。
この独自の追加部分がES5を想定して作成されているため、バンドル元ファイルによってはES3環境での動作を妨げます。
そこでモジュールバンドラーにrollup.jsを利用することにしました。
こちらはjsファイルのバンドルに特化したモジュールバンドラーです。rollup.jsのプラグインを追加しない状態では、独自の関数をバンドル先に埋め込むことがありません。
rollup.jsの概要と利点については、こちらの記事でより詳しく解説されています。
インストール
上記のpackage.jsonに指定されているモジュールをインストールしてください。
すべてnpmからインストールが可能です。
babelの設定
babelの設定は以下の通りです。
"@babel/preset-env", { "loose" : true }
でLoose modeを有効にすると、Object.defineProperties
を使用しないようにトランスパイルが行われます。また{ "modules": false }
を指定することで、importしたモジュールが単一のファイルにまとめられます。
babelの設定についてはこちらの記事を参考とさせていただきました。ありがとうございます。
▼.babelrc
{
"presets": [
[
"@babel/preset-env",
{
"loose": true,
"modules": false
}
]
],
"plugins": [
"@babel/transform-member-expression-literals",
"@babel/transform-property-literals",
"@babel/plugin-transform-property-mutators",
"@babel/plugin-transform-reserved-words"
]
}
プラグインはそれぞれ対応した構文のトランスパイルを行います。
その他のes2015以降の機能を利用したい場合は、対応するbabel-pluginを追加してください。
例として、Object.assignを使用したい場合は@babel/plugin-transform-object-assignを追加します。
rollup.jsの実行
次にrollup.jsを利用してimportしたファイルをバンドルします。
今回はrollup.jsをCLIではなくAPIから利用しています。
これはrollupのinputファイルをnode-globを利用して複数指定するためです。
▼bundle.js
const rollup = require("rollup");
const babel = require("@rollup/plugin-babel");
const glob = require("glob");
const path = require("path");
const srcDir = "./src";
const distDir = "./bin";
// ./src以下のjsファイルのリストを取得する。ただし_から始まるファイルとmodulesディレクトリは除外する。
const entries = glob.sync("**/*.js", {
ignore: ["modules/**/*.js", "**/_*.js"],
cwd: srcDir
});
//リストアップしたjsファイルをバンドルする。
for (let entry of entries) {
const inputOptions = {
input: path.resolve(srcDir, entry),
plugins: [babel({ babelHelpers: "bundled" })],
};
const outputOptions = {
format: "cjs",
file: path.resolve(distDir, entry)
};
build(inputOptions, outputOptions);
}
async function build(inputOptions, outputOptions) {
const bundle = await rollup.rollup(inputOptions);
await bundle.write(outputOptions);
}
rollup.jsの複数input指定を行うプラグインとしてはrollup-plugin-multi-inputなどがありますが、このプラグインでは出力ファイルに共通のimportがある場合、その部分をチャンクとしてくくり出してしまいます。
AdobeCCのバッチでは動的なimportが行えないため、node.jsからrollup.jsを利用しています。
▼package.json
"scripts": {
"bundle": "node bundle.js"
}
最後にbundle
コマンドを実行すればbin
ディレクトリにjsファイルが出力されます。