# 機能設計書 46-CommonJSチャンクローディング

## 概要

本ドキュメントは、Node.js環境向けのCommonJS方式チャンク読み込み機能について、CommonJsChunkLoadingPlugin、RequireChunkLoadingRuntimeModule、ReadFileChunkLoadingRuntimeModuleを中心に設計内容を記述する。

### 本機能の処理概要

本機能は、Node.js環境においてrequire()またはfs.readFile()方式でチャンクを読み込むランタイムコードを生成する。同期方式(require)と非同期方式(readFile)の2つのモードをサポートする。

**業務上の目的・背景**：SSR(Server-Side Rendering)やNode.jsアプリケーションのバンドルでは、ブラウザのscriptタグは利用できない。代わりにNode.jsのrequire()やfs.readFile()を使用してチャンクを読み込む必要がある。

**機能の利用シーン**：webpack設定の`output.chunkLoading`が`require`(同期)または`async-node`(非同期)の場合に使用される。Node.jsターゲットのビルドで自動的に選択される。

**主要な処理内容**：
1. CommonJsChunkLoadingPlugin: asyncChunkLoadingオプションに基づきrequire方式またはreadFile方式を選択
2. RequireChunkLoadingRuntimeModule: require()による同期チャンク読み込みコード生成
3. ReadFileChunkLoadingRuntimeModule: fs.readFile()による非同期チャンク読み込みコード生成
4. installChunk関数によるモジュールファクトリ登録

**関連システム・外部連携**：StartupChunkDependenciesPlugin(起動チャンク依存関係)、EnsureChunkRuntimeModule

**権限による制御**：ファイルシステムの読み取り権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 画面との直接的な関連なし（Node.js環境向け内部機構） |

## 機能種別

ランタイムコード生成

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| chunkId | ChunkId | Yes | 読み込むチャンクのID | - |
| promises | Promise[] | Yes | チャンク読み込みPromiseの配列 | - |
| asyncChunkLoading | boolean | No | 非同期チャンク読み込みを使用するか | - |

### 入力データソース

- __webpack_require__.e(chunkId)経由のチャンク読み込みリクエスト

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| ランタイムコード | string | require/readFile読み込みのJavaScriptランタイムコード |
| installedChunks | object | チャンク状態管理オブジェクト |

### 出力先

- webpackランタイムバンドル内

## 処理フロー

### 処理シーケンス

```
1. CommonJsChunkLoadingPlugin.apply()
   └─ asyncChunkLoading ? ReadFileChunkLoadingRuntimeModule : RequireChunkLoadingRuntimeModule を選択
   └─ StartupChunkDependenciesPlugin を適用

2. [require方式] RequireChunkLoadingRuntimeModule.generate()
   └─ installedChunks初期化 (1 = loaded)
   └─ installChunk関数: modules/ids/runtime受信・登録
   └─ ensureChunkHandlers.require: require(path + filename)で同期読み込み

3. [readFile方式] ReadFileChunkLoadingRuntimeModule.generate()
   └─ installedChunks初期化 (1 = loaded)
   └─ installChunk関数: modules/ids/runtime受信・登録
   └─ ensureChunkHandlers.readFileVm: fs.readFile + vm.runInThisContextで非同期読み込み
```

### フローチャート

```mermaid
flowchart TD
    A[CommonJsChunkLoadingPlugin] --> B{asyncChunkLoading?}
    B -->|true| C[ReadFileChunkLoadingRuntimeModule]
    B -->|false| D[RequireChunkLoadingRuntimeModule]
    C --> E[fs.readFile + vm.runInThisContext]
    D --> F[require でチャンク読み込み]
    F --> G[installChunk]
    E --> G
    G --> H[moduleFactoriesにモジュール登録]
    H --> I[installedChunks更新]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-46-01 | 同期読み込み | require方式では同期的にチャンクを読み込み実行 | asyncChunkLoading=false |
| BR-46-02 | 非同期読み込み | readFile方式ではPromiseベースで非同期読み込み | asyncChunkLoading=true |
| BR-46-03 | チャンク状態 | 1=loaded, それ以外=未ロード | 常時 |
| BR-46-04 | 外部インストール | externalInstallChunkで外部からのチャンクインストールをサポート | 該当設定時 |

### 計算ロジック

- ルートパス算出: `getUndoPath(outputName, outputOptions.path, true)` で出力ファイルからルートへの相対パスを算出

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| MODULE_NOT_FOUND | Error | HMRマニフェストファイルが存在しない | 更新なしとして処理 |
| ENOENT | Error | HMRマニフェストファイルが存在しない | 更新なしとして処理 |

### リトライ仕様

リトライは行わない。

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

該当なし

## パフォーマンス要件

- require方式は同期実行のため、Node.jsのイベントループをブロックする
- readFile方式は非同期で、イベントループをブロックしない

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

- readFile方式ではvm.runInThisContextでコードを実行するため、信頼できるチャンクのみ読み込むこと

## 備考

- chunkLoading値: "require"(同期), "async-node"(非同期)
- baseURIはurl.pathToFileURL()で生成

---

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

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

### 推奨読解順序

#### Step 1: プラグイン選択ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | CommonJsChunkLoadingPlugin.js | `lib/node/CommonJsChunkLoadingPlugin.js` | **37-42行目**: asyncChunkLoadingに基づくRuntimeModule選択 |

#### Step 2: 同期方式(require)を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | RequireChunkLoadingRuntimeModule.js | `lib/node/RequireChunkLoadingRuntimeModule.js` | **60-236行目**: generate()メソッド全体 |
| 2-2 | RequireChunkLoadingRuntimeModule.js | `lib/node/RequireChunkLoadingRuntimeModule.js` | **129-146行目**: installChunk関数 |
| 2-3 | RequireChunkLoadingRuntimeModule.js | `lib/node/RequireChunkLoadingRuntimeModule.js` | **148-181行目**: ensureChunkHandlers.require |

**主要処理フロー**:
- **164行目**: `require(rootOutputDir + getChunkScriptFilename(chunkId))` で同期読み込み
- **169-171行目**: installedChunksが未設定の場合installChunk呼び出し

#### Step 3: 非同期方式(readFile)を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ReadFileChunkLoadingRuntimeModule.js | `lib/node/ReadFileChunkLoadingRuntimeModule.js` | **60行目以降**: generate()メソッド |

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

```
CommonJsChunkLoadingPlugin.apply(compiler)
    |
    +-- StartupChunkDependenciesPlugin.apply(compiler)
    |
    +-- compilation.hooks.runtimeRequirementInTree
            +-- handler()
                    +-- compilation.addRuntimeModule(ChunkLoadingRuntimeModule)
                            |
                            +-- [require方式] RequireChunkLoadingRuntimeModule.generate()
                            |       +-- installChunk()
                            |       +-- ensureChunkHandlers.require
                            |
                            +-- [readFile方式] ReadFileChunkLoadingRuntimeModule.generate()
                                    +-- installChunk()
                                    +-- ensureChunkHandlers.readFileVm
```

### データフロー図

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

chunkId         ───▶  [require方式]                    ───▶  モジュールファクトリ
                      require(path + filename)                 installedChunks更新
                      installChunk(chunk)

chunkId         ───▶  [readFile方式]                   ───▶  モジュールファクトリ
                      fs.readFile(path + filename)             installedChunks更新
                      vm.runInThisContext(content)
                      installChunk(chunk)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| CommonJsChunkLoadingPlugin.js | `lib/node/CommonJsChunkLoadingPlugin.js` | ソース | プラグイン登録・方式選択 |
| RequireChunkLoadingRuntimeModule.js | `lib/node/RequireChunkLoadingRuntimeModule.js` | ソース | require方式ランタイムコード生成 |
| ReadFileChunkLoadingRuntimeModule.js | `lib/node/ReadFileChunkLoadingRuntimeModule.js` | ソース | readFile方式ランタイムコード生成 |
| StartupChunkDependenciesPlugin.js | `lib/runtime/StartupChunkDependenciesPlugin.js` | ソース | 起動チャンク依存関係プラグイン |
