expexp.jp

CSS , JavaScript

【2019年版】webpack 4 個人的設定まとめ

webpackで開発を行ってきましたが、導入当初から仕様が変わったり、個人的な設定方法が固まってきたので一旦記事としてまとめます。

ちなみに以前の記事はこちらです。Babelをはじめ、CSS/SASSのバンドル、さらにファイルを分ける設定までを紹介しています(本記事でも同様の内容を紹介)。

今回はwebpackによる環境構築から、JS/CSSファイルの出力、さらにHTMLもwebpackから出力する方法を紹介します。環境はMac、node v10.15.1、npm 6.7.0、webpackのバージョンは4.29以上で進めます(近頃、開発中のwebpack 5の話題を見かける。4の記事を書くのもそろそろ終わりかな)。

目次

環境構築

mkdir myproject

作成したディレクトリへ移動します。

cd myproject

npmを初期化して、package.jsonを作成します。

npm init -y

出来たpackage.jsonは以下のようになります。

▽package.json

{
  "name": "myproject",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

メインエントリの記述は別ファイルに書くので消します。あとパッケージの公開予定もないのでprivateの記述を追加します。

{
  "name": "myproject",
  "version": "1.0.0",
  "description": "",
  "private": true,
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

webpack本体とコマンドライン入力用のwebpack-cliをインストールします。

▽コマンドライン

npm install --save-dev webpack webpack-cli

上の書き方は長いので、省略して書きましょう。

npm i -D webpack webpack-cli

以下は省略した内容の詳細です。

install => i
--save-dev => -D

webpackインストール後のpackage.jsonは以下のようになります。

▽package.json

{
  "name": "myproject",
  "version": "1.0.0",
  "description": "",
  "private": true,
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^4.29.0",
    "webpack-cli": "^3.2.1"
  }
}

コマンドラインでwebpackを実行するためのコマンドをscripts項目に設定します。

{
  "name": "myproject",
  "version": "1.0.0",
  "description": "",
  "private": true,
  "scripts": {
    "build": "webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^4.29.0",
    "webpack-cli": "^3.2.1"
  }
}

起点となるJavaScriptファイルをmyproject内に作成します。デフォルトの設置場所・ファイル名は/src/index.jsになります。

この状態でコマンドラインに以下のコマンドを入力してエラーが出なければwebpackの開発環境構築が完了です。

▽コマンドライン

npm run build

ビルドに成功すると/distディレクトリとmain.jsが作成されます。

ただし、このままでは設定が不十分なのでWARNING in configurationが出ます。設定方法は次の項目で紹介します。

ベーシックな設定

上記までの設定でも出来ないことはないですが、より複雑な設定が必要になってくるので、設定用のファイルを作成します。ファイル名はwebpack.config.jsです。

▽webpack.config.js

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
  }
};

上記の記述は環境構築時と同様の処理が行われます。outputのfilenameが出力されるJSのファイル名です。任意のものに変更しましょう。

modeの設定を追加します。開発用のdevelopmentと公開用のproductionがあります。

const path = require('path');

module.exports = {
  mode: 'production',
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
  }
};

開発用のdevelopmentは非圧縮の状態でビルドされます。公開用のproductionでは圧縮されてビルドされます。この圧縮の違いはバンドルするものが増えるにつれて顕著に現れます(後述しますがソースマップの生成も含めると容量がかなり増えます)。

ただ毎回webpack.config.jsのmodeを書き換えるのは面倒なので(そもそも忘れる)、package.json側にmodeの記述を追加して、書き換えの手間を省きます。

const path = require('path');

module.exports = ( env, argv ) => ({
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
  }
});

webpack.config.jsを上記のように書き換えます。この設定はのちのち活きてきます。package.jsonもscripts項目に追記します。

▽package.json

{
  "name": "myproject",
  "version": "1.0.0",
  "description": "",
  "private": true,
  "scripts": {
    "build": "webpack --mode=production",
    "build:dev": "webpack --mode=development"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^4.29.0",
    "webpack-cli": "^3.2.1"
  }
}

これでコマンドラインだけでmodeの切り替えが出来ます。

▽コマンドライン

npm run build

上記はproduction、下記はdevelopmentでビルドされます。

npm run build:dev

ファイルを監視する設定

ファイルの編集回数が増えれば、ビルドの回数も必然的に増えます。

Watchコマンド

webpackには標準でファイルを監視する仕組みが内臓されいます。ただデフォルトではオフになっているので、有効化する必要があります。

webpack.config.jsで設定する

const path = require('path');

module.exports = ( env, argv ) => ({
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
  },
  watch: true
});

package.jsonで設定する

{
  "name": "myproject",
  "version": "1.0.0",
  "description": "",
  "private": true,
  "scripts": {
    "build": "webpack --mode=production",
    "build:dev": "webpack --mode=development --watch"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^4.29.0",
    "webpack-cli": "^3.2.1"
  }
}

または、

{
  "name": "myproject",
  "version": "1.0.0",
  "description": "",
  "private": true,
  "scripts": {
    "build": "webpack --mode=production",
    "build:dev": "webpack --mode=development",
    "watch:dev": "webpack --mode=development --watch"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^4.29.0",
    "webpack-cli": "^3.2.1"
  }
}

DevServer

専用パッケージのwebpack-dev-serverを使ってファイルを監視することも出来ます。

▽コマンドライン

npm i -D webpack-dev-server

▽webpack.config.js

const path = require('path');

module.exports = ( env, argv ) => ({
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
  },
  devServer: {}
});

▽package.json

{
  "name": "myproject",
  "version": "1.0.0",
  "description": "",
  "private": true,
  "scripts": {
    "build": "webpack --mode=production",
    "build:dev": "webpack --mode=development",
    "start:dev": "webpack-dev-server --mode=development"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^4.29.0",
    "webpack-cli": "^3.2.1",
    "webpack-dev-server": "^3.1.14"
  }
}

devServerオプションを指定しない場合は、プロジェクトディレクトリがルートになります(今回の場合はmyproject)。任意のディレクトリをルートにしたい場合は以下のようになります。distディレクトリにwebpackがビルドするファイルをすべて更新する仕組みです。

const path = require('path');

module.exports = ( env, argv ) => ({
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
  },
  devServer: {
    contentBase: path.resolve(__dirname, 'dist'),
    watchContentBase: true,
  }
});

devServerで開くポートは指定することも出来ます。

const path = require('path');

module.exports = ( env, argv ) => ({
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
  },
  devServer: {
    contentBase: path.resolve(__dirname, 'dist'),
    watchContentBase: true,
    port: 3000,
  }
});

DevServerオプションは他にもあるので、色々試してください。openとか便利です。

JavaScriptをまとめる設定

まとめるのはwebpackのメイン機能で、単純にJavaScriptだけをまとめる設定であれば、私個人の最小構成は以下の通りです。

ただ、ECMAScriptで書くのでこの設定は使いませんが。

※ここから出力するファイル名をbundle.jsに変更しています。任意のものに変更してください。

▽package.json

{
  "name": "myproject",
  "version": "1.0.0",
  "description": "",
  "private": true,
  "scripts": {
    "build": "webpack --mode=production",
    "build:dev": "webpack --mode=development"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^4.29.0",
    "webpack-cli": "^3.2.1"
  }
}

▽webpack.config.js

const path = require('path');

module.exports = ( env, argv ) => ({
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  }
});

最近はmodeの設定をconfig.jsに書くことは少なくなりました。

JavaScriptをBabelでトランスパイルする設定

まだまだIEに苦しんでいるのでBabelは必須です。

Babel 6以前とBabel 7以降ではインストールするパッケージの指定が異なりますので注意してください。Babel 7以降は以下のようになります。

▽コマンドライン

npm i -D babel-loader @babel/core @babel/preset-env webpack

▽package.json

{
  "name": "myproject",
  "version": "1.0.0",
  "description": "",
  "private": true,
  "scripts": {
    "build": "webpack --mode=production",
    "build:dev": "webpack --mode=development"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.2.2",
    "@babel/preset-env": "^7.3.1",
    "babel-loader": "^8.0.5",
    "webpack": "^4.29.0",
    "webpack-cli": "^3.2.1"
  }
}

▽webpack.config.js

const path = require('path');

module.exports = ( env, argv ) => ({
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  },

  module: {
    rules: [
      {
        test: /\.js$/,
        use: [
          {
            loader: 'babel-loader',
            options: {
              presets: ['@babel/preset-env']
            }
          }
        ],
        exclude: /node_modules/,
      }
    ]
  }
});

excludeでnode_modulesをトランスパイルの対象から除外することを忘れないようにしましょう。またトランスパイルしてエラーが出てたり、追加したモジュールの挙動がおかしい場合は、競合している記述がないかチェックしましょう。モジュールのimport順を変更するだけで治ったりする場合があります。

CSSをまとめる設定

私はSASSを使うのでCSSのみの設定は使いませんが、一通り紹介します。

追加するパッケージはcss-loaderとstyle-loaderです。

▽コマンドライン

npm i -D css-loader style-loader

▽package.json

{
  "name": "myproject",
  "version": "1.0.0",
  "description": "",
  "private": true,
  "scripts": {
    "build": "webpack --mode=production",
    "build:dev": "webpack --mode=development"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.2.2",
    "@babel/preset-env": "^7.3.1",
    "babel-loader": "^8.0.5",
    "css-loader": "^2.1.0",
    "style-loader": "^0.23.1",
    "webpack": "^4.29.0",
    "webpack-cli": "^3.2.1"
  }
}

▽webpack.config.js

const path = require('path');

module.exports = ( env, argv ) => ({
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  },

  module: {
    rules: [

      // babel-loaderの設定
      {
        test: /\.js$/,
        use: [
          {
            loader: 'babel-loader',
            options: {
              presets: ['@babel/preset-env']
            }
          }
        ],
        exclude: /node_modules/,
      },

      // css-loaderの設定
      {
        test: /\.css$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              url: false
            }
          }
        ]
      }
    ]
  }
});

css-loaderのurl取り込み処理は、デフォルトでtrueになっているので、注意してください。

css-loaderだけでもイケるんじゃ?と思われがちですが、style-loaderがないとJSのみでのCSS反映が出来ません(詳しくは公式を見てね)。大人しくstyle-loaderもインストールしてください。

まとめたいCSSを取り込む記述はentryのJS、もしくはそれにバンドルされるJSに記述してください。

▽例:index.js

import './style.css';

SASSをまとめる設定

SASS(SCSS)をまとめる設定です。CSSとまとめる設定と似ています。

追加するパッケージはsass-loaderと、SASSをCSSに変換するためのnode-sassも必要になります。

▽コマンドライン

npm i -D sass-loader node-sass

▽package.json

{
  "name": "myproject",
  "version": "1.0.0",
  "description": "",
  "private": true,
  "scripts": {
    "build": "webpack --mode=production",
    "build:dev": "webpack --mode=development"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.2.2",
    "@babel/preset-env": "^7.3.1",
    "babel-loader": "^8.0.5",
    "css-loader": "^2.1.0",
    "node-sass": "^4.11.0",
    "sass-loader": "^7.1.0",
    "style-loader": "^0.23.1",
    "webpack": "^4.29.0",
    "webpack-cli": "^3.2.1"
  }
}

▽webpack.config.js

const path = require('path');

module.exports = ( env, argv ) => ({
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  },

  module: {
    rules: [

      // babel-loaderの設定
      {
        test: /\.js$/,
        use: [
          {
            loader: 'babel-loader',
            options: {
              presets: ['@babel/preset-env']
            }
          }
        ],
        exclude: /node_modules/,
      },

      // css/sass-loaderの設定
      {
        test: /\.(sa|sc|c)ss$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              url: false
            }
          },
          'sass-loader'
        ]
      }
    ]
  }
});

CSSの設定を元にSASS用へ書き換えています。rules内の各loaderの順序に気をつけましょう。style→css→sassの順です。SASS(SCSS)はもちろん、この設定でもCSSの取り込みは可能です。

JavaScriptとCSSファイルを分ける設定

今までは1つのJavaScriptにCSSまでまとめていましたが、ここからwebpackは使いたいけどJSファイルとCSSファイルを分けたい人用の設定です。

パッケージの変更点はJSにまとめる必要がないのでstyle-loaderを外します。代わりにCSSファイルを生成するmini-css-extract-plugin、CSSを圧縮するためのoptimize-css-assets-webpack-plugin、JSを圧縮するためのterser-webpack-pluginをインストールします。

▽コマンドライン

npm i -D mini-css-extract-plugin optimize-css-assets-webpack-plugin terser-webpack-plugin

▽package.json

{
  "name": "myproject",
  "version": "1.0.0",
  "description": "",
  "private": true,
  "scripts": {
    "build": "webpack --mode=production",
    "build:dev": "webpack --mode=development"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.2.2",
    "@babel/preset-env": "^7.3.1",
    "babel-loader": "^8.0.5",
    "css-loader": "^2.1.0",
    "mini-css-extract-plugin": "^0.5.0",
    "node-sass": "^4.11.0",
    "optimize-css-assets-webpack-plugin": "^5.0.1",
    "sass-loader": "^7.1.0",
    "terser-webpack-plugin": "^1.2.1",
    "webpack": "^4.29.0",
    "webpack-cli": "^3.2.1"
  }
}

やりたいことが増えればpackage.jsonが長くなる、これでも短い方です。

▽webpack.config.js

const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');

module.exports = ( env, argv ) => ({
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  },

  // 最適化オプションを上書き
  optimization: {
    minimizer: [
      new TerserPlugin({}),
      new OptimizeCssAssetsPlugin({})
    ]
  },

  module: {
    rules: [

      // babel-loaderの設定
      {
        test: /\.js$/,
        use: [
          {
            loader: 'babel-loader',
            options: {
              presets: ['@babel/preset-env']
            }
          }
        ],
        exclude: /node_modules/,
      },

      // css/sass-loaderの設定
      {
        test: /\.(sa|sc|c)ss$/,
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader',
            options: {
              url: false
            }
          },
          'sass-loader'
        ]
      }
    ]
  },

  plugins: [
    new MiniCssExtractPlugin({
      filename: 'style.css'
    }),
  ]
});

webpack.config.jsにJSからCSSを分離する処理を追加しています。

CSSはmini-css-extract-pluginから吐き出される関係で、optimizationの設定をしていないと圧縮されません。configの記述はオーバーライドのため、minimizerでCSSだけではなくJavaScriptの圧縮設定もやり直す必要があります(webpackには元から圧縮設定があるため)。

rulesではstyle-loaderの代わりにmini-css-extract-pluginをloaderとして組み込みます。

新たに追加されたpluginsでは、出力されるCSSの名前を指定します。指定がない場合はmain.css等になります。

HTML(Pug)を出力する設定

webpackでPugを扱う設定です。ここまでくると公開データが画像以外全てがまとまるので気持ちがいいです。Pugの詳細な説明は省きますが、変数が使えたりモジュール化したり出来て大変便利、Vue.jsでもReactでも使えます。

追加するパッケージはPugを使うためのpugとpug-loader、HTMLを生成するためのhtml-webpack-plugin、生成先のフォルダ内を掃除(削除)してくれるclean-webpack-pluginをインストールします。

▽コマンドライン

npm i -D pug pug-loader html-webpack-plugin clean-webpack-plugin

▽package.json

{
  "name": "myproject",
  "version": "1.0.0",
  "description": "",
  "private": true,
  "scripts": {
    "build": "webpack --mode=production",
    "build:dev": "webpack --mode=development"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.2.2",
    "@babel/preset-env": "^7.3.1",
    "babel-loader": "^8.0.5",
    "clean-webpack-plugin": "^1.0.1",
    "css-loader": "^2.1.0",
    "html-webpack-plugin": "^3.2.0",
    "mini-css-extract-plugin": "^0.5.0",
    "node-sass": "^4.11.0",
    "optimize-css-assets-webpack-plugin": "^5.0.1",
    "pug": "^2.0.3",
    "pug-loader": "^2.4.0",
    "sass-loader": "^7.1.0",
    "terser-webpack-plugin": "^1.2.1",
    "webpack": "^4.29.0",
    "webpack-cli": "^3.2.1"
  }
}

▽webpack.config.js

const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');

module.exports = ( env, argv ) => ({
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  },

  // 最適化オプションを上書き
  optimization: {
    minimizer: [
      new TerserPlugin({}),
      new OptimizeCssAssetsPlugin({})
    ]
  },

  module: {
    rules: [
      // pug-loaderの設定
      {
        test: /\.pug$/,
        use: ['pug-loader']
      },

      // babel-loaderの設定
      {
        test: /\.js$/,
        use: [
          {
            loader: 'babel-loader',
            options: {
              presets: ['@babel/preset-env']
            }
          }
        ],
        exclude: /node_modules/,
      },

      // css/sass-loaderの設定
      {
        test: /\.(sa|sc|c)ss$/,
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader',
            options: {
              url: false
            }
          },
          'sass-loader'
        ]
      }
    ]
  },

  plugins: [
    new CleanWebpackPlugin(
      ['dist'],
      {
        // 除外するファイルやディレクトリを指定
        exclude: ['img']
      }
    ),
    new MiniCssExtractPlugin({
      filename: 'style.css'
    }),
    new HtmlWebpackPlugin({
      template: './src/index.pug'
    })
  ]
});

rulesにpug-loaderの設定を追加します。

pluginsにclean-webpack-pluginとhtml-webpack-pluginの設定を追加します。clean-webpack-pluginは生成先ディレクトリを綺麗に掃除してくれるプラグインです。ハッシュ付きのファイルを作成するときに重宝します。

clean-webpack-pluginで掃除対象から除外したい場合はexcludeを忘れずに設定しましょう。お掃除ロボがせっかく作った画像を綺麗に掃除してくれちゃいます。

おまけ1:HTMLを圧縮しない

上記設定ではproductionはもちろん、developmentでビルドしてもHTMLは圧縮されます。圧縮したくない場合はpug-loaderのオプション(pretty)を設定すれば可能です。ただいちいち書き換えるのは面倒なのでmodeによって圧縮処理を切り替えます。

▽webpack.config.js

const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');

module.exports = ( env, argv ) => ({
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  },

  // 最適化オプションを上書き
  optimization: {
    minimizer: [
      new TerserPlugin({}),
      new OptimizeCssAssetsPlugin({})
    ]
  },

  module: {
    rules: [
      // pug-loaderの設定
      {
        test: /\.pug$/,
        use: [
          {
            loader: 'pug-loader',
            options: argv.mode !== 'production' ? {
              pretty: true
            } : {}
          }
        ]
      },〜中略〜
    ]
  },

  plugins: [
    new CleanWebpackPlugin(
      ['dist'],
      {
        // 除外するファイルやディレクトリを指定
        exclude: ['img']
      }
    ),
    new MiniCssExtractPlugin({
      filename: 'style.css'
    }),
    new HtmlWebpackPlugin({
      template: './src/index.pug'
    })
  ]
});

上記はよく使う分岐処理です。modeがproductionでなければHTMLを圧縮しない(pretty: true)、productionだった場合はHTMLを圧縮する(デフォルト設定)という処理です。他のloaderやオプションにも応用することが出来ます。

おまけ2:ソースマップの設定

ソースマップを出力する場合はDevtoolのオプションをオーバーライドします。

▽webpack.config.js

const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');

module.exports = ( env, argv ) => ({
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  },

  // 最適化オプションを上書き
  optimization: {
    minimizer: [
      new TerserPlugin({}),
      new OptimizeCssAssetsPlugin({})
    ]
  },

  devtool: 'inline-source-map',

  〜後略〜
});

少し前まで各loaderのオプションで設定していましたが、現在はdevtoolで設定します。

inline-source-mapではソースマップを各ファイル内に生成します。source-mapと設定すると.mapファイルを生成します。他にもありましたが使ったことがありません。便利なのがあったら教えてください。

私はこの設定でこと足りますが、さらに細かいソースマップもプラグインを追加することで出力可能なようです。

おまけ3:バンドルしたファイルにハッシュを付与

開発時やクライアントのキャッシュ問題を回避するのに重宝します。Pugと相性も良いです。

▽webpack.config.js

const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');

module.exports = ( env, argv ) => ({
  entry: './src/index.js',
  output: {
    filename: 'bundle-[hash].js',
    path: path.resolve(__dirname, 'dist')
  },

  〜中略〜

  plugins: [
    new CleanWebpackPlugin(
      ['dist'],
      {
        // 除外するファイルやディレクトリを指定
        exclude: ['img']
      }
    ),
    new MiniCssExtractPlugin({
      filename: 'style-[hash].css'
    }),
    new HtmlWebpackPlugin({
      template: './src/index.pug'
    })
  ]
});