# 機能設計書 17-チャンクマージ・分割

## 概要

本ドキュメントは、webpackのチャンクマージ・分割機能について、AggressiveMergingPlugin / AggressiveSplittingPlugin / LimitChunkCountPlugin / MinChunkSizePluginによるチャンク数・サイズの最適化の設計と実装の詳細を記述する。

### 本機能の処理概要

チャンクマージ・分割機能は、コード分割後に生成されたチャンクの数とサイズを後処理で最適化する4つのプラグインを提供する。これらはSplitChunksPluginとは異なり、既に分割されたチャンクに対して事後的にマージや追加分割を行う。

**業務上の目的・背景**：コード分割により多数の小さなチャンクが生成されると、HTTP/1.1環境では同時接続数の制限によりパフォーマンスが低下する。逆に少数の巨大なチャンクではキャッシュ効率が悪い。これらのプラグインにより、チャンクの数とサイズのバランスを調整し、ネットワーク転送とキャッシュの両面で最適なバランスを実現する。

**機能の利用シーン**：HTTP/1.1環境でのチャンク数制限、HTTP/2環境でのアグレッシブ分割、最小チャンクサイズの確保によるリクエストオーバーヘッド削減、長期キャッシュ戦略の支援。

**主要な処理内容**：
1. **AggressiveMergingPlugin**: サイズ削減効果の高いチャンクペアを積極的にマージ
2. **AggressiveSplittingPlugin**: 指定サイズ範囲でチャンクを積極的に分割（HTTP/2向け）
3. **LimitChunkCountPlugin**: チャンク数が上限を超える場合、サイズ差が最小のペアをマージ
4. **MinChunkSizePlugin**: 最小サイズ未満のチャンクを隣接チャンクにマージ

**関連システム・外部連携**：ChunkGraph（integrateChunks, canChunksBeIntegrated等）、Compilation.chunksと連携する。

**権限による制御**：各プラグインの設定オプションで制御。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 本機能は画面機能マッピングに直接の関連画面なし。バックグラウンドの最適化処理として動作 |

## 機能種別

最適化処理 / チャンクマージ・分割

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| AggressiveMergingPlugin.minSizeReduce | `number` | No | マージのトリガとなる最小サイズ削減率 | デフォルト: 1.5 |
| AggressiveSplittingPlugin.minSize | `number` | No | 分割チャンクの最小サイズ | デフォルト: 30KB |
| AggressiveSplittingPlugin.maxSize | `number` | No | 分割チャンクの最大サイズ | デフォルト: 50KB |
| LimitChunkCountPlugin.maxChunks | `number` | No | チャンク数の上限 | - |
| MinChunkSizePlugin.minChunkSize | `number` | Yes | チャンクの最小サイズ | - |

### 入力データソース

- Compilationのchunksコレクション
- ChunkGraphのモジュール-チャンクマッピング

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| マージ後のチャンク | `Chunk` | マージされたチャンク |
| 削除されたチャンク | `Chunk` | マージにより不要になったチャンク |

### 出力先

Compilationのchunksコレクション（不要チャンクが削除）

## 処理フロー

### 処理シーケンス

```
1. STAGE_ADVANCEDフェーズのoptimizeChunksフックで各プラグインが実行
2. [AggressiveMergingPlugin]
   └─ 全非初期チャンクペアの組み合わせを列挙
   └─ サイズ削減効果（improvement）を計算
   └─ 最も効果的なペアをマージ
3. [LimitChunkCountPlugin]
   └─ maxChunksを超える間、サイズ差が最小のペアをマージ
4. [MinChunkSizePlugin]
   └─ minChunkSize未満のチャンクを検出
   └─ サイズ差が最小のペアをマージ
5. [AggressiveSplittingPlugin]
   └─ 指定サイズ範囲を超えるチャンクを分割
```

### フローチャート

```mermaid
flowchart TD
    A[optimizeChunks hook STAGE_ADVANCED] --> B{AggressiveMerging?}
    B -->|Yes| C[チャンクペアの<br>improvement計算]
    C --> D[最高improvement<br>ペアをマージ]
    B -->|No| E{LimitChunkCount?}
    E -->|Yes| F{maxChunks<br>超過?}
    F -->|Yes| G[sizeDiff最小<br>ペアをマージ]
    G --> F
    F -->|No| H{MinChunkSize?}
    E -->|No| H
    H -->|Yes| I{minChunkSize<br>未満あり?}
    I -->|Yes| J[最適ペアを<br>マージ]
    I -->|No| K[完了]
    H -->|No| K
    J --> K
    D --> K
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | マージ可能性チェック | canChunksBeIntegrated()でマージ可能なペアのみ対象 | 全プラグイン共通 |
| BR-02 | 非初期チャンク限定 | AggressiveMergingPluginはcanBeInitial()=falseのチャンクのみ対象 | AggressiveMergingPlugin |
| BR-03 | サイズ削減率閾値 | improvement < minSizeReduceの場合はマージしない | AggressiveMergingPlugin |
| BR-04 | 反復実行 | optimizeChunksフックはtrueを返すと再実行される | 全プラグイン |

### 計算ロジック

- **AggressiveMergingPlugin improvement**: `(aSize + bSize) / abSize` で計算。1.0より大きいほどマージ効果が高い
- **MinChunkSizePlugin**: `a + b - ab`（サイズ削減量）でソートし、最も効果的なペアを選択

## データベース操作仕様

該当なし

## エラー処理

### エラーケース一覧

該当なし（マージ不可のペアはスキップ）

### リトライ仕様

該当なし（optimizeChunksフックはtrue返却で再実行）

## トランザクション仕様

該当なし

## パフォーマンス要件

- 全チャンクペアの組み合わせをO(n^2)で探索するため、チャンク数が極端に多い場合はパフォーマンスに影響
- LimitChunkCountPluginはLazyBucketSortedSetで効率的なソートを実現

## セキュリティ考慮事項

該当なし

## 備考

- AggressiveSplittingPluginはHTTP/2環境向けの分割戦略を提供
- これらのプラグインはSplitChunksPluginの後（STAGE_ADVANCED）で実行される

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: AggressiveMergingPluginを理解する

最もシンプルなマージプラグインから始める。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | AggressiveMergingPlugin.js | `lib/optimize/AggressiveMergingPlugin.js` | 全98行のシンプルな実装。マージロジックの基本パターンを把握 |

**主要処理フロー**:
1. **44行目**: minSizeReduceのデフォルト値1.5
2. **52-80行目**: 全非初期チャンクペアの組み合わせを列挙し、improvement（サイズ削減効果）を計算
3. **64-73行目**: chunkGraphのgetChunkSize/getIntegratedChunksSizeでサイズ計算
4. **89-90行目**: integrateChunksでマージ実行、compilation.chunks.deleteで不要チャンクを削除

#### Step 2: MinChunkSizePluginを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | MinChunkSizePlugin.js | `lib/optimize/MinChunkSizePlugin.js` | 全122行。最小サイズ制約によるマージ |

**主要処理フロー**:
- **65-84行目**: minChunkSize未満のチャンクを検出し、マージ可能なペアを収集
- **86-106行目**: サイズ削減量でソートし、最も効果的なペアをマージ
- **112-113行目**: integrateChunksとchunks.deleteでマージ実行

#### Step 3: LimitChunkCountPluginを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | LimitChunkCountPlugin.js | `lib/optimize/LimitChunkCountPlugin.js` | LazyBucketSortedSetを使った効率的なチャンク削減 |

**主要処理フロー**:
- **60-63行目**: maxChunksオプションの取得
- **73-80行目**: STAGE_ADVANCEDのoptimizeChunksフックに登録

#### Step 4: AggressiveSplittingPluginを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | AggressiveSplittingPlugin.js | `lib/optimize/AggressiveSplittingPlugin.js` | チャンク分割ロジック |

**主要処理フロー**:
- **64-80行目**: デフォルトオプション（minSize: 30KB, maxSize: 50KB, chunkOverhead: 0）
- **40-43行目**: moveModuleBetween関数でモジュールを旧チャンクから新チャンクに移動

### プログラム呼び出し階層図

```
Compilation.hooks.optimizeChunks (STAGE_ADVANCED)
    |
    +-- AggressiveMergingPlugin
    |       +-- chunkGraph.canChunksBeIntegrated(a, b)
    |       +-- chunkGraph.getChunkSize(chunk, options)
    |       +-- chunkGraph.getIntegratedChunksSize(a, b, options)
    |       +-- chunkGraph.integrateChunks(target, source)
    |       +-- compilation.chunks.delete(source)
    |
    +-- LimitChunkCountPlugin
    |       +-- LazyBucketSortedSet
    |       +-- chunkGraph.integrateChunks()
    |       +-- compilation.chunks.delete()
    |
    +-- MinChunkSizePlugin
    |       +-- chunkGraph.getChunkSize(chunk, equalOptions)
    |       +-- chunkGraph.canChunksBeIntegrated(a, b)
    |       +-- chunkGraph.integrateChunks()
    |       +-- compilation.chunks.delete()
    |
    +-- AggressiveSplittingPlugin
            +-- chunkGraph.disconnectChunkAndModule()
            +-- chunkGraph.connectChunkAndModule()
            +-- compilation.addChunk()
```

### データフロー図

```
[入力]                         [処理]                              [出力]

分割済みチャンク群 ------> AggressiveMergingPlugin      +--> マージされたチャンク
                               |                         |
チャンク数制限 ----------> LimitChunkCountPlugin        +--> 削減されたチャンク数
                               |                         |
最小チャンクサイズ ------> MinChunkSizePlugin           +--> 最小サイズ保証
                               |                         |
分割サイズ範囲 ----------> AggressiveSplittingPlugin    +--> 均等分割されたチャンク
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| AggressiveMergingPlugin.js | `lib/optimize/AggressiveMergingPlugin.js` | ソース | アグレッシブマージ |
| AggressiveSplittingPlugin.js | `lib/optimize/AggressiveSplittingPlugin.js` | ソース | アグレッシブ分割 |
| LimitChunkCountPlugin.js | `lib/optimize/LimitChunkCountPlugin.js` | ソース | チャンク数制限 |
| MinChunkSizePlugin.js | `lib/optimize/MinChunkSizePlugin.js` | ソース | 最小チャンクサイズ保証 |
| ChunkGraph.js | `lib/ChunkGraph.js` | ソース | チャンクマージ操作 |
| LazyBucketSortedSet.js | `lib/util/LazyBucketSortedSet.js` | ユーティリティ | 遅延バケットソート |
| OptimizationStages.js | `lib/OptimizationStages.js` | 定数 | 最適化ステージ定数 |
