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

## 概要

本ドキュメントは、webpackにおけるCSSチャンクの動的読み込みランタイムコード生成機能について記述する。CssLoadingRuntimeModuleクラスが、ブラウザ環境でCSSチャンクを動的にロードするためのランタイムJavaScriptコードを生成する仕組みを定義する。

### 本機能の処理概要

CSSチャンクローディングは、webpackのコード分割（code splitting）においてCSSファイルをチャンク単位で動的に読み込むためのランタイムコードを生成する機能である。

**業務上の目的・背景**：Webアプリケーションにおいて、CSSファイルをJavaScriptチャンクと同様に動的に読み込む必要がある。ページ遷移や遅延読み込みの際に、対応するCSSスタイルシートを必要なタイミングで読み込むことで、初期ロードのパフォーマンスを向上させる。また、Hot Module Replacement（HMR）時にはCSSの差分更新も行う必要がある。

**機能の利用シーン**：CSSを含むチャンクが動的インポート（import()）により遅延読み込みされる場面で利用される。また、preload/prefetchによるCSSの事前読み込みや、HMR開発時のCSS更新時にも使用される。

**主要な処理内容**：
1. CSSチャンクの読み込み状態管理（installedChunks）のランタイムコード生成
2. link要素を生成しDOMに挿入するloadStylesheet関数の生成
3. チャンク読み込みのPromiseベースの非同期処理コード生成
4. prefetch/preloadによる事前読み込みコードの生成
5. HMR時のCSS差分更新コード生成

**関連システム・外部連携**：ブラウザのDOM API（document.createElement('link')）を利用してスタイルシートを動的に挿入する。CssModulesPlugin（lib/css/CssModulesPlugin.js）と連携し、CSSチャンクの有無を判定する。

**権限による制御**：特になし。ランタイムコードはビルド時に生成され、ブラウザ上で実行される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 該当なし | - | CSSチャンクローディングは画面に直接関連せず、ランタイムインフラとして全画面から間接的に利用される |

## 機能種別

ランタイムコード生成 / チャンクローディング

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| runtimeRequirements | ReadOnlyRuntimeRequirements (Set) | Yes | ランタイムに必要な機能要件のセット | ensureChunkHandlers, hmrDownloadUpdateHandlers等のRuntimeGlobals定数を含むか判定 |
| crossOriginLoading | string \| false | No | CORSの設定値 | "use-credentials" または文字列 |
| uniqueName | string | No | ビルドの一意名 | data-webpack属性に使用 |
| chunkLoadTimeout | number | No | チャンク読み込みのタイムアウト（ms） | 数値 |
| charset | boolean | No | charsetをlinkタグに設定するか | ブール値 |

### 入力データソース

- Compilationオブジェクトから取得するoutputOptions（crossOriginLoading, uniqueName, chunkLoadTimeout, charset）
- ChunkGraphから取得するCSSチャンクの有無判定情報（conditionMap）
- 初期チャンクのID一覧（chunk.getAllInitialChunks()）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| runtimeCode | string \| null | ブラウザで実行されるCSSチャンク読み込みのJavaScriptランタイムコード |

### 出力先

バンドルファイル内のランタイムコードとして出力される。ブラウザのJavaScriptランタイムで実行され、link要素をDOMに挿入する。

## 処理フロー

### 処理シーケンス

```
1. ランタイム要件の確認
   └─ ensureChunkHandlers / hmrDownloadUpdateHandlers の有無を判定
2. CSSチャンク条件マップの生成
   └─ chunkGraph.getChunkConditionMapでCSSを含むチャンクを特定
3. 初期チャンクIDの収集
   └─ getAllInitialChunks()からCSSを持つチャンクのIDをSetに格納
4. installedChunksオブジェクトの生成
   └─ 初期チャンクID: 0（読み込み済み）のマッピング生成
5. loadStylesheet関数の生成
   └─ link要素の生成・属性設定・DOM挿入・イベントハンドラ設定
6. ensureChunkHandlers.cssの生成（withLoading時）
   └─ Promise制御によるCSS非同期読み込みコード
7. prefetch/preloadハンドラの生成（必要時）
   └─ rel="prefetch"/"preload"のlink要素生成
8. HMRハンドラの生成（withHmr時）
   └─ CSS差分更新のためのスタイルシート差し替えコード
```

### フローチャート

```mermaid
flowchart TD
    A[generate開始] --> B{withLoading or withHmr?}
    B -->|No| C[null返却]
    B -->|Yes| D[installedChunks初期化コード生成]
    D --> E[loadStylesheet関数生成]
    E --> F{withLoading?}
    F -->|Yes| G[ensureChunkHandlers.css生成]
    F -->|No| H[チャンク読み込みスキップ]
    G --> I{withPrefetch?}
    H --> I
    I -->|Yes| J[prefetchハンドラ生成]
    I -->|No| K{withPreload?}
    J --> K
    K -->|Yes| L[preloadハンドラ生成]
    K -->|No| M{withHmr?}
    L --> M
    M -->|Yes| N[HMR更新ハンドラ生成]
    M -->|No| O[ランタイムコード返却]
    N --> O
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | チャンク状態管理 | undefined=未読み込み, null=preloaded/prefetched, [resolve,reject,Promise]=読み込み中, 0=読み込み済み | 常時 |
| BR-02 | 既存スタイルシート検出 | 同一URLまたはdata-webpack属性で既存linkタグを検索し、重複読み込みを防止 | loadStylesheet実行時 |
| BR-03 | タイムアウト処理 | chunkLoadTimeoutミリ秒後にタイムアウトイベントを発火 | CSS読み込み待ち時 |
| BR-04 | CORS設定 | crossOriginLoadingが"use-credentials"の場合は無条件設定、それ以外は異なるオリジンの場合のみ設定 | クロスオリジンCSS読み込み時 |
| BR-05 | HMR差分判定 | cssTextKeyで旧タグと新タグのCSSテキストを比較し、変更がない場合は更新をスキップ | HMR更新時 |

### 計算ロジック

hasCssMatcher: chunkGraph.getChunkConditionMapから生成されるブールマッチャーで、chunkIdがCSSを含むかどうかを判定する。compileBooleanMatcherにより最適化されたJavaScriptコードに変換される。

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

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

該当なし（ブラウザランタイムコード生成のためDB操作は存在しない）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| ChunkLoadError | ランタイムエラー | CSSチャンクの読み込みに失敗（ネットワークエラー等） | error.type, error.requestにエラー詳細を設定し、Promiseをrejectする |
| timeout | ランタイムエラー | chunkLoadTimeout時間内にCSSが読み込まれない | link要素をDOMから削除し、doneコールバックにtypeイベントを渡す |
| TypeError | ビルド時エラー | compilationがCompilationインスタンスでない場合 | getCompilationHooksでTypeErrorをスロー |

### リトライ仕様

ランタイムレベルでのリトライ機能は実装されていない。エラー時はPromiseがrejectされ、上位の呼び出し元が処理する。

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

該当なし（DOM操作のためトランザクション管理は存在しない）

## パフォーマンス要件

- CSSチャンクの読み込みはchunkLoadTimeoutで制御される（デフォルト値はwebpack設定による）
- prefetch/preloadによる事前読み込みで体感パフォーマンスを向上
- installedChunksによるキャッシュで重複読み込みを防止

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

- CSP（Content Security Policy）対応: scriptNonceが設定されている場合、link要素にnonce属性を付与
- CORS対応: crossOriginLoading設定に基づき、crossOrigin属性を適切に設定
- data-webpack属性によるlink要素の識別で、不正な要素との混同を防止

## 備考

- プラットフォーム中立モード（isNeutralPlatform）では、document未定義環境への対応コードが生成される
- SyncWaterfallHookにより、createStylesheet / linkPreload / linkPrefetchのカスタマイズが可能
- webpack 6でのAPI変更の可能性あり

---

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

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

### 推奨読解順序

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

CssLoadingRuntimeModuleが使用するデータ構造とフック定義を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | CssLoadingRuntimeModule.js | `lib/css/CssLoadingRuntimeModule.js` | 22-27行目: CssLoadingRuntimeModulePluginHooksの型定義（createStylesheet, linkPreload, linkPrefetchの3フック） |
| 1-2 | RuntimeGlobals.js | `lib/RuntimeGlobals.js` | ensureChunkHandlers, hmrDownloadUpdateHandlers, prefetchChunkHandlers等のランタイムグローバル定数 |
| 1-3 | RuntimeModule.js | `lib/RuntimeModule.js` | RuntimeModuleの基底クラス構造 |

**読解のコツ**: CssLoadingRuntimeModuleはRuntimeModuleを継承しており、generate()メソッドがランタイムコードの文字列を返す。Template.asStringでJavaScriptコードを組み立てるパターンを理解すること。

#### Step 2: エントリーポイントを理解する

CssLoadingRuntimeModuleのライフサイクルを追う。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | CssModulesPlugin.js | `lib/css/CssModulesPlugin.js` | CssLoadingRuntimeModuleのインスタンス化と登録処理 |
| 2-2 | CssLoadingRuntimeModule.js | `lib/css/CssLoadingRuntimeModule.js` | 58-61行目: コンストラクタでruntimeRequirementsを受け取る |

**主要処理フロー**:
1. **37-53行目**: getCompilationHooksでコンパイレーション固有のフックを取得・初期化
2. **58-61行目**: コンストラクタでランタイム要件を保持
3. **67-510行目**: generate()でランタイムJavaScriptコード全体を生成

#### Step 3: ランタイムコード生成を理解する

generate()メソッドの内部処理を段階的に読み解く。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | CssLoadingRuntimeModule.js | `lib/css/CssLoadingRuntimeModule.js` | 82-92行目: conditionMapとhasCssMatcherの生成 |
| 3-2 | CssLoadingRuntimeModule.js | `lib/css/CssLoadingRuntimeModule.js` | 94-111行目: withLoading/withHmrフラグの判定と初期チャンクID収集 |
| 3-3 | CssLoadingRuntimeModule.js | `lib/css/CssLoadingRuntimeModule.js` | 138-172行目: link要素生成コードの構築 |
| 3-4 | CssLoadingRuntimeModule.js | `lib/css/CssLoadingRuntimeModule.js` | 196-252行目: loadStylesheet関数のランタイムコード生成 |
| 3-5 | CssLoadingRuntimeModule.js | `lib/css/CssLoadingRuntimeModule.js` | 254-334行目: ensureChunkHandlers.cssの非同期読み込みコード |
| 3-6 | CssLoadingRuntimeModule.js | `lib/css/CssLoadingRuntimeModule.js` | 424-508行目: HMR更新ハンドラのコード生成 |

**主要処理フロー**:
- **82-92行目**: ChunkGraphからCSSチャンクの条件マップを生成し、compileBooleanMatcherで最適化
- **138-172行目**: link要素の属性設定（charset, nonce, data-webpack, fetchpriority, rel, href, crossOrigin）
- **226-236行目**: onLinkCompleteハンドラ（onerror/onload/timeoutの統一処理）
- **274-277行目**: Promise生成とinstalledChunksへの格納
- **445-451行目**: cssTextKeyによるCSS内容の比較関数

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

```
CssModulesPlugin
    |
    +-- CssLoadingRuntimeModule (インスタンス化)
           |
           +-- generate()
                  |
                  +-- chunkGraph.getChunkConditionMap()
                  |
                  +-- compileBooleanMatcher()
                  |
                  +-- chunk.getAllInitialChunks()
                  |
                  +-- chunkHasCss() [CssModulesPlugin]
                  |
                  +-- CssLoadingRuntimeModule.getCompilationHooks()
                  |      |
                  |      +-- createStylesheet.call()
                  |      +-- linkPreload.call()
                  |      +-- linkPrefetch.call()
                  |
                  +-- Template.asString() [コード組み立て]
```

### データフロー図

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

runtimeRequirements ------> generate()                    -----> ランタイムJSコード
                               |
Compilation                    +-> conditionMap生成             - installedChunks管理
  - outputOptions              +-> 初期チャンクID収集           - loadStylesheet関数
  - chunkGraph                 +-> loadStylesheet生成          - ensureChunkHandlers.css
                               +-> ensureHandler生成           - prefetch/preloadハンドラ
Chunk                          +-> prefetch/preload生成        - HMR更新ハンドラ
  - getAllInitialChunks()       +-> HMRハンドラ生成
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| CssLoadingRuntimeModule.js | `lib/css/CssLoadingRuntimeModule.js` | ソース | CSSチャンク読み込みランタイムコードの生成（本機能の主要ファイル） |
| CssModulesPlugin.js | `lib/css/CssModulesPlugin.js` | ソース | CSSモジュール全体の管理、CssLoadingRuntimeModuleの登録 |
| RuntimeModule.js | `lib/RuntimeModule.js` | ソース | ランタイムモジュールの基底クラス |
| RuntimeGlobals.js | `lib/RuntimeGlobals.js` | ソース | ランタイムグローバル定数の定義 |
| Template.js | `lib/Template.js` | ソース | ランタイムコード生成のテンプレートユーティリティ |
| compileBooleanMatcher.js | `lib/util/compileBooleanMatcher.js` | ソース | チャンクIDマッチング条件の最適化コード生成 |
| Compilation.js | `lib/Compilation.js` | ソース | コンパイレーションインスタンス・outputOptionsの提供 |
| ChunkGraph.js | `lib/ChunkGraph.js` | ソース | チャンクとモジュールの関連情報の管理 |
