# 機能設計書 36-遅延コンパイル

## 概要

本ドキュメントは、webpackにおけるlazy-compilation機能のクライアントサイドランタイムについて記述する。hot/lazy-compilation-web.jsおよびhot/lazy-compilation-node.jsが、リクエスト時に初めてモジュールをコンパイルすることで開発時のビルド速度を向上させる仕組みのクライアント側を担当する。

### 本機能の処理概要

遅延コンパイル（lazy compilation）は、エントリポイントや動的インポートされるモジュールのコンパイルを実際にリクエストされるまで遅延させる機能である。大規模プロジェクトにおいて、未使用モジュールのコンパイルを回避することで初期ビルド時間を大幅に短縮する。

**業務上の目的・背景**：大規模なWebアプリケーションでは数百〜数千のモジュールが存在するが、開発時にすべてのモジュールをコンパイルする必要はない。遅延コンパイルにより、ブラウザから実際にアクセスされたページ・ルートに必要なモジュールのみをオンデマンドでコンパイルすることで、開発サーバーの起動時間とリビルド時間を劇的に短縮する。

**機能の利用シーン**：experiments.lazyCompilationが有効な場合に使用される。開発者がブラウザで特定のページに遷移した際、そのページに必要なモジュールのコンパイルがトリガーされる。

**主要な処理内容**：
1. EventSource（ブラウザ）またはHTTPリクエスト（Node.js）でdev-serverに接続
2. アクティブモジュールのキー情報をサーバーに送信
3. モジュールのコンパイル完了をサーバーから受信
4. 参照カウントによるEventSource接続の管理
5. URL更新機能

**関連システム・外部連携**：webpack-dev-server（Server-Sent Events経由）。EventSource API（ブラウザ）またはhttp/httpsモジュール（Node.js）を使用。

**権限による制御**：experiments.lazyCompilation設定により機能の有効/無効が制御される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 該当なし | - | 遅延コンパイルは開発時のインフラ機能であり、特定の画面に直接関連しない |

## 機能種別

開発ツール / ランタイムクライアント

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| __resourceQuery | string | Yes | dev-serverの接続先URL（ビルド時に注入） | URLデコードして使用 |
| options.data | string | Yes | モジュール識別キー | keepAliveのパラメータ |
| options.onError | function | Yes | エラーハンドラ関数 | keepAliveのパラメータ |
| options.active | boolean | Yes | モジュールがアクティブかどうか | keepAliveのパラメータ |
| options.module | module | Yes | HMR対応確認用のモジュールオブジェクト | keepAliveのパラメータ |

### 入力データソース

- webpackビルド時に__resourceQueryとして注入される開発サーバーURL
- ランタイムモジュールから渡されるkeepAliveオプション

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| destroyFunction | function | EventSource接続を切断するためのクリーンアップ関数 |
| コンソールログ | string | HMR未有効時の警告メッセージ |

### 出力先

EventSource接続（ブラウザ）またはHTTPリクエスト（Node.js）でdev-serverに通信。

## 処理フロー

### 処理シーケンス

```
1. URL初期化
   └─ __resourceQueryからdev-serverのURLベースを取得
2. keepAlive呼び出し
   └─ モジュールのアクティブ状態をサーバーに通知
3. EventSource接続管理
   ├─ 参照カウント（activeKeys Map）の更新
   └─ 参照カウントが0→1時にEventSource接続開始
4. コンパイルトリガー
   └─ サーバーがモジュールのコンパイルを開始
5. 接続切断
   ├─ 1秒の遅延後に参照カウントをデクリメント
   └─ 参照カウントが0になったらEventSource接続終了
```

### フローチャート

```mermaid
flowchart TD
    A[keepAlive呼び出し] --> B[errorHandlers.add]
    B --> C[activeKeys.get]
    C --> D{value === 0?}
    D -->|Yes| E[updateEventSource]
    E --> F[EventSource接続開始]
    D -->|No| G[参照カウント増加]
    F --> H{active && module.hot?}
    G --> H
    H -->|No| I[HMR未有効警告]
    H -->|Yes| J[正常動作]
    J --> K[destroy関数返却]
    K --> L[destroy呼び出し時]
    L --> M[1秒遅延]
    M --> N{参照カウント === 1?}
    N -->|Yes| O[activeKeys.delete + EventSource切断]
    N -->|No| P[参照カウント減少]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | EventSource必須 | ブラウザ版はEventSource未対応環境でエラーをスロー | lazy-compilation-web.js起動時 |
| BR-02 | 参照カウント管理 | activeKeysのMapで各モジュールキーの参照カウントを管理し、0になったら接続切断 | keepAlive/destroy時 |
| BR-03 | 遅延切断 | destroy時に1秒の遅延を設け、即座の再接続を回避 | destroy関数実行時 |
| BR-04 | キー結合 | 複数のアクティブキーは"@"で連結してサーバーに送信 | updateEventSource時 |
| BR-05 | HMR警告 | module.hotが未定義かつactiveでない場合、HMR未有効の警告をコンソールに出力 | keepAlive時 |

### 計算ロジック

EventSource URLの構築: urlBase + Array.from(activeKeys.keys()).join("@") で全アクティブモジュールキーを"@"区切りで連結しURLに付加する。

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

### 操作別データベース影響一覧

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | Error | EventSource未対応環境（lazy-compilation-web.js） | "Environment doesn't support lazy compilation (requires EventSource)"スロー |
| - | Error | EventSourceのonerror | 登録済みのerrorHandlersに通知 |
| - | Error | HTTPリクエストエラー（lazy-compilation-node.js） | onErrorコールバックに通知 |

### リトライ仕様

EventSourceは内部的に自動再接続を行う。HTTPリクエスト方式では手動のリトライは実装されていない。

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

該当なし

## パフォーマンス要件

- 初期ビルド時間の大幅短縮（必要なモジュールのみコンパイル）
- EventSourceのServer-Sent Eventsによるリアルタイム通知

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

- 開発環境専用の機能であり、本番環境では使用しないこと
- EventSource接続はdev-serverへのHTTP接続であり、ネットワークセキュリティに注意

## 備考

- lazy-compilation-universal.jsはブラウザ/Node.js両対応のユニバーサル版
- setUrl()関数でランタイム中にURLベースを変更可能

---

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

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

### 推奨読解順序

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

遅延コンパイルクライアントのデータ管理構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | lazy-compilation-web.js | `hot/lazy-compilation-web.js` | 11-15行目: urlBase, activeEventSource, activeKeys(Map), errorHandlers(Set)の初期化 |

**読解のコツ**: activeKeysは`Map<string, number>`として機能し、キーはモジュール識別子、値は参照カウントである。参照カウントが0になるとEventSource接続が切断される。

#### Step 2: ブラウザ版クライアントを理解する

lazy-compilation-web.jsのkeepAlive/updateEventSource/setUrlを読み解く。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | lazy-compilation-web.js | `hot/lazy-compilation-web.js` | 5-9行目: EventSource存在チェック |
| 2-2 | lazy-compilation-web.js | `hot/lazy-compilation-web.js` | 17-48行目: updateEventSource関数 |
| 2-3 | lazy-compilation-web.js | `hot/lazy-compilation-web.js` | 54-86行目: keepAlive関数 |
| 2-4 | lazy-compilation-web.js | `hot/lazy-compilation-web.js` | 91-93行目: setUrl関数 |

**主要処理フロー**:
- **5-8行目**: EventSourceが未定義の場合エラースロー
- **11行目**: __resourceQueryからURLベースをデコード
- **17-48行目**: updateEventSourceで既存接続を閉じ、アクティブキーがあれば新規接続
- **21-22行目**: URLベース + キー連結("@"区切り)でEventSource接続
- **54-86行目**: keepAliveで参照カウント管理・接続開始・destroy関数返却
- **76-84行目**: destroy関数で1秒遅延後に参照カウントデクリメント

#### Step 3: Node.js版クライアントを理解する

lazy-compilation-node.jsのHTTPベースの実装を読み解く。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | lazy-compilation-node.js | `hot/lazy-compilation-node.js` | 11-66行目: keepAlive関数（HTTPリクエスト方式） |

**主要処理フロー**:
- **24行目**: load-http.jsでhttp/httpsモジュールを遅延読み込み
- **31-48行目**: HTTPリクエストをtext/event-streamヘッダで送信
- **54-58行目**: destroy関数でレスポンスをdestroy

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

```
lazy-compilation-web.js (ブラウザ)
    |
    +-- exports.keepAlive(options)
    |      +-- errorHandlers.add(onError)
    |      +-- activeKeys.set(data, count+1)
    |      +-- updateEventSource()
    |      |      +-- EventSource(urlBase + keys)
    |      |      +-- onerror → errorHandlers通知
    |      +-- return destroy()
    |             +-- setTimeout(1000)
    |             +-- activeKeys.delete/decrement
    |             +-- updateEventSource()
    |
    +-- exports.setUrl(value)

lazy-compilation-node.js (Node.js)
    +-- exports.keepAlive(options)
    |      +-- load-http → http/https
    |      +-- client.request(url, headers)
    |      +-- return destroy()
    |             +-- response.destroy()
    +-- exports.setUrl(value)
```

### データフロー図

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

__resourceQuery ──────────> URL初期化
                               |
keepAlive(options) ────────> activeKeys更新            ──> EventSource接続
  data: モジュールキー          |                           (dev-server通知)
  onError: エラーハンドラ       +-> updateEventSource()
                               |
destroy() ─────────────────> activeKeys減少            ──> EventSource切断
                               +-> updateEventSource()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| lazy-compilation-web.js | `hot/lazy-compilation-web.js` | ランタイム | ブラウザ環境用のlazy compilationクライアント |
| lazy-compilation-node.js | `hot/lazy-compilation-node.js` | ランタイム | Node.js環境用のlazy compilationクライアント |
| lazy-compilation-universal.js | `hot/lazy-compilation-universal.js` | ランタイム | ユニバーサル版のlazy compilationクライアント |
| load-http.js | `hot/load-http.js` | ランタイム | HTTPモジュールの遅延読み込みヘルパー |
