先に言っておくと、IE11は死ぬ。
何がしたいか
前提として、現代では ES Modules を除けばほとんどのモダンブラウザ(IE11を除く)でES2015は実装が終わりつつあり、IE11のような特定の環境を除けばほんのすこしの変換でES201xのコードが動く。うまくやれば、コンパイル時間もbabelの起動時間も短縮できる。何度も言うがIE11は死ぬ。
それと、先週リリースされたChrome55でasync/awaitがデフォルトで有効になった。これで何ができるかというと、babel で async/await をコンパイルすると、CPS変換で巨大なスイッチ文に変換してとにかくコードが読みづらいという問題があって、それをネイティブの機能を使うことで解決できる。(ソースマップもよくわからんところに吹っ飛んで使えなかった)
このアプローチを試みた際の問題
browserify/webpack(1) は requireでcommonjsを解決するのにASTのパース、変形を行うのだが、その入力としてES5水準のコードまでコンパイルされていることを想定しているため、ES2015のコードを食わせるとどちらも死んでしまう。
なのでそのあたりが考慮されてて、かつasync/awaitも通せるwebpack2を使った。本当は browserifyの方が好きだがパーサに介入できる気配がないので、substack がその必要に気づくまで待つ。
設定
{
"plugins": [
"syntax-async-functions",
"transform-decorators-legacy",
"transform-class-properties",
"transform-object-rest-spread",
"transform-react-jsx",
"transform-flow-strip-types"
]
}
{
"dependencies": {
"babel-core": "^6.21.0",
"babel-loader": "^6.2.10",
"babel-plugin-syntax-async-functions": "^6.13.0",
"babel-plugin-transform-class-properties": "^6.19.0",
"babel-plugin-transform-decorators-legacy": "^1.3.4",
"babel-plugin-transform-flow-strip-types": "^6.21.0",
"babel-plugin-transform-object-rest-spread": "^6.20.2",
"babel-plugin-transform-react-jsx": "^6.8.0",
"webpack": "2.1.0-beta.25",
"webpack-async-await": "^1.1.0"
}
}
const webpack = require('webpack');
const AsyncAwaitPlugin = require('webpack-async-await') ;
module.exports = {
entry: './src/main.js',
output: {
path: "public",
filename: 'bundle.js'
},
plugins: [
new AsyncAwaitPlugin({})
],
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader',
exclude: /node_modules/
}
]
}
};
想定してるディレクトリは
- .babelrc
- webpack.config.js
- package.json
- public
- bundle.js
- src
- main.js
で、$ webpack
と叩くとビルドされる。自分の趣味で flowtype とか jsx とか入ってるけどこの辺はいらない人はいらないだろう。
webpack-async-await は 中で使ってる acorn に async-awaitのパーサを足して落ちないようにしてる感じのコードだった。ワークアラウンドなのでそのうちいらなくなるとは思う。
結果
debuggerが変なswitchに巻き込まれずにちゃんと動いて最高。
Chromeだけじゃプロダクションで使えない? これは僕が趣味で遊ぶための環境であって仕事で使うには環境変数で多段でビルドオプションを切り替えるとか、そういう話になるんで各自勝手に頑張ってくれ。