# 機能設計書 14-モジュール連結（Scope Hoisting）

## 概要

本ドキュメントは、webpackのModuleConcatenationPlugin（Scope Hoisting）によるモジュール結合最適化について、その設計と実装の詳細を記述する。

### 本機能の処理概要

モジュール連結（Scope Hoisting）は、複数のES Moduleを単一のスコープに結合し、モジュール間の関数呼び出しオーバーヘッドを削減する最適化機能である。webpackのproductionモードではデフォルトで有効化される。

**業務上の目的・背景**：従来のwebpackバンドルでは、各モジュールが独立したクロージャでラップされ、`__webpack_require__`関数による間接呼び出しが行われていた。これにより、(1)関数呼び出しのオーバーヘッド、(2)各モジュールラッパーのコードサイズ、(3)JavaScriptエンジンの最適化阻害、が問題となっていた。Scope Hoistingにより、これらの問題を解消してバンドルサイズと実行速度を改善する。

**機能の利用シーン**：プロダクションビルドでの自動最適化、ライブラリバンドル時のサイズ削減、パフォーマンスクリティカルなアプリケーションでのJavaScript実行速度改善。

**主要な処理内容**：
1. ESMモジュールの連結可能性を判定（bailout条件のチェック）
2. モジュールのインポート/エクスポート関係に基づく連結グループの構築
3. ConcatenatedModuleの生成（複数モジュールを結合した仮想モジュール）
4. チャンクグラフの更新（元モジュールの置換）

**関連システム・外部連携**：HarmonyImportDependency、ConcatenatedModule、ChunkGraph、ModuleGraph、最適化フック（optimizeChunkModules）と連携する。

**権限による制御**：optimization.concatenateModules設定で有効/無効を制御。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 10 | Login (reexport-components) | 補助機能 | コンポーネントモジュール群のスコープ結合による最適化 |
| 11 | Dashboard (reexport-components) | 補助機能 | コンポーネントモジュール群のスコープ結合による最適化 |

## 機能種別

最適化処理 / モジュール結合

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| optimization.concatenateModules | `boolean` | No | モジュール連結の有効/無効 | デフォルト: productionモードでtrue |

### 入力データソース

- Compilationのモジュールグラフ（ESMモジュール間のインポート/エクスポート関係）
- ChunkGraphのモジュール-チャンクマッピング

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| ConcatenatedModule | `Module` | 結合された仮想モジュール |
| 更新されたChunkGraph | `ChunkGraph` | 元モジュールが結合モジュールに置換されたグラフ |

### 出力先

Compilationのモジュールコレクション、ChunkGraph

## 処理フロー

### 処理シーケンス

```
1. 全モジュールの連結可能性チェック
   └─ ESMモジュールか、副作用フラグ、チャンク条件等を検証
2. bailout判定
   └─ 非ESM、eval使用、特定の依存タイプ等で連結不可と判定
3. 連結グループの構築
   └─ ルートモジュールから辿れるHarmonyImport先を候補に追加
4. 候補の検証
   └─ チャンク条件、ランタイム条件、循環依存等をチェック
5. ConcatenatedModuleの生成
   └─ 結合対象モジュールを一つの仮想モジュールにまとめる
6. ChunkGraphの更新
   └─ 元モジュールをConcatenatedModuleに置換
```

### フローチャート

```mermaid
flowchart TD
    A[optimizeChunkModules hook] --> B[全モジュールスキャン]
    B --> C{ESMモジュール?}
    C -->|No| D[bailoutReasonを記録]
    C -->|Yes| E{bailout条件チェック}
    E -->|bailout| D
    E -->|OK| F[連結候補として登録]
    F --> G[HarmonyImport先を探索]
    G --> H{チャンク条件<br>一致?}
    H -->|No| I[候補から除外]
    H -->|Yes| J[連結グループに追加]
    J --> K[ConcatenatedModule生成]
    K --> L[ChunkGraph更新]
    L --> M[完了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | ESM限定 | ESMモジュール（HarmonyImport/Export使用）のみが連結対象 | 全モジュール |
| BR-02 | bailout条件 | eval使用、非strict、特定依存タイプ等は連結不可 | モジュール検査時 |
| BR-03 | チャンク一致 | 連結対象のモジュールは同じチャンクセットに属する必要がある | グループ構築時 |
| BR-04 | ランタイム条件 | ランタイムが異なるモジュールは連結不可 | グループ構築時 |
| BR-05 | cacheUnaffected非互換 | moduleMemCaches使用時はエラー（グローバル効果のため） | プラグイン適用時 |

### 計算ロジック

- bailout理由は`bailoutReasonMap`にモジュール→理由のマッピングとして記録
- 統計情報（Statistics型）で連結の成功/失敗理由別カウントを追跡

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | Error | cacheUnaffectedとの併用 | "optimization.concatenateModules can't be used with cacheUnaffected"エラー |
| - | OptimizationBailout | 連結不可の場合 | bailout理由をモジュールの最適化ログに記録 |

### リトライ仕様

該当なし

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

該当なし

## パフォーマンス要件

- STAGE_DEFAULTフェーズのoptimizeChunkModules（非同期）フックで実行
- 大規模プロジェクトでの連結候補の探索はneo-asyncライブラリで非同期処理

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

該当なし

## 備考

- バンドルサイズの削減効果はモジュール数に比例（各モジュールラッパーが不要になるため）
- Tree Shakingとの相乗効果が期待できる

---

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

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

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ModuleConcatenationPlugin.js | `lib/optimize/ModuleConcatenationPlugin.js` | 34-45行目: Statistics型定義（各種bailout理由のカウント） |

**読解のコツ**: Statistics型のフィールド名がbailout理由の種類を示す。cached, alreadyInConfig, invalidModule, incorrectChunks, incorrectDependency等。

#### Step 2: bailout判定ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ModuleConcatenationPlugin.js | `lib/optimize/ModuleConcatenationPlugin.js` | 77-105行目: setBailoutReason, setInnerBailoutReason, getInnerBailoutReason |
| 2-2 | ModuleConcatenationPlugin.js | `lib/optimize/ModuleConcatenationPlugin.js` | 112-136行目: formatBailoutWarning |

**主要処理フロー**:
1. **77-86行目**: setBailoutReasonでbailout理由をマップに記録し、最適化bailoutログに追加
2. **92-94行目**: setInnerBailoutReasonでマップへの記録のみ（ログには追加しない）
3. **101-105行目**: getInnerBailoutReasonで理由を取得（関数の場合はrequestShortenerで評価）

#### Step 3: メイン最適化ループを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ModuleConcatenationPlugin.js | `lib/optimize/ModuleConcatenationPlugin.js` | 138-150行目: optimizeChunkModulesフックの登録（STAGE_DEFAULT、非同期） |

**主要処理フロー**:
- **138-142行目**: optimizeChunkModules.tapAsyncでSTAGE_DEFAULTステージに登録
- **144-146行目**: ロガー取得、chunkGraphとmoduleGraphの参照取得
- **149行目以降**: relevantModules配列に連結可能なモジュールを収集

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

```
Compilation.hooks.optimizeChunkModules (STAGE_DEFAULT)
    |
    +-- ModuleConcatenationPlugin
            |
            +-- setBailoutReason(module, reason)
            +-- setInnerBailoutReason(module, reason)
            |
            +-- [モジュール連結可能性チェック]
            |       +-- ESMモジュール判定
            |       +-- bailout条件チェック
            |
            +-- [連結グループ構築]
            |       +-- HarmonyImportDependencyの辿り
            |       +-- チャンク条件検証
            |       +-- ランタイム条件検証
            |
            +-- new ConcatenatedModule(rootModule, modules)
            |
            +-- chunkGraph更新
                    +-- モジュール置換
```

### データフロー図

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

ESMモジュール群 ---------> bailout判定              +--> ConcatenatedModule
                               |                    |
ModuleGraph ------------> 連結グループ構築          +--> 更新されたChunkGraph
(HarmonyImport関係)            |                    |
                               v                    |
ChunkGraph ------------> ConcatenatedModule生成    +--> bailoutログ
(チャンク帰属情報)              |
                               v
                        ChunkGraph更新
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ModuleConcatenationPlugin.js | `lib/optimize/ModuleConcatenationPlugin.js` | ソース | メインプラグイン |
| ConcatenatedModule.js | `lib/optimize/ConcatenatedModule.js` | ソース | 結合モジュールの実装 |
| HarmonyImportDependency.js | `lib/dependencies/HarmonyImportDependency.js` | ソース | ESMインポート依存関係 |
| ChunkGraph.js | `lib/ChunkGraph.js` | ソース | チャンク-モジュール関連付け |
| ModuleGraph.js | `lib/ModuleGraph.js` | ソース | モジュール間依存グラフ |
| runtime.js | `lib/util/runtime.js` | ユーティリティ | ランタイム比較・マージ関数 |
| comparators.js | `lib/util/comparators.js` | ユーティリティ | モジュール比較関数 |
