webpack 4 の optimization.splitChunks の使い方、使い所 〜廃止された CommonsChunkPlugin から移行する〜

# はじめに
先日リリースされたwebpack 4でCommonsChunkPluginは廃止されました（[CommonsChunkPluginの解説はこちら](https://qiita.com/soarflat/items/f8212434c4c3cb8ee00d)）。

その代わりとした追加された`optimization.splitChunks`の基本的な使い方、使い所に関しての記事です。
`optimization.splitChunks`を利用すればサイトパフォーマンスの改善（詳細は後述）ができるため、利用する機会が多い設定（機能）です。

解説に利用しているコードの最終形態はGitHub上にあります。
[hira777/webpack-split-chunks-example](https://github.com/hira777/webpack-split-chunks-example)

webpackを理解していることを前提とした記事ですので、基礎知識を習得したい方は[webpack 4入門](http://qiita.com/soarflat/items/28bf799f7e0335b68186)をご覧ください。

# `optimization.splitChunks`とは
「複数のエントリーポイント間で利用している共通モジュールをバンドルしたファイル」を出力するための設定のこと。
設定は`webpack.config.js`に記述する。

## 通常の出力と`optimization.splitChunks`を有効にした出力の違い（イメージ図）
以下は通常の出力

![webpack.jpg](https://qiita-image-store.s3.amazonaws.com/0/69667/17aa53d3-a8db-86a8-709d-b7672ad19d3e.jpeg)

以下は`optimization.splitChunks`を有効にした出力

![splitChunks.png](https://qiita-image-store.s3.amazonaws.com/0/69667/c3f8a18b-5c41-8b58-e541-d79dabe4e384.png)

## なぜ`optimization.splitChunks`を有効にするのか
上記のイメージ図のように共通ファイルを出力するため、以下のようなメリットがあるから。

- 複数のエントリーポイントが1つの共通ファイルを利用するため、全体のファイルサイズが小さくなる
- 共通ファイルなのでキャッシュを活用できる（1度読み込めば別ページに遷移しても読み込みが不要、共通ではないファイルだけ読み込めば良い）

# `optimization.splitChunks`を有効にしてみる
`webpack.config.js`に`optimization.splitChunks`の設定を記述して共通のモジュールをバンドルしたファイルを出力してみる。

## ディレクトリ構成
```
.
├── package.json
├── public
│   ├── index.html
│   ├── index2.html
│   ├── index3.html
│   └── js
│       ├── app.bundle.js
│       ├── app2.bundle.js
│       ├── app3.bundle.js
│       └── vendor.bundle.js
├── src
│   └── js
│       ├── app.js
│       ├── app2.js
│       └── app3.js
└── webpack.config.js
```

## 各ファイルの詳細

### `package.json`

```json:package.json
{
  "name": "webpack-split-chunks-example",
  "version": "1.0.0",
  "devDependencies": {
    "webpack": "^4.30.0",
    "webpack-cli": "^3.3.0"
  },
  "dependencies": {
    "jquery": "^3.4.0",
    "velocity-animate": "^1.5.2"
  }
}
```

上記の`package.json`が存在する階層で以下のコマンドを実行すれば、必要なパッケージ（モジュール）をインストールできる。

```sh
npm install
```

or

```sh
yarn install
```

### `webpack.config.js`

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

module.exports = {
  entry: {
    app: './src/js/app.js',
    app2: './src/js/app2.js',
    app3: './src/js/app3.js',
  },
  output: {
    filename: '[name].bundle.js',
    path: path.join(__dirname, 'public/js'),
  },
  optimization: {
    splitChunks: {
      name: 'vendor',
      chunks: 'initial',
    }
  }
};
```

以下が`optimization.splitChunks`に関する記述である。

```js
optimization: {
  splitChunks: {
    name: 'vendor',
    chunks: 'initial',
  }
}
```

#### `name`
共通モジュールをバンドルしたファイル（チャンク）の名前。今回は`'vendor'`を指定したため、出力されるファイル名は`vendor.bundle.js`になる。

`true`にすると自動的に名前がつけられる。

#### `chunks`
共通モジュールとしてバンドルする対象の設定。`initial`、`async`、`all`が存在する。

基本的な利用であれば`initial`を指定しておけば良い。

バンドルしたファイルを複数に分割して出力し、非同期で読み込む場合などは状況に応じて`async`や`all`を指定する。

### `app.js`、`app2.js`
エントリーポイントである`app.js`、`app2.js`は以下の処理を記述している。

- セレクタを指定し、文字列を出力。
- 指定したセレクタをフェードアウトする。

```js:app.js
import $ from 'jquery';
import velocity from 'velocity-animate';

const text = 'app';
const $body = $('body');

$body.html(text);
velocity($body, 'fadeOut', {
  duration: 1000
});
```

```js:app2.js
import $ from 'jquery';
import velocity from 'velocity-animate';

const text = 'app2';
const $body = $('body');

$body.html(text);
velocity($body, 'fadeOut', {
  duration: 1000
});
```

どちらも外部モジュールである`jquery`と`velocity-animate`を利用している。
そのため、`jquery`と`velocity-animate`は複数のエントリーポイント間で利用されている共通のモジュールである。

### `app3.js`
エントリーポイントである`app3.js`は以下の処理を記述している。

```js:app3.js
const body = document.getElementsByTagName('body')[0];
body.innerText = 'Body!!';
```

`body`要素に文字列を出力しているだけのため、モジュールは何も利用していない。

## webpackコマンドでバンドルしたファイルを出力
上記構成の`webpack.config.js`が存在する階層で`webpack --mode production`（もしくは`webpack --mode development`）コマンドを実行すれば、それぞれバンドルしたファイルが出力される。

何が共通モジュールなのかはwebpackが自動で判別し、共通モジュールをバンドルしたファイル（今回は`vendor.bundle.js`）を出力する。

今回の設定だと以下のファイルが`public/js/`に出力される。

- `app.bundle.js`
- `app2.bundle.js`
- `app3.bundle.js`
- `vendor.bundle.js`

```bash
webpack --mode production

# 以下のような出力がされる
Hash: 71b17588b6f95673e281
Version: webpack 4.30.0
Time: 436ms
Built at: 2019-04-20 23:19:44
           Asset       Size  Chunks             Chunk Names
   app.bundle.js   1.57 KiB       1  [emitted]  app
  app2.bundle.js   1.57 KiB       2  [emitted]  app2
  app3.bundle.js  991 bytes       3  [emitted]  app3
vendor.bundle.js    130 KiB       0  [emitted]  vendor
Entrypoint app = vendor.bundle.js app.bundle.js
Entrypoint app2 = vendor.bundle.js app2.bundle.js
Entrypoint app3 = app3.bundle.js
[2] ./src/js/app.js 179 bytes {1} [built]
[3] ./src/js/app2.js 180 bytes {2} [built]
[4] ./src/js/app3.js 81 bytes {3} [built]
    + 2 hidden modules
```

どのエントリーポイントの共通モジュールがバンドルされたのかは、コマンド実行時の出力で確認できる。
上記の出力を確認してみると、`vendor.bundle.js`が`app.bundle.js`と`app2.bundle.js`の共通モジュールをバンドルしている（依存関係を持っている）ことがわかる。

```bash
Entrypoint app = vendor.bundle.js app.bundle.js
Entrypoint app2 = vendor.bundle.js app2.bundle.js
Entrypoint app3 = app3.bundle.js
```

### 出力されたファイルを確認してみる
それぞれのエントリーポイントから出力されたファイルを読み込んでいるHTMLは以下の通り。

**index.html**

```html:index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
  <script src="js/vendor.bundle.js"></script>
  <script src="js/app.bundle.js"></script>
</body>
</html>
```

![app.gif](https://qiita-image-store.s3.amazonaws.com/0/69667/566306e0-bcad-33ec-5800-7faef7375361.gif)

**index2.html**

```html:index2.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
  <script src="js/vendor.bundle.js"></script>
  <script src="js/app2.bundle.js"></script>
</body>
</html>
```
![app2.gif](https://qiita-image-store.s3.amazonaws.com/0/69667/9c719c7c-ccf9-21b9-bb8f-3cb6a2723469.gif)

**index3.html**

```html:index3.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
  <script src="js/app3.bundle.js"></script>
</body>
</html>
```

![app3.jpg](https://qiita-image-store.s3.amazonaws.com/0/69667/ca2433c6-95bd-f7bb-7161-7ba2f63e737e.jpeg)

全て正常に動作していることがわかる。

今回の場合、共通モジュールを利用している`app.bundle.js`と`app2.bundle.js`は`vendor.bundle.js`も読み込むと正常に動作する。

`app3.bundle.js`は共通モジュールを利用していないため、`vendor.bundle.js`自体を読み込む必要がなく、正常に動作する。

## `optimization.splitChunks`を有効にしないとどのようなファイルが出力されるのか
通常の出力と何が違うのかを理解するために、`optimization.splitChunks`を有効にしないとどのようなファイルが出力するのか見てみる。
以下は`optimization.splitChunks`の記述を削除した`webpack.config.js`。

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

module.exports = {
  entry: {
    app: './src/app.js',
    app2: './src/app2.js',
    app3: './src/app3.js',
  },
  output: {
    filename: '[name].bundle.js',
    path: path.join(__dirname, 'public/js'),
  }
};
```

上記の設定で`webpack --mode production`（もしくは`webpack --mode development`）コマンドを実行すると以下のようなファイルが出力される。

```bash
webpack

# 以下のような出力がされる
Hash: 2a40542b654de233f5af
Version: webpack 4.30.0
Time: 2198ms
Built at: 2019-04-20 23:22:43
         Asset       Size  Chunks             Chunk Names
 app.bundle.js    131 KiB       0  [emitted]  app
app2.bundle.js    131 KiB       1  [emitted]  app2
app3.bundle.js  991 bytes       2  [emitted]  app3
Entrypoint app = app.bundle.js
Entrypoint app2 = app2.bundle.js
Entrypoint app3 = app3.bundle.js
[2] ./src/js/app.js 179 bytes {0} [built]
[3] ./src/js/app2.js 180 bytes {1} [built]
[4] ./src/js/app3.js 81 bytes {2} [built]
    + 2 hidden modules
```

このファイルでもブラウザ上で正常に動作するが、**モジュールを利用している`app.js`と`app2.js`のそれぞれに`jquery`と`velocity-animate`がバンドルされて出力されてしまっている**。

そのため、先ほど`optimization.splitChunks`を有効にして出力したファイルと比べ、以下の問題点がある。

- エントリーポイントを更新する度に`jquery`と`velocity-animate`もバンドルしたファイルが更新されるため、キャッシュを活用できない
- `app.bundle.js`と`app2.bundle.js`のファイルサイズが大きくなってしまう
- それぞれのエントリーポイントに同じモジュールを読み込んでいるため、無駄にファイルサイズが大きくなっている

ということで`optimization.splitChunks`を有効にすれば、キャッシュを活用するだけではなく、全体のファイルサイズも少なくできる。

# `optimization.splitChunks`の様々な設定や使い方
上記は最低限の利用方法のため、利用シーンに応じた設定や使い方をいくつか紹介する。

## `optimization.splitChunks`でバンドルする共通モジュールを指定する
特に指定をしなければ`optimization.splitChunks`は自動で共通モジュールをバンドルして出力をする。

今回は`jquery`と`velocity-animate`が共通で利用されているため、それらがバンドルされて出力される。

自動で共通モジュールをバンドルする機能は便利だが、その機能がこちらの意図に削ぐわない時もある。

前述した構成にユーザーが作成した`moduleA.js`を追加するシーンを想定してみる。

ディレクトリ構成は以下のようになる。

```
.
├── README.md
├── package.json
├── public
│   ├── index.html
│   ├── index2.html
│   ├── index3.html
│   └── js
│       ├── app.bundle.js
│       ├── app2.bundle.js
│       ├── app3.bundle.js
│       └── vendor.bundle.js
├── src
│   └── js
│       ├── app.js
│       ├── app2.js
│       ├── app3.js
│       └── modules
│           └── moduleA.js
└── webpack.config.js
```

`moduleA.js`の内容は以下の通り。

```js:moduleA.js
export default function () {
  console.log('moduleA!!!');
  console.log('moduleA!!!');
  console.log('moduleA!!!');
  console.log('moduleA!!!');
  console.log('moduleA!!!');
};
```

上記モジュールを以下のように`app.js`と`app2.js`で読みこんで利用する。

```js:app.js
import $ from 'jquery';
import velocity from 'velocity-animate';
import moduleA from './modules/moduleA';

const text = 'app';
const $body = $('body');

$body.html(text);
velocity($body, 'fadeOut', {
  duration: 1000
});
moduleA();
```

```js:app2.js
import $ from 'jquery';
import velocity from 'velocity-animate';
import moduleA from './modules/moduleA';

const text = 'app2';
const $body = $('body');

$body.html(text);
velocity($body, 'fadeOut', {
  duration: 1000
});
moduleA();
```

この状態で`webpack --mode production`（もしくは`webpack --mode development`）コマンドを実行すると`jquery`、`velocity-animate`、`moduleA.js`がバンドルされた`vendor.bundle.js`が出力される。

自動で共通のモジュールがバンドルされたが、**`moduleA.js`が頻繁に更新されるモジュールであったり、`moduleB.js`のような新しいモジュールが追加される度に`vendor.bundle.js`が更新されてしまうため、キャッシュをあまり活用できない**。

`jquery`、`velocity-animate`のような頻繁に更新しない外部モジュール（`node_modules`配下のモジュール）のみをバンドルしたい場合、以下のように`webpack.config.js`に記述を変更する。

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

module.exports = {
  entry: {
    app: './src/js/app.js',
    app2: './src/js/app2.js',
    app3: './src/js/app3.js',
  },
  output: {
    filename: '[name].bundle.js',
    path: path.join(__dirname, 'public/js'),
  },
  optimization: {
    splitChunks: {
      // cacheGroups内にバンドルの設定を複数記述できる
      cacheGroups: {
        // 今回はvendorだが、任意の名前で問題ない
        vendor: {
          // node_modules配下のモジュールをバンドル対象とする
          test: /node_modules/,
          name: 'vendor',
          chunks: 'initial',
          enforce: true
        }
      }
    }
  }
};
```

この状態で`webpack --mode production`（もしくは`webpack --mode development`）コマンドを実行すると以下のように`jquery`、`velocity-animate`のみがバンドルされた`vendor.bundle.js`が出力され、`moduleA.js`は`app.js`と`app2.js`のそれぞれにバンドルされて出力される。

```bash
webpack --mode production

# 以下のような出力がされる
Hash: 85dfe516e28462f92c16
Version: webpack 4.30.0
Time: 1996ms
Built at: 2019-04-20 23:26:15
           Asset       Size  Chunks             Chunk Names
   app.bundle.js   1.76 KiB       1  [emitted]  app
  app2.bundle.js   1.76 KiB       2  [emitted]  app2
  app3.bundle.js  991 bytes       3  [emitted]  app3
vendor.bundle.js    130 KiB       0  [emitted]  vendor
Entrypoint app = vendor.bundle.js app.bundle.js
Entrypoint app2 = vendor.bundle.js app2.bundle.js
Entrypoint app3 = app3.bundle.js
[0] ./src/js/modules/moduleA.js 177 bytes {1} {2} [built]
[3] ./src/js/app.js 231 bytes {1} [built]
[4] ./src/js/app2.js 232 bytes {2} [built]
[5] ./src/js/app3.js 81 bytes {3} [built]
    + 2 hidden modules
```

## 共通モジュールをバンドルしたファイルを複数出力する
上記の`moduleA.js`のようなサイズが小さいモジュールであれば、それぞれのエントリーポイントにバンドルしても問題ない。

しかし、サイズが大きいモジュールをそれぞれのエントリーポイントにバンドルしてしまうと、全体のファイルサイズが大きくなる等のデメリットが生じてしまう。

とは言えども、頻繁に更新をしない外部モジュールはそれらだけをバンドルしてキャッシュを活用したい。

そのため、外部モジュールをバンドルしたファイルとは別の「自分たちが作成した共通モジュールをバンドルしたファイル」を出力すれば、全体のファイルサイズが大きくなるデメリットも解消される。

以下のように`webpack.config.js`に記述を追加すれば、共通モジュールをバンドルしたファイルを複数出力できる。

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

module.exports = {
  entry: {
    app: './src/js/app.js',
    app2: './src/js/app2.js',
    app3: './src/js/app3.js',
  },
  output: {
    filename: '[name].bundle.js',
    path: path.join(__dirname, 'public/js'),
  },
  optimization: {
    splitChunks: {
      cacheGroups: {
        // 今回はvendorだが、任意の名前で問題ない
        vendor: {
          // node_modules配下のモジュールをバンドル対象とする
          test:/node_modules/,
          name: 'vendor',
          chunks: 'initial',
          enforce: true
        },
        vendorModules: {
          // 今回はsrc/js/modules配下にバンドルしたいモジュールが存在するため指定は以下になる
          test: /src\/js\/modules/,
          name: 'vendor-modules',
          chunks: 'initial',
          enforce: true
        }
      }
    }
  }
};
```

この状態で`webpack --mode production`（もしくは`webpack --mode development`）コマンドを実行すると以下のように`jquery`、`velocity-animate`がバンドルされた`vendor.bundle.js`と`moduleA.js`がバンドルされた`vendor-modules.js`が出力される。

```bash
webpack --mode production

# 以下のような出力がされる
Hash: 2695ceef4fb3c93f0e96
Version: webpack 4.30.0
Time: 270ms
Built at: 2019-04-20 23:27:55
                   Asset       Size  Chunks             Chunk Names
           app.bundle.js   1.59 KiB       2  [emitted]  app
          app2.bundle.js   1.59 KiB       3  [emitted]  app2
          app3.bundle.js  991 bytes       4  [emitted]  app3
vendor-modules.bundle.js  238 bytes       1  [emitted]  vendor-modules
        vendor.bundle.js    130 KiB       0  [emitted]  vendor
Entrypoint app = vendor.bundle.js vendor-modules.bundle.js app.bundle.js
Entrypoint app2 = vendor.bundle.js vendor-modules.bundle.js app2.bundle.js
Entrypoint app3 = app3.bundle.js
[2] ./src/js/modules/moduleA.js 177 bytes {1} [built]
[3] ./src/js/app.js 231 bytes {2} [built]
[4] ./src/js/app2.js 232 bytes {3} [built]
[5] ./src/js/app3.js 81 bytes {4} [built]
    + 2 hidden modules
```

以下のように出力された`vendor-modules.js`も読み込めば動作する。

```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
  <script src="js/vendor-modules.bundle.js"></script>
  <script src="js/vendor.bundle.js"></script>
  <script src="js/app.bundle.js"></script>
</body>
</html>
```

## `optimization.splitChunks`のデフォルト設定を理解し、上書きする
webpack実行時、以下の`optimization.splitChunks`に関する設定がデフォルトで有効になっている。

```js
optimization: {
  splitChunks: {
    chunks: 'async',
    minSize: 30000,
    maxSize: 0,
    minChunks: 1,
    maxAsyncRequests: 5,
    maxInitialRequests: 3,
    automaticNameDelimiter: '~',
    name: true,
    cacheGroups: {
      vendors: {
        test: /[\\/]node_modules[\\/]/,
        priority: -10
      },
      default: {
        minChunks: 2,
        priority: -20,
        reuseExistingChunk: true
      }
    }
  }
}
```

つまり、以下の設定でwebpackを実行すれば

```js
const path = require('path');

module.exports = {
  entry: {
    app: './src/js/app.js',
    app2: './src/js/app2.js',
    app3: './src/js/app3.js',
  },
  output: {
    filename: '[name].bundle.js',
    path: path.join(__dirname, 'public/js'),
  }
};
```

以下の設定でwebpackが実行されているのと同じである。

```js
const path = require('path');

module.exports = {
  entry: {
    app: './src/js/app.js',
    app2: './src/js/app2.js',
    app3: './src/js/app3.js',
  },
  output: {
    filename: '[name].bundle.js',
    path: path.join(__dirname, 'public/js'),
  },
  optimization: {
    splitChunks: {
      chunks: 'async',
      minSize: 30000,
      maxSize: 0,
      minChunks: 1,
      maxAsyncRequests: 5,
      maxInitialRequests: 3,
      automaticNameDelimiter: '~',
      name: true,
      cacheGroups: {
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          priority: -10
        },
        default: {
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true
        }
      }
    }
  }
};
```

### 設定項目
各設定項目は以下の通り（まだ解説していないものだけ記載）

※一部項目があまり理解できていないため、間違いがあれば修正を加えていきます。

#### `minSize`
共通モジュールとしてバンドルするモジュールの最小サイズ（単位はbyte）。

デフォルトが30000のため、**30kb未満のモジュールは複数のエントリーポイントで利用されていても共通モジュールとしてバンドルされない**。

#### `minChunks`
モジュールがいくつのエントリーポイントで利用されていれば、共通モジュールとしてバンドルするかの設定。

前述した`moduleA.js`は2つのエントリーポイントでしか利用されていないため、`minChunks: 3`を指定すると共通モジュールとしてバンドルされない。

#### `maxAsyncRequests`
オンデマンドローディング時の最大並列リクエスト数（あまり良くわかっていない）

#### `maxInitialRequests`
エントリポイントでの並列リクエストの最大数（あまり良くわかっていない）

#### `cacheGroups`
前述した`vendor.bundle.js`、`vendor-modules.js`のように、指定した共通モジュールを出力したい時に設定する項目。

`minSize`や`minChunks`なども指定できるため、出力するファイル毎に設定が可能。

#### `priority`
`cacheGroups`内の設定の優先順位（値が大きいほど優先順位が高い）。

ユーザーが追加した`cacheGroups`の`priority`はデフォルトが0のため、デフォルトで存在する`default`と`vendors`より優先度が高い。

そのため、以下の場合どちらも`node_modules`内のモジュールを対象として共通モジュールをバンドルする設定だが、`vendor`の設定が優先されてファイルが出力される。

```js
splitChunks: {
  cacheGroups: {
    vendors: {
      test: /[\\/]node_modules[\\/]/,
      priority: -10
    },
    vendor: {
      test: /node_modules/,
      name: "vendor",
      minSize: 1,
      minChunks: 2,
    }
  }
}
```

#### `reuseExistingChunk`
モジュールが正確に一致したときに新しいチャンクを作成する代わりに、既存のチャンクを再利用することができる（あまり良くわかっていない）。

### 設定を上書きする
デフォルト設定では`chunks: 'async'`が指定されているため、この状態でwebpackを実行しても共通モジュールをバンドルしたファイルは出力されないことが多い。

そのため、`chunks: 'all'` に上書きしてみる。設定を上書きしたい場合は以下のように`webpack.config.js`に設定を記述すれば良い。

```js
const path = require('path');

module.exports = {
  entry: {
    app: './src/js/app.js',
    app2: './src/js/app2.js',
    app3: './src/js/app3.js',
  },
  output: {
    filename: '[name].bundle.js',
    path: path.join(__dirname, 'public/js'),
  },
  optimization: {
    splitChunks: {
      // この設定以外はデフォルトのまま
      chunks: 'all'
    }
  }
};
```

上記の設定でwebpackを実行すると、以下のような出力がされる。

```bash
Hash: 756f13664ec4b4102c16
Version: webpack 4.30.0
Time: 306ms
Built at: 2019-04-20 23:36:34
                     Asset       Size  Chunks             Chunk Names
             app.bundle.js   1.76 KiB       1  [emitted]  app
            app2.bundle.js   1.76 KiB       2  [emitted]  app2
            app3.bundle.js  991 bytes       3  [emitted]  app3
vendors~app~app2.bundle.js    130 KiB       0  [emitted]  vendors~app~app2
Entrypoint app = vendors~app~app2.bundle.js app.bundle.js
Entrypoint app2 = vendors~app~app2.bundle.js app2.bundle.js
Entrypoint app3 = app3.bundle.js
[0] ./src/js/modules/moduleA.js 177 bytes {1} {2} [built]
[3] ./src/js/app.js 231 bytes {1} [built]
[4] ./src/js/app2.js 232 bytes {2} [built]
[5] ./src/js/app3.js 81 bytes {3} [built]
    + 2 hidden modules
```

`app.bundle.js`と`app2.bundle.js`の共通モジュールをバンドルしている`vendors~app~app2.bundle.js`が出力された。

デフォルト設定である`minSize: 30000`が有効であるため、30kb以下である`moduleA.js`は`app.js`と`app2.js`のそれぞれにバンドルされて出力される。`moduleA.js`も共通モジュールとしてバンドルしたいのであれば、`minSize: 1`などを指定すればバンドルされる。

自分で`optimization.splitChunks`の設定をしたのに予期しないファイルが出力された場合、デフォルト設定が有効になっている可能性もあるので注意。

# 終わり

自分で設定を書いてみて、どんなファイルが出力されるのか確認してみると理解が深まるかと思います。非常に有用な設定ですので、状況に応じて利用していきましょう。

この`optimization.splitChunks`に関しては私が公開した Umdey 講座でも学習できます。

- [webpack 最速入門](https://www.udemy.com/course/practical-webpack/?couponCode=B6D5AE3897554CBBDAD7)（**~~10,800 円~~ -> 2,000 円**）

記事と内容が重複している箇所もありますが、`optimization.splitChunks`の基本から応用的な使い方までハンズオン形式で学習できます。

興味を持ってくださった方はご購入いただけると大変嬉しいです。よろしくお願いいたします。

## 最適化に関連する記事

最適化に関連する webpack を 利用した Tree Shaking に関しての記事を書きましたので、興味があるかはこちらの記事もどうぞ。

[webpackのTree Shakingを理解してファイルサイズを削減する](https://qiita.com/soarflat/items/755bbbcd6eb81bd128c4)

## お知らせ

Kindle でも技術書を出版しています。

Kindle（Kindle Unlimited だったら無料）:
[React Hooks 入門](https://www.amazon.co.jp/gp/product/B08JTXQ2M6)（500 円）

興味を持ってくださった方はご購入いただけると大変嬉しいです。よろしくお願いいたします。