Babel 7 を試す

2018年9月11日 0 開発 , ,

2018/8/27 に Babel 7 がリリースされたので既存プロジェクトに導入してみたので変更や問題点などをまとめる。

参考資料とサンプル プロジェクトは以下。

Scoped Packages

Babel 公式の npm が Scoped Packages に変更された。scope は @babelbabel-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.jsonbabel プロパティーで記述していた。しかしこんな議論があったのと、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')
})

この状態で developmentproduction 両方のビルドを試してみたところ、標準出力には いずれも development が表示されるではないか。webpack の GitHub issues を調べてみたら #2121 を見つけた。issue コメントにあった設定例をみると JSON.stringify せず直に 'production' を設定していたので、そのように修正してみたが結果は変わらず。

気づいていなかっただけで従来の package.json における babel.env 分岐も失敗していた可能性がある。仮に power-assert が処理されても assert が置き換えられるぐらいだろうし、テスト コードは実装側から参照していないため害はなさそう。しかし意図しない動作になっているのは怖いので対策してみた。

方法は単純。webpack 処理で process.env.NODE_ENV を設定するだけ。webpack 処理はすでに --modedevelopmentproduction を分岐していたので

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 に移行したくなってきた。あとで試すかも。


REPLY

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です