今時のwebpackの構成

webpack4がリリースされていて、ちょっと調べて行く中で、webpack.configの構成方法を工夫した方がいいんだと言うことを知りました。
公式でも解説されている事なのですが、webpack.configを以下のように構成するのが、今時なんだそうです。

* 共通のwebpack.config = webpack.common.js
* 開発用のwebpack.config = webpack.dev.js
* リリース用のwebpack.config = webpack.prod.js

この方が、シンプルに考えられるよねってことです。

# webpack-mergeのインストール
この構成で、webpack.configを構成するには、webpack-mergeが必要になります。
開発用とリリース用のwebpack.configに、共通のwebpack.configを取り込むために、webpack-mergeを使います。

> npm install webpack-merge --save-dev

# 共通のwebpack.configを作成
開発用とリリース用で共通となる部分のwebpack.configを、webpack.common.jsとして作成します。

```javascript:webpack.common.js
const path = require('path');
const nodeExternals = require('webpack-node-externals');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const glob = require('glob');

module.exports = {
    entry: {
        server: './src/server/main.ts',
        assets: glob.sync('./src/server/assets/**/*')
    },
    target: 'node',
    node: {
        __dirname: false,
        __filename: false
    },
    externals: [
        nodeExternals()
    ], 
    module: {
        rules: [
            {
                test: /\.ts$/,
                use: [
                    // 下から順に処理される
                    {
                        loader: 'ts-loader',
                        options: {
                            configFile: 'src/server/tsconfig.server.json'
                        }
                    },
                    {
                        loader: 'tslint-loader',
                        options: {
                            typeCheck: true,
                            // tslint時に自動的に修正しない
                            fix: false,
                            // warningをエラーにすることでその後のビルドを止める
                            emitErrors: true
                        },
                    },
                ],
                exclude: /(node_modules|client)/
            },
            {
                test: /\.txt$/,
                use: {
                    loader: 'file-loader'
                },
                exclude: /(node_modules|client)/
            }
        ]
    },
    resolve: {
        extensions: [ '.ts', '.txt' ]
    },
    plugins: [
        new BundleAnalyzerPlugin({
                openAnalyzer: false,
                generateStatsFile: true,
                analyzerMode: 'static',
                reportFilename: '../../report.html',
                statsFilename: '../../stats.json'
            })
    ],
    output: {
        filename: '[name].js',
        path: path.resolve(__dirname, 'dist/server'),
        publicPath: path.resolve(__dirname, 'dist/server')
    }
};
```

# 開発用のwebpack.configを作成
開発用として必要になる構成、例えばmodeをdevelopmentにするとか、devtoolでソースマップを作成するとかを指定します。
共通として作成したwebpack.common.jsを取り込む必要があるので、webpack-mergeを使います。

```javascript:webpack.dev.js
const merge = require('webpack-merge');
const common = require('./webpack.common');

module.exports = merge(common, {
    mode: 'development',
    devtool: 'source-map'
})
```

# リリース用のwebpack.configを作成
今度はリリース用として必要になる構成、例えばmodeをproductionにするとかを指定します。
こっちでも、共通として作成したwebpack.common.jsを取り込む必要があるので、webpack-mergeを使います。

```javascript:webpack.prod.js
const merge = require('webpack-merge');
const common = require('./webpack.common');
const TerserPlugin = require('terser-webpack-plugin');

module.exports = merge(common, {
    mode: 'production',
    optimization: {
        minimizer: [
            new TerserPlugin({
                terserOptions: {
                    keep_classnames: true,
                    drop_console: true
                }
            })
        ]
    }
})
```

# 使い分け
以下のビルドするときのパラメータを変えると使い分けるとできます。

* 開発するとき･･･webpack --config webpack.dev.js
* リリースするとき･･･webpack --config webpack.prod.js

ただ、これだとPCで開発しているとき、Herokuにリリースするときを考えると、めんどくさいので、gulpを使う事にしました。
gulpfile.jsを以下のようにすると、NODE_ENVを見て、構成を変えることができます。

```javascript:gulpfile.js
const gulp = require('gulp');
const webpack = require('webpack');
const webpackStream = require('webpack-stream');

const webpackConfigDev = require('./webpack.dev');
const webpackConfigProd = require('./webpack.prod');

// Node.jsのビルド(webpack)
gulp.task('build-server', () => {
    const webpackConfig = (process.env.NODE_ENV || 'development') === 'development' ? webpackConfigDev : webpackConfigProd;

    return webpackStream(webpackConfig, webpack)
            .pipe(gulp.dest('dist/server'));
});
```

すっきり！