webpack2で開発時にソースマップを出したり本番用に圧縮する

前回はReact.jsを使えるようにしたり、webpack-dev-serverを使ってみました。
React.jsでJSを書いていけるようになったのはいいですが、次に気になるのは本番用に書き出したり圧縮するにはどうすればいいか。
今回は開発時は圧縮せずソースマップを出したり、本番用のビルドでコードを圧縮するようなことをやってみたいと思います。
ソースマップを出してみる
ソースマップを出すのは簡単ですがいろいろと種類があるみたいです。
https://webpack.js.org/configuration/devtool/#devtool
環境に合わせて選ぶのがいいと思います。「inline-source-map」を使うと、コードの中にソースマップのData URIを追加するようです。
ソースマップを使うにはwebpack.config.jsにdevtoolを追加します。今回は「cheap-module-eval-source-map」を使ってみます。
webpack.config.js
const path = require('path'); module.exports = { entry: path.join(__dirname, 'src/app.js'), output: { path: path.join(__dirname, 'public'), filename: 'bundle.js' }, devServer: { contentBase: path.join(__dirname, 'public'), port: 3000, inline: true }, // ここを追記 devtool: 'cheap-module-eval-source-map', module: { rules: [ { test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ } ] } };
これで「npm start」コマンドを打って「localhost:3000」にアクセスし、chromeの開発者ツールでsourceタブを開くと「webpack://」というディレクトリに元ファイルが表示されます。
本番用と開発用で分ける
ソースマップは開発時は必要ですが、本番用のコードでは不要です。そこで開発時はソースマップを書き出すけど、本番用にビルドする時は書き出さない設定をやってみます。
process.argvを使ってコマンドライン引数を受け取って場合分けしてみます。
まずは、babel-polyfillをインストールします。babel-polyfillを入れるとincludesが使えるようになります。
npm i babel-polyfill -D
そしてコードに追記します。
webpack.config.js
require('babel-polyfill'); // ここ追記 const path = require('path'); // ここ追記 const DEBUG = !process.argv.includes('--env.production'); console.log(DEBUG); // ここは記事用に書いてるだけなので後で消す module.exports = { entry: path.join(__dirname, 'src/app.js'), output: { path: path.join(__dirname, 'public'), filename: 'bundle.js' }, devServer: { contentBase: path.join(__dirname, 'public'), port: 3000, inline: true }, devtool: DEBUG ? 'cheap-module-eval-source-map' : false, module: { rules: [ { test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ } ] } };
「var DEBUG = !process.argv.includes(‘–env.production’);」このように書くとpackege.jsonのscriptsの引数があるなしで、true/falseを返してくれるので、それで条件分岐できます。
試しに上記のコードでconsole.log(DEBUG);と書いていますが、–env.productionのあるなしでどう変わるか見てみます。
まずはpackegejsonを書き換えます。
packege.json
// 省略 "scripts": { "start": "webpack-dev-server", "prod": "webpack --env.production", "debug": "webpack" }, // 省略
これで、「npm start」の時は開発時、「npm run prod」は本番用になりました。
「npm start」するとターミナルに「true」と出てきて、「npm run prod」をすると「false」と出てきます。DEBUGという変数にしてるので、trueがデバッッグ用(開発時)、falseがそうでない時(本番用)という感じになります。
そして、先ほどのdevtoolのところを条件分岐に書き換えます。
webpack.config.js
// 省略 devtool: DEBUG ? 'cheap-module-eval-source-map' : false, // 省略
コードの圧縮
最後に、開発時と本番用を分けるのを利用して、開発時は非圧縮、本番用に圧縮して書き出すのをやってみます。
webpackにはプラグインがたくさん用意されていて、圧縮にはそのプラグインを使います。
この中から圧縮系のプラグインを使ってみます。
使ってみるのは3つ
- OccurrenceOrderPlugin
- UglifyJsPlugin
- AggressiveMergingPlugin
OccurrenceOrderPluginは以前は、OccurenceOrderPluginという名前でしたが変更されました。
プラグインを使うには以下のように記述するのですが、開発時と本番用で分けるのでちょっと違う書き方をします。
webpack.config.js
const webpack = require("webpack"); // 追加 // 省略 devServer: { contentBase: 'public', port: 3000, inline: true }, plugins: [ new webpack.optimize.OccurrenceOrderPlugin(), new webpack.optimize.AggressiveMergingPlugin() ], devtool: DEBUG ? 'cheap-module-eval-source-map' : false, // 省略
pushを使って、DEBUGじゃないときは圧縮のプラグインを追加するようにします。最終的なコードはこちら
webpack.config.js
require('babel-polyfill'); const path = require('path'); const webpack = require("webpack"); const DEBUG = !process.argv.includes('--env.production'); const plugins = [ new webpack.optimize.OccurrenceOrderPlugin() ]; if(!DEBUG){ plugins.push( new webpack.optimize.UglifyJsPlugin({ compress: { screw_ie8: false, warnings: false } }), new webpack.optimize.AggressiveMergingPlugin() ); } module.exports = { entry: path.join(__dirname, 'src/app.js'), output: { path: path.join(__dirname, 'public'), filename: 'bundle.js' }, devServer: { contentBase: path.join(__dirname, 'public'), port: 3000, inline: true }, plugins: plugins, devtool: DEBUG ? 'cheap-module-eval-source-map' : false, module: { rules: [ { test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ } ] } };
もう一度コマンドはこちら
開発時
npm start
本番用
npm run prod