最低限のコストで最近よく聞くいい感じのjsを書きたい時の構成をずらーっと書いてみる
準備するもの
- node/npm (最近はrbenvクローンのnodenvがいい感じ、操作は同じ)
- webpack
- babel
.babelrc
.babelrcを設置しとくとbabelのデフォルト設定がこいつの中身で書き換わる
- Reactを使わないなら、presetの
reactはいらない export defaultされたパッケージをimportした時に.defaultで引くのを許せるなら、add-module-exportsはいらない(後述)
Reactいる
{
"presets": [
"es2015",
"stage-0",
"react"
],
"plugins": [
"add-module-exports"
]
}
いらない
{
"presets": [
"es2015",
"stage-0"
],
"plugins": [
"add-module-exports"
]
}
webpack.config.babel.js
webpack.config.jsという名前でファイルを設置しとくと、webpackコマンドが勝手に中身を読みに行ってくれる
さらにwebpack.config.babel.jsという名前にしておくと、babelなコードとして読んでくれる(webpackはinterpretをロードしているため。このbabelにも.babelrcの内容は適用される)
babel-polyfillを食わせておくと、Array.prototype.includesみたいなprototypeメソッドが拡張されるbabel-runtimeはトップオブジェクトだけ
- DefinePluginを使っておくとUglifyのCodeElimination(後述)でいい感じにデバッグコードを除去できる
...オペレータを使うと、条件で中身が切り替わるオブジェクトがいい感じに作れる.js以外にもビルドしたいassetがあるならmodule.loadersに追加する(後述)
import 'babel-polyfill'; import path from 'path'; import webpack from 'webpack'; const DEBUG = !process.argv.includes('--release'); const VERBOSE = process.argv.includes('--verbose'); export default { cache: DEBUG, debug: DEBUG, stats: { colors: true, reasons: DEBUG, hash: VERBOSE, version: VERBOSE, timings: true, chunks: VERBOSE, chunkModules: VERBOSE, cached: VERBOSE, cachedAssets: VERBOSE, }, entry: './src/app.js', output: { publicPath: '/', sourcePrefix: ' ', path: path.join(__dirname, 'public'), filename: 'app.js', }, target: 'web', devtool: DEBUG ? 'cheap-module-eval-source-map' : false, plugins: [ new webpack.optimize.OccurenceOrderPlugin(), new webpack.DefinePlugin({ 'process.env.NODE_ENV': `"${process.env.NODE_ENV || (DEBUG ? 'development' : 'production')}"` }), ...(DEBUG ? [] : [ new webpack.optimize.DedupePlugin(), new webpack.optimize.UglifyJsPlugin({ compress: { screw_ie8: true, warnings: VERBOSE } }), new webpack.optimize.AggressiveMergingPlugin(), ]), ], resolve: { extensions: ['', '.js', '.jsx'], }, module: { loaders: [ { test: /\.jsx?$/, include: [path.resolve(__dirname, 'src')], loader: 'babel' }, ], }, };
Reactがいらない場合、resolveとmodule.loadersを下記のように削る
{ resolve: { extensions: ['', '.js'], }, module: { loaders: [ { test: /\.js$/, include: [path.resolve(__dirname, 'src')], loader: 'babel' }, ], }, }
これでwebpackとbabelの設定はおしまい
もろもろインストールする
Reactがいらない場合、最後の一行はいらない
npm init npm i --save babel-polyfill npm i --save-dev webpack babel-core babel-loader babel-preset-es2015 babel-preset-stage-0 babel-plugin-add-module-exports npm i --save-dev babel-preset-react
ファイルを設置してビルドする
src/app.jsを設置する
わかりやすい例としてasync/awaitを使ったsleepコードでも書いてみる
import 'babel-polyfill'; const sleep = (msec) => new Promise((resolve) => { setTimeout(resolve, msec); }); (async () => { console.log('start'); await sleep(2000); console.log('end'); })();
ビルドする
$(npm bin)/webpack
publicフォルダの中にappとかができてると思うので、nodeする
node public/app.js
以上となります
余談: export default
add-module-exportsがある
// a.js export default 'hoge'; // b.js import a from './a.js'; console.log(a); // 'hoge'
ない
// a.js export default 'hoge'; // b.js import a from './a.js'; console.log(a); // { default: 'hoge' }
余談: CodeElimination
const debugInfo = 'hoge'; if (process.env.NODE_ENV === 'development') { console.log(debugInfo); }
こいつをwebpackに通すと、DefinePluginによってprocess.env.NODE_ENVが置換される
const debugInfo = 'hoge'; if ('production' === 'development') { console.log(debugInfo); }
'production' === 'development'は常にfalseなので、Uglifyによってこのconditionはまるごと削除される
const debugInfo = 'hoge';
余談: 例えばStylusをビルドする場合
こんな感じにする
{ module: { loaders: { { test: /\.styl$/, loaders: ['style?useable', `css?${DEBUG ? 'sourceMap' : 'minimize'}`, 'stylus'] }, }, }, };