Help us understand the problem. What is going on with this article?

Babel + rollup.js で ES3環境向けトランスパイル

目標

moduleのimportを使用したjavascriptを、Babelrollup.jsを利用して、es3相当にトランスパイルします。

前提とする環境

本記事で前提とする環境は以下の通りです。
バージョンが異なる場合、この記事の内容は適用できない場合があります。
記事を読む前にバージョンをご確認ください。

▼package.json

{
  "devDependencies": {
    "@babel/cli": "^7.2.3",
    "@babel/core": "^7.2.2",
    "@babel/plugin-transform-member-expression-literals": "^7.2.0",
    "@babel/plugin-transform-property-literals": "^7.2.0",
    "@babel/plugin-transform-property-mutators": "^7.2.0",
    "@babel/plugin-transform-reserved-words": "^7.2.0",
    "@babel/preset-env": "^7.2.3",
    "glob": "^7.1.3",
    "rollup": "^0.68.2",
    "rollup-plugin-babel": "^4.1.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の概要と利点については、こちらの記事でより詳しく解説されています。

Rollupがちょうどいい感じ

インストール

上記のpackage.jsonに指定されているモジュールをインストールしてください。
すべてnpmからインストールが可能です。

babelの設定

babelの設定は以下の通りです。
"@babel/preset-env", { "loose" : true }でLoose modeを有効にすると、Object.definePropertiesを使用しないようにトランスパイルが行われます。また{ "modules": false }を指定することで、importしたモジュールが単一のファイルにまとめられます。

babelの設定についてはこちらの記事を参考とさせていただきました。ありがとうございます。

MSを偲び、ここにIE6対応SPAの作り方を記す

▼.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 path = require("path");
const rollup = require("rollup");
const babel = require("rollup-plugin-babel");
const glob = require("glob");

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()]
  };
  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ファイルが出力されます。

masato_makino
UI Designer / Front End Engineer
https://makino.design/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away