webpack(v1)とbabelでES6コードをさくっと書く
最低限のコストで最近よく聞くいい感じの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
以上となります
追記
webpackは基本的にすべての依存パッケージを同一ファイルにまとめてくれるので、このpublic/app.js
はどこへ持っていっても動く
webpackには画像などの重いファイルをoutput.publicPath
を元にパス化してファイル分割する機能があるため、assetを一緒にbundleした場合はその限りでない
jsだけ書いてたら気にしなくていいです
追記
で、実際ここからどう開発するの?という話
たとえばdom-loaded待ってfastclickでも入れたいとする
npm i --save domready fastclick
で、app.jsでimport
する
import 'babel-polyfill'; import domready from 'domready'; import fastclick from 'fastclick'; const sleep = (msec) => new Promise((resolve) => { setTimeout(resolve, msec); }); (async () => { console.log('start'); await sleep(2000); console.log('end'); })(); domready(() => { fastclick.attach(document.body); });
サーバー側でロードされることを期待しないのであれば、client側のライブラリもガンガン呼んでいい
余談: 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'] }, }, }, };