【webpack】webpack設定を一からまとめてみる②

webpack学習の備忘録。
[【webpack】webpack設定を一からまとめてみる①](https://qiita.com/shin_moto/items/d75f1694bccf2bb4302d) の続き。
前記事では基本設定について書いたので、本記事ではもう少し実践的な使い方についてをまとめたいと思う。

・開発と本番で設定ファイルを分ける
・ファイルの最適化を行う

## 開発と本番で設定ファイルを分ける
開発用であれば、早くビルド出来るよう考慮したり、
本番用であれば、圧縮や出力ファイルの最適化を優先したりなどが必要になってきます。
なので、使用するプラグインなども違って来るので、自ずとファイルを分けておくと管理がしやすくなる。
![スクリーンショット 2020-11-14 14.00.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531606/1c38ef92-29ec-ccaf-9bb1-9fde62f464ec.png)
基本は共通設定ファイル、開発用、本番用とそれぞれ用意する形。

まず、共通設定ファイルを読み込む為のプラグインをインストールする。

```
npm add webpack-merge --dev
```
開発用ファイル

```webpack.dev.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpackMerge = require('webpack-merge'); // これでwebpackの設定をマージする
const commonConf = require('./webpack.common'); // 共通設定ファイルを読み込む
const outputFile = '[name]'; // 出力ファイルを変数化 
const assetFile = '[name]'; //　上に同じく

// マージの第一引数に読み込む共通設定ファイル
module.exports = () => webpackMerge.merge(commonConf({outputFile, assetFile}), {
  mode: 'development', 
  devtool: 'source-map',
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
      inject: 'body' 
    }),
  ],
});
```

デバッグがしやすいように`devtool: 'source-map'`でソースマップを出力するようにしておきます。

本番用ファイル

```webpack.prod.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpackMerge = require('webpack-merge'); 
const commonConf = require('./webpack.common'); 
const outputFile = '[name].[chunkhash]'; // 本番ではファイルにハッシュをつける
const assetFile = '[contenthash]'; // 上に同じく

module.exports = () => webpackMerge.merge(commonConf({outputFile, assetFile}), {
  mode: 'production', 
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
      inject: 'body'
    }),
  ],
});
```
共通設定ファイル

```webpack.common.js
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 

// 変数化した部分をパラメーターとして渡す
module.exports = ({outputFile, assetFile}) => ({
  entry: {app: './src/app.js', sub: './src/sub.js'}, 
  output: {
    path: path.resolve(__dirname, 'public'),
    filename: `${outputFile}.js` // 開発と本番で出力結果を変えたい部分を変数化
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: `${outputFile}.css`,
    }),
  ],

// 以下略

```

あとは[こちらの記事](https://qiita.com/shin_moto/items/0304a6c745b8b12e7f0f)のように` package.json` で` scriptsコマンド` を定義しておくと実行する時に楽になる。


## ファイルの最適化を行う
所謂、圧縮、軽量化を行う` minify` が出来るようにする。
cssのminifyには`optimize-css-assets-webpack-plugin`を新たに導入し、htmlは既に導入済みの`html-webpack-plugin`に設定を追加する事で実現が可能となっている。

javascriptのminifyには`TerserPlugin`と言うプラグインを用いるが、`productionモード`で実行する際にはデフォルトで使用されているプラグインとなっている。しかし、cssのminifyで新たに導入するプラグインを設定を書く為に`optimization`を設定すると、デフィルトの設定が無効化されてしまう為、別途設定を記述してやる必要があるそうな。

と言うわけで必要なプラグインをインストールする

```
npm add optimize-css-assets-webpack-plugin terser-webpack-plugin --dev
```
本番用ファイルにプラグインの読み込みと設定を追記する

```webpack.prod.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin'); // javascriptのminifyで使う
const OptimizeCssPlugin = require('optimize-css-assets-webpack-plugin'); // cssのminifyで使う
const webpackMerge = require('webpack-merge'); 
const commonConf = require('./webpack.common'); 
const outputFile = '[name].[chunkhash]';
const assetFile = '[contenthash]';

module.exports = () => webpackMerge.merge(commonConf({outputFile, assetFile}), {
  mode: 'production', 
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
      inject: 'body', 
      // htmlのminify設定を記述（デフォルトを上書き）
      minify: {
          collapseWhitespace: true, // 空白を取り除く
          removeComments: true, // コメントを取り除く
          removeRedundantAttributes: true, // 不要なAttributesを取り除く
          removeScriptTypeAttributes: true,
          removeStyleLinkTypeAttributes: true,
          useShortDoctype: true
      }
      // chunkFilename: '[name].[hash].css'
    }),
  ],
  // 各プラグイン読み込み
  optimization: {
    minimizer: [
      new TerserPlugin(), 
      new OptimizeCssPlugin() 
    ]
  }
});
```
これでビルド時に出力されるファイルがmknify出来るようになる。
前記事でも触れたが、開発モード、本番モードのデフォルト設定については以下公式を参照。
[Mode | webpack](https://webpack.js.org/configuration/mode/)