# 機能設計書 15-Tree Shaking

## 概要

本ドキュメントは、webpackのTree Shaking機能について、SideEffectsFlagPlugin / FlagDependencyUsagePlugin / FlagDependencyExportsPluginによる未使用エクスポート除去の設計と実装の詳細を記述する。

### 本機能の処理概要

Tree Shakingは、ES Module形式のエクスポートのうち、実際に使用されていないものを検出し、バンドルから除去する最適化機能である。3つのプラグインが連携して動作する。

**業務上の目的・背景**：大規模なライブラリ（lodash、date-fns等）をインポートする場合、全機能をバンドルに含めるとファイルサイズが不必要に増大する。Tree Shakingにより、実際に使用する関数やクラスのみをバンドルに含め、未使用コードを自動的に除去することで、プロダクションバンドルのサイズを大幅に削減できる。

**機能の利用シーン**：プロダクションビルドでの未使用コード除去、ライブラリの部分インポート最適化、コンポーネントライブラリからの必要コンポーネントのみの抽出、re-exportパターンにおける不要エクスポートの除去。

**主要な処理内容**：
1. **FlagDependencyExportsPlugin**: モジュールの提供エクスポート情報を収集・フラグ付け
2. **FlagDependencyUsagePlugin**: エクスポートの使用状況を追跡し、各エクスポートの使用状態を記録
3. **SideEffectsFlagPlugin**: package.jsonのsideEffectsフィールドとソースコード解析に基づき副作用フラグを設定

**関連システム・外部連携**：ExportsInfo、ModuleGraph、JavascriptParser、HarmonyExportImportedSpecifierDependency、HarmonyImportSpecifierDependencyと連携する。

**権限による制御**：optimization.usedExports、optimization.sideEffects設定で制御。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 10 | Login (reexport-components) | 主機能 | Button,Dialogのみインポートし、未使用のCheckbox等を除去 |
| 11 | Dashboard (reexport-components) | 主機能 | Button,Checkboxのみインポートし、未使用のDialog等を除去 |

## 機能種別

最適化処理 / デッドコード除去

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| optimization.usedExports | `boolean \| "global"` | No | 使用エクスポートのフラグ付けを有効化 | デフォルト: productionでtrue |
| optimization.sideEffects | `boolean` | No | sideEffectsフラグの認識を有効化 | デフォルト: productionでtrue |
| package.json sideEffects | `boolean \| string[]` | No | パッケージの副作用宣言 | glob形式のパターン配列対応 |

### 入力データソース

- Compilationのモジュールグラフ（インポート/エクスポート関係）
- package.jsonのsideEffectsフィールド
- ソースコードのAST解析結果

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| ExportsInfo | `ExportsInfo` | 各エクスポートの使用状態（Used/Unused/OnlyPropertiesUsed） |
| sideEffectsフラグ | `boolean` | モジュールの副作用有無フラグ |

### 出力先

ModuleGraphのExportsInfo、モジュールのbuildMeta

## 処理フロー

### 処理シーケンス

```
1. FlagDependencyExportsPlugin (finishModulesフェーズ)
   └─ 全モジュールのエクスポート情報を収集し、提供されるエクスポートをフラグ付け
2. SideEffectsFlagPlugin (moduleフック + optimizeDependenciesフック)
   └─ package.jsonのsideEffectsとソースコード解析で副作用フラグを設定
3. FlagDependencyUsagePlugin (optimizeDependenciesフェーズ)
   └─ エントリポイントから辿り、各エクスポートの使用状態を記録
4. コード生成時
   └─ 未使用エクスポートはコード生成から除外
```

### フローチャート

```mermaid
flowchart TD
    A[finishModules] --> B[FlagDependencyExportsPlugin]
    B --> C[全モジュールのエクスポート情報収集]
    C --> D[optimizeDependencies]
    D --> E[SideEffectsFlagPlugin]
    E --> F{sideEffects<br>フラグ確認}
    F -->|false| G[副作用なしとマーク]
    F -->|true/未設定| H[副作用ありとマーク]
    G --> I[FlagDependencyUsagePlugin]
    H --> I
    I --> J[エントリポイントから使用追跡]
    J --> K{エクスポート<br>使用?}
    K -->|Yes| L[UsageState.Used]
    K -->|No| M[UsageState.Unused]
    L --> N[コード生成]
    M --> N
    N --> O[未使用コード除外]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | ESM限定 | Tree ShakingはES Module形式（import/export）でのみ有効 | モジュール形式判定時 |
| BR-02 | sideEffectsフラグ | package.jsonのsideEffects: falseでモジュール全体のスキップが可能 | パッケージに設定時 |
| BR-03 | glob形式サポート | sideEffects: ["*.css"]のようにglob形式で副作用ファイルを指定可能 | パッケージに設定時 |
| BR-04 | 使用状態の伝播 | エクスポートの使用状態はインポートチェーンを通じて伝播する | 依存関係追跡時 |
| BR-05 | グローバルモード | usedExports: "global"でランタイムごとではなくグローバルに使用状態を追跡 | 設定時 |

### 計算ロジック

- **UsageState**: Unused(0), OnlyPropertiesUsed(1), NoInfo(2), Unknown(3), Used(4)の5段階
- **副作用判定**: (1) package.jsonのsideEffects (2) ソースコードのAST解析 の2段階で判定

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | Error | cacheUnaffectedとの併用（FlagDependencyUsagePlugin） | "optimization.usedExports can't be used with cacheUnaffected"エラー |

### リトライ仕様

該当なし

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

該当なし

## パフォーマンス要件

- FlagDependencyExportsPluginはfinishModulesフェーズで非同期実行
- FlagDependencyUsagePluginはTupleQueueによる幅優先探索で効率的に使用状態を追跡
- キャッシュによりリビルド時の再計算を最小化

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

該当なし

## 備考

- CommonJS形式のモジュールはTree Shakingの対象外（動的なexportsアクセスのため）
- sideEffects: falseの宣言が不正確な場合、必要なコードが除去される可能性がある
- InnerGraph解析（No.16）との連携でより精密な除去が可能

---

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

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

### 推奨読解順序

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

エクスポート情報のデータモデルを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ExportsInfo.js | `lib/ExportsInfo.js` | ExportsInfo, ExportInfo クラスとUsageState列挙型 |

**読解のコツ**: UsageStateの値（Unused=0, OnlyPropertiesUsed=1, NoInfo=2, Unknown=3, Used=4）を把握すること。数値が大きいほど「使用されている可能性が高い」。

#### Step 2: エクスポート情報の収集を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | FlagDependencyExportsPlugin.js | `lib/FlagDependencyExportsPlugin.js` | 31-80行目: finishModulesフックでのエクスポート情報収集 |

**主要処理フロー**:
1. **35-37行目**: finishModules.tapAsyncで非同期フックに登録
2. **48-49行目**: Queueでモジュールを順次処理
3. **51-53行目**: exportsTypeがないモジュールはsetUnknownExportsProvided()
4. **72-79行目**: キャッシュ不可のモジュールはキューに追加

#### Step 3: 使用状態の追跡を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | FlagDependencyUsagePlugin.js | `lib/FlagDependencyUsagePlugin.js` | 29-80行目: optimizeDependenciesフックでの使用追跡 |

**主要処理フロー**:
1. **33-36行目**: globalフラグでランタイムごとorグローバル追跡を選択
2. **46-48行目**: optimizeDependencies.tapでSTAGE_DEFAULTに登録
3. **59-60行目**: TupleQueueでモジュールとランタイムのペアを管理
4. **69-80行目**: processReferencedModuleで参照されたモジュールの使用状態を更新

#### Step 4: 副作用フラグの設定を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | SideEffectsFlagPlugin.js | `lib/optimize/SideEffectsFlagPlugin.js` | 66-100行目: moduleフックでのpackage.json sideEffects読み取り |

**主要処理フロー**:
- **81-85行目**: cache初期化とcompiler.hooksへの登録
- **90-100行目**: normalModuleFactory.hooks.moduleでresolveDataからsideEffectsフィールドを取得
- **51-62行目**: globToRegexpでsideEffectsのglob形式パターンをRegExpに変換

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

```
Compilation
    |
    +-- hooks.finishModules
    |       +-- FlagDependencyExportsPlugin
    |               +-- exportsInfo.setHasProvideInfo()
    |               +-- exportsInfo.setUnknownExportsProvided()
    |
    +-- hooks.optimizeDependencies (STAGE_DEFAULT)
    |       +-- SideEffectsFlagPlugin
    |       |       +-- module.factoryMeta.sideEffectFree = true/false
    |       |
    |       +-- FlagDependencyUsagePlugin
    |               +-- processReferencedModule(module, usedExports, runtime)
    |               +-- exportsInfo.setUsedWithoutInfo(runtime)
    |               +-- exportsInfo.setUsedInUnknownWay(runtime)
    |
    +-- normalModuleFactory.hooks.module
            +-- SideEffectsFlagPlugin (package.json sideEffects読み取り)
```

### データフロー図

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

package.json sideEffects --> SideEffectsFlagPlugin         +--> module.factoryMeta.sideEffectFree
                                  |                         |
モジュールのexport文 -------> FlagDependencyExportsPlugin  +--> ExportsInfo (provided flags)
                                  |                         |
エントリからのimport -------> FlagDependencyUsagePlugin    +--> ExportsInfo (usage flags)
チェーン                          |                         |
                                  v                         |
                            コード生成                     +--> 未使用エクスポート除外
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| SideEffectsFlagPlugin.js | `lib/optimize/SideEffectsFlagPlugin.js` | ソース | 副作用フラグ設定 |
| FlagDependencyUsagePlugin.js | `lib/FlagDependencyUsagePlugin.js` | ソース | エクスポート使用状態追跡 |
| FlagDependencyExportsPlugin.js | `lib/FlagDependencyExportsPlugin.js` | ソース | エクスポート情報収集 |
| ExportsInfo.js | `lib/ExportsInfo.js` | ソース | エクスポート情報データモデル |
| ModuleGraph.js | `lib/ModuleGraph.js` | ソース | モジュール間依存グラフ |
| HarmonyExportImportedSpecifierDependency.js | `lib/dependencies/HarmonyExportImportedSpecifierDependency.js` | ソース | re-exportの依存関係 |
| HarmonyImportSpecifierDependency.js | `lib/dependencies/HarmonyImportSpecifierDependency.js` | ソース | インポート指定子の依存関係 |
