Babel 7 を試す
2018/8/27 に Babel 7 がリリースされたので既存プロジェクトに導入してみたので変更や問題点などをまとめる。参考資料とサンプル プロジェクトは以下。
- Upgrade to Babel 7 - Babel
- 次のリリースであるBabel7の主な変更点まとめ - 技術探し
- サンプル プロジェクト akabekobeko/examples-electron
Scoped Packages
Babel 公式の npm が Scoped Packages に変更された。scope は @babel
。babel-XXXX
は @babel/XXXX
という命名へ移行された。私のよく利用するものだと以下のようになる。
{
"devDependencies": {
"@babel/core": "^7.0.0",
"@babel/preset-env": "^7.0.0",
"@babel/preset-react": "^7.0.0",
"@babel/register": "^7.0.0"
}
}
第三者の Babel preset/plugin について babel-XXXX
命名を維持させながら、公式 npm を明確に区別できるようになった。webpack など npm で第三者の拡張を許可しているものに、この方法が広まってほしい。
babel.config.js
これまで Babel に関する設定はプロジェクトの package.json
に babel
プロパティーで記述していた。しかしこんな議論があったのと、Babel の設定ファイルとして JavaScript サポートが追加されたので移行することにした。
ファイル名は babel.config.js
。機能は Config Files で解説されている。移行後の内容は以下。
module.exports = (api) => {
const presetEnv = [
'@babel/preset-env',
{
targets: {
electron: '2.0'
}
}
]
return {
presets: api.env('development') ? [
presetEnv,
'@babel/preset-react',
'power-assert'
] : [
presetEnv,
'@babel/preset-react'
]
}
}
新形式は JavaScript というか Node モジュールとして定義する。このファイル自体は Babel の対象にならないようなので export default
ではなく module.exports
としている。アロー関数は現時点の Node LTS である v8.x 系なら対応しているので採用。
モジュールとする関数には api
という引数が渡される。これは命名そのままで Babel を操作したり環境情報を取得するためのもの。
api.env()
を呼ぶと現在の環境変数名が得られる。api.env('環境変数名')
とした場合は、それが指定されていれば true
を返す。これを利用して development
時だけ power-assert
を処理するようにした。
webpack の DefinePlugin が機能しない?
サンプル プロジェクトでは Babel と webpack を組み合わせている。そして Babel 7 対応は npm 更新と Babel 関連の設定変更だけでよい認識していた。実際、正常に動作する。
しかし babel.config.js
移行にともない webpack の DefinePlugin による development
分岐が本当に機能しているか不安だったので、ログをとってみた。
module.exports = (api) => {
console.log(api.env())
// ...後略
}
webpack の設定は以下。
new WebPack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
})
この状態で development
と production
両方のビルドを試してみたところ、標準出力には いずれも development
が表示されるではないか。webpack の GitHub issues を調べてみたら #2121 を見つけた。issue コメントにあった設定例をみると JSON.stringify
せず直に 'production'
を設定していたので、そのように修正してみたが結果は変わらず。
気づいていなかっただけで従来の package.json
における babel.env
分岐も失敗していた可能性がある。仮に power-assert が処理されても assert が置き換えられるぐらいだろうし、テスト コードは実装側から参照していないため害はなさそう。しかし意図しない動作になっているのは怖いので対策してみた。
方法は単純。webpack 処理で process.env.NODE_ENV
を設定するだけ。webpack 処理はすでに --mode
で development
と production
を分岐していたので
export default (env, argv) => {
const MAIN = !!(env && env.main)
const PROD = !!(argv.mode && argv.mode === 'production')
if (PROD) {
process.env.NODE_ENV = 'production'
}
}
とした。これをそれぞれの --mode
で実行したところ、babel.config.js
側の api.env()
が想定どおりの値を返すことが確認できた。
ちなみに webpack の設定ファイルを webpack.config.babel.js
にすると Babel 変換されるため babel.config.js
が呼ばれる。しかし webpack に --mode production
を指定してもこちらのログは当然ながら常に development
だった。
環境変数を npm-scripts から分岐するために cross-env を利用しているなら、webpack CLI より前に production
を設定できるかもしれない。ただし webpack を利用しているならビルド系の設定を webpack に集約するほうが管理しやすいのでそうしている。
mocha + power-assert
Babel の Scoped Packages 化にともない npm-scripts へ定義していた mocha + power-assert 実行コマンドも対応させる。まずは関連 npm を更新。
{
"devDependencies": {
"babel-preset-power-assert": "^3.0.0",
"mocha": "^5.2.0",
"power-assert": "^1.6.0"
}
}
続けてコマンド。
{
"scripts": {
"test": "mocha --require @babel/register src/js/**/*.test.js",
}
}
--require
へ指定するモジュールを babel-register
から @babel/register
に変えるだけで正常に動作した。
まとめ
いくつか問題はあったものの Babel 公式資料が充実していることもあり、さほど苦労せず移行できた。他のプロジェクトも順次 Babel 7 にする予定。
破壊的な変更があるため、このブログも含む古い記事を読むと混乱するかもしれない。ソフトウェアに関する調べ物をするときに資料の日時と言及対象のバージョンを確認するのは鉄則。とはいえ利用する機会のありそうなものならメジャー更新は定点観測するようにしておくと、知識更新の差分を小さくできてよい感じ。
今回は試さなかったけれど Babel 7 の目玉機能に TypeScript 対応がある。私としては ECMAScript で型定義が標準化されることを望んでいる。しかし vscode で優遇されていることもあり TypeScript に移行したくなってきた。あとで試すかも。