【webpack4】逆引き webpack.config.js まとめ【ユースケース別】

# はじめに

この記事は webpack の設定ファイル（`webpack.config.js`）についてまとめたものです。
webpack 自体については他に良質なサイトや解説記事が沢山ありますので、そちらをご参照ください。
なお、他の記事でも書いていますが [webpack 公式サイト](https://webpack.js.org/) を見るのが一番間違いないです。

ここでは、ユースケース別に逆引きできるように`webpack.config.js`の書き方をまとめてみました。
プロジェクトで使用する技術スタックに応じて、テンプレートとして使うことを想定しています。

ちなみに、2020/02/24現在 webpack 歴は一週間です（予防線）

webpack についての知見を得る度に、記事をアップデートしていきます。

# 動作環境

| OS             |
|:---------------|
| Windows 10 Pro |

| Application | Version    |
|:------------|:-----------|
| Node.js     | 12.16.0    |
| npm         | 6.13.4     |
| Yarn        | 1.22.0     |

| Package     | Version   |
|:------------|:----------|
| webpack     | 4.41.6    |
| webpack-cli | 3.3.11    |

## インストール

```powershell:PowerShell
# npm
npm init -y
npm install webpack webpack-cli --save-dev

# Yarn
yarn init --yes
yarn add webpack webpack-cli --dev
```

[webpack 公式サイト](https://webpack.js.org/)でも、[ローカルインストールを推奨](https://webpack.js.org/guides/installation/#local-installation)しています。
webpack v4 以降から、コマンドラインで webpack を使用する場合は webpack-cli が必要になりました。
`npm init (yarn init)` で `package.json` を作成しているのは、npm-script を使用するためです。

## 実行（ビルド）

### CLI

```powershell:PowerShell
# npm
npx webpack

# yarn
yarn webpack
```

パラメーターとして様々なオプションを指定可能。

### npm-scripts

```json-doc:package.json
{
  "scripts": {
    "build": "webpack",
    "watch": "webpack --watch",
    "prod": "webpack --mode=production"
  },
  "devDependencies": {
    "webpack": "^4.41.6",
    "webpack-cli": "^3.3.11"
  }
}
```

```powershell:PowerShell
# npm
npm run build

# Yarn
yarn run build
```

npm-scripts に様々なオプション付きの webpack コマンドを登録しておくと便利です。

# 逆引きwebpack.config.js

## 基本構成

### ES Modules

#### ディレクトリ構成

```
<Project Root> ┬ dist
               │  └ main.js
               ├ node_modules
               ├ package.json
               ├ src
               │  └ index.js
               └ webpack.config.js
```

#### webpack.config.js

```javascript:webpack.config.js
const path = require('path');

module.exports = {
  // モード
  mode: 'development',

  // エントリーポイント
  entry: './src/index.js',

  // ファイル出力先
  output: {
    // 出力先ディレクトリ
    path: path.resolve(__dirname, 'dist'),
    // 出力ファイル名
    filename: 'main.js'
  },

  // ソースマップ
  devtool: 'cheap-module-eval-source-map'
};
```

各プロパティを省略した場合のデフォルト値は以下の通り。

| プロパティ       | デフォルト値    |
|:----------------|:---------------|
| mode            | production     |
| entry           | ./src/index.js |
| output.path     | ./dist         |
| output.filename | main.js        |

### ECMAScript2015+

#### 追加パッケージ

| Package           | Version   |
|:------------------|:----------|
| babel-loader      | 8.0.6     |
| @babel/core       | 7.8.4     |
| @babel/preset-env | 7.8.4     |

#### インストール

```powershell:PowerShell
# npm
npm install babel-loader @babel/core @babel/preset-env --save-dev

# Yarn
yarn add babel-loader @babel/core @babel/preset-env --dev
```

#### ディレクトリ構成

```
<Project Root> ┬ dist
               │  └ main.js
               ├ node_modules
               ├ package.json
               ├ src
               │  └ index.js
               └ webpack.config.js
```

#### webpack.config.js

```javascript:webpack.config.js
const path = require('path');

module.exports = {
  // モード
  mode: 'development',

  // エントリーポイント
  entry: './src/index.js',

  // ファイル出力先
  output: {
    // 出力先ディレクトリ
    path: path.resolve(__dirname, 'dist'),
    // 出力ファイル名
    filename: 'main.js'
  },

  // ソースマップ
  devtool: 'cheap-module-eval-source-map',

  // ローダー
  module: {
    rules: [
      {
        test: /\.js$/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env']
          }
        }
      }
    ]
  }
};
```

### TypeScript

#### 追加パッケージ

| Package    | Version   |
|:-----------|:----------|
| ts-loader  | 6.2.1     |
| typescript | 3.8.2     |

#### インストール

```powershell:PowerShell
# npm
npm install ts-loader typescript --dev-save
npx tsc --init

# Yarn
yarn add ts-loader typescript --dev
yarn tsc --init
```

#### ディレクトリ構成

```
<Project Root> ┬ dist
               │  └ main.js
               ├ node_modules
               ├ package.json
               ├ src
               │  └ index.js
               ├ tsconfig.json
               └ webpack.config.js
```

#### tsconfig.json

```json-doc:tsconfig.json
{
  "compilerOptions": {
    // ソースマップ出力
    "sourceMap": true,
    // 変換先ECMAScriptバージョン
    "target": "es5",
    // モジュール出力
    "module": "es2015",
    "strict": true,
    "noImplicitAny": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true
  }
}
```

#### webpack.config.js

```javascript:webpack.config.js
const path = require('path');

module.exports = {
  // モード
  mode: 'development',

  // エントリーポイント
  entry: './src/index.ts',

  // ファイル出力先
  output: {
    // 出力先ディレクトリ
    path: path.resolve(__dirname, 'dist'),
    // 出力ファイル名
    filename: 'main.js'
  },

  // ソースマップ
  devtool: 'cheap-module-eval-source-map',

  // ローダー
  module: {
    rules: [
      {
        test: /\.ts$/,
        use: 'ts-loader'
      }
    ]
  },

  // モジュール解決
  resolve: {
    extensions: ['.ts']
  }
};
```

### Sass

#### 追加パッケージ

| Package      | Version   |
|:-------------|:----------|
| sass-loader  | 8.0.2     |
| style-loader | 1.1.3     |
| css-loader   | 3.4.2     |
| sass         | 1.25.0    |

#### インストール

```powershell:PowerShell
# npm
npm install sass-loader style-loader css-loader sass --dev-save

# Yarn
yarn add sass-loader style-loader css-loader sass --dev
```

#### ディレクトリ構成

```
<Project Root> ┬ dist
               │  └ main.js
               ├ node_modules
               ├ package.json
               ├ src
               │  ├ index.js
               │  └ style.scss
               └ webpack.config.js
```

#### webpack.config.js

```javascript:webpack.config.js
const path = require('path');

module.exports = {
  // モード
  mode: 'development',

  // エントリーポイント
  entry: './src/index.js',

  // ファイル出力先
  output: {
    // 出力先ディレクトリ
    path: path.resolve(__dirname, 'dist'),
    // 出力ファイル名
    filename: 'main.js'
  },

  // ソースマップ
  devtool: 'cheap-module-eval-source-map',

  // ローダー
  module: {
    rules: [
      {
        test: /\.scss$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              url: false,
              sourceMap: true,
              importLoaders: 1
            }
          },
          {
            loader: 'sass-loader',
            options: {
              sourceMap: true
            }
          }
        ]
      }
    ]
  }
};
```

複数の loader を通す場合、 use プロパティに配列で loader を設定します。
loader の処理は、配列の**最後から**順番に行われます。

### Images

#### 追加パッケージ

| Package      | Version   |
|:-------------|:----------|
| url-loader   | 3.0.0     |

#### インストール

```powershell:PowerShell
# npm
npm install url-loader --dev-save

# Yarn
yarn add url-loader --dev
```

#### ディレクトリ構成

```
<Project Root> ┬ dist
               │  └ main.js
               ├ node_modules
               ├ package.json
               ├ src
               │  ├ index.js
               │  └ image.png
               └ webpack.config.js
```

#### webpack.config.js

```javascript:webpack.config.js
const path = require('path');

module.exports = {
  // モード
  mode: 'development',

  // エントリーポイント
  entry: './src/index.js',

  // ファイル出力先
  output: {
    // 出力先ディレクトリ
    path: path.resolve(__dirname, 'dist'),
    // 出力ファイル名
    filename: 'main.js'
  },

  // ソースマップ
  devtool: 'cheap-module-eval-source-map',

  // ローダー
  module: {
    rules: [
      {
        test: /\.(gif|png|jpg|eot|wof|woff|woff2|ttf|svg)$/,
        loader: 'url-loader'
      }
    ]
  }
};
```

## ユースケース

### Multi Page Application（複数エントリーポイント）

#### ディレクトリ構成

```
<Project Root> ┬ dist
               │  ├ index.bundle.js
               │  ├ list.bundle.js
               │  └ detail.bundle.js
               ├ node_modules
               ├ package.json
               ├ src
               │  ├ index.js
               │  ├ list.js
               │  └ detail.js
               └ webpack.config.js
```

#### webpack.config.js

```javascript:webpack.config.js
const path = require('path');

module.exports = {
  // モード
  mode: 'development',

  // エントリーポイント
  entry: {
    index: './src/index.js',
    list: './src/list.js',
    detail: './src/detail.js'
  },

  // ファイル出力先
  output: {
    // 出力先ディレクトリ
    path: path.resolve(__dirname, 'dist'),
    // 出力ファイル名
    filename: '[name].bundle.js'
  },

  // ソースマップ
  devtool: 'cheap-module-eval-source-map'
};
```

### CSS を別ファイルとして出力する

#### 追加パッケージ

| Package                 | Version   |
|:------------------------|:----------|
| css-loader              | 3.4.2     |
| mini-css-extract-plugin | 0.9.0     |

#### インストール

```powershell:PowerShell
# npm
npm install css-loader mini-css-extract-plugin --dev-save

# Yarn
yarn add css-loader mini-css-extract-plugin --dev
```

#### ディレクトリ構成

```
<Project Root> ┬ dist
               │  ├ main.js
               │  └ style.css
               ├ node_modules
               ├ package.json
               ├ src
               │  ├ index.js
               │  └ style.css
               └ webpack.config.js
```

#### webpack.config.js

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

module.exports = {
  // モード
  mode: 'development',

  // エントリーポイント
  entry: './src/index.js',

  // ファイル出力先
  output: {
    // 出力先ディレクトリ
    path: path.resolve(__dirname, 'dist'),
    // 出力ファイル名
    filename: 'main.js'
  },

  // ソースマップ
  devtool: 'cheap-module-eval-source-map',

  // ローダー
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
          },
          {
            loader: 'css-loader',
            options: {
              url: false,
              sourceMap: true
            }
          }
        ]
      }
    ]
  },

  // プラグイン
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'style.css',
    }),
  ]
};
```