# 機能設計書 30-CSSモジュール

## 概要

本ドキュメントは、webpackのCssModulesPluginによるCSSファイルのモジュール処理機能について記述する。

### 本機能の処理概要

CssModulesPluginは、CSSファイルをwebpackモジュールとして処理し、CSSインポート（`@import`）、URL解決（`url()`）、CSS Modules（ローカルスコープ）、ICSS（Interoperable CSS）対応を行う包括的なCSS処理機能を提供する。

**業務上の目的・背景**：モダンなWeb開発ではCSSもモジュールシステムで管理する必要がある。CSS Modulesによるローカルスコープ化、`@import`による依存管理、`url()`内のアセット参照解決を統合的に処理することで、スタイルシートの保守性とビルドの一貫性を向上させる。webpack 5でネイティブCSS対応が導入され、css-loaderなしでのCSS処理が可能になった。

**機能の利用シーン**：`module.rules` の `type` で `'css'`（通常CSS）、`'css/auto'`（ファイル名による自動判定）、`'css/module'`（CSS Modules）、`'css/global'`（グローバルCSS）を指定して利用する。`experiments.css: true` の有効化が必要。

**主要な処理内容**：
1. 4種類のCSSモジュールタイプに対応するパーサー（CssParser）とジェネレーター（CssGenerator）を登録する
2. CSS依存関係（CssImportDependency, CssUrlDependency, CssIcss*Dependency）のファクトリとテンプレートを登録する
3. CSSモジュールを正しい順序でソートし、チャンクごとのCSSファイルを生成する
4. CSSチャンクローディングランタイム（CssLoadingRuntimeModule）を提供する
5. コンテンツハッシュの計算とHMR対応を行う

**関連システム・外部連携**：NormalModuleFactory、JavascriptModulesPlugin、CssModule（CSSの特殊モジュールクラス）、walkCssTokens（CSSトークナイザー）と連携する。

**権限による制御**：本機能に権限による制御はない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 画面機能マッピングに該当する画面なし |

## 機能種別

データ変換処理（CSSファイルのモジュール化・チャンク化・ランタイム生成）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| parser.defaultMode | string | No | CSS Modulesのデフォルトモード | "global" / "local" / "auto" |
| generator.exportsOnly | boolean | No | CSSエクスポートのみ（CSS出力なし） | - |
| generator.esModule | boolean | No | ESModule形式エクスポート | - |
| type | string | Yes | CSSモジュールタイプ | css / css/auto / css/module / css/global |

### 入力データソース

webpack設定の `module.rules[].type` および `module.rules[].parser` / `module.rules[].generator` オプション。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| CSS output | ConcatSource | チャンクごとのCSSファイル |
| JavaScript module | Source | CSS Modulesのエクスポートオブジェクト（クラス名マッピング） |
| Content hash | string | CSSコンテンツハッシュ（キャッシュバスティング用） |

### 出力先

CSSファイルは出力ディレクトリに独立ファイルとして出力される。CSS Modulesのエクスポートはjavascriptモジュールとしてバンドルに含まれる。

## 処理フロー

### 処理シーケンス

```
1. プラグイン適用（apply）
   ├─ CSS依存関係のファクトリ/テンプレート登録
   │   ├─ CssImportDependency
   │   ├─ CssUrlDependency
   │   ├─ CssIcssImportDependency
   │   ├─ CssIcssExportDependency
   │   ├─ CssIcssSymbolDependency
   │   └─ StaticExportsDependency
   ├─ 4タイプのパーサー登録（CssParser）
   │   ├─ css: デフォルトモード
   │   ├─ css/auto: defaultMode="auto"
   │   ├─ css/module: defaultMode="local"
   │   └─ css/global: defaultMode="global"
   ├─ 4タイプのジェネレーター登録（CssGenerator）
   ├─ 4タイプのモジュールクラス登録（CssModule）
   │   └─ @importからのCSSはlayer/supports/media情報を継承
   ├─ BOM除去処理（processResult フック）
   ├─ HMR対応（JavascriptModulesPlugin.renderModuleContent）
   ├─ afterCodeGeneration: チャンクごとのCSS順序付け
   ├─ chunkHash/contentHash: CSSコンテンツハッシュ計算
   ├─ renderManifest: CSSチャンク出力情報の提供
   └─ ランタイムモジュール登録
       ├─ CssLoadingRuntimeModule（チャンクCSS読み込み）
       └─ CssMergeStyleSheetsRuntimeModule（スタイルシート結合）
2. パース処理（CssParser）
   ├─ walkCssTokensでCSS構文解析
   ├─ @import文の依存関係抽出
   ├─ url()参照の解決
   ├─ CSS Modules（:local/:global）の処理
   ├─ ICSS :import/:export の処理
   └─ composesプロパティの処理
3. コード生成（CssGenerator）
   ├─ CSS出力ソースの生成
   ├─ CSS Modulesエクスポートの生成
   └─ JavaScript/CSS両方のソースタイプ対応
4. チャンクレンダリング（renderChunk）
   ├─ 順序付けされたCSSモジュールの連結
   ├─ @layer/@supports/@media の継承ラッパー適用
   ├─ publicPathのauto解決
   └─ モジュールパッケージフックの呼び出し
```

### フローチャート

```mermaid
flowchart TD
    A[CSSファイル読み込み] --> B[CssParser.parse]
    B --> C["@import依存抽出"]
    B --> D["url()参照解決"]
    B --> E["CSS Modules処理"]
    B --> F["ICSS処理"]
    C --> G[CssImportDependency]
    D --> H[CssUrlDependency]
    E --> I[CssIcssExportDependency]
    F --> J[CssIcssImportDependency]
    G --> K[CssGenerator.generate]
    H --> K
    I --> K
    J --> K
    K --> L{モジュール順序付け}
    L --> M[renderChunk]
    M --> N[@layer/@supports/@media ラッパー]
    N --> O[CSSファイル出力]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | CSSモジュール順序 | チャンクグループ内のpostOrderIndexに基づきCSSモジュールをソート | 常時 |
| BR-02 | 順序競合警告 | チャンクグループ間でCSSモジュール順序が矛盾する場合に警告を出力 | 複数チャンクグループ |
| BR-03 | 継承チェーン | @importで読み込まれたCSSはlayer/supports/mediaを親から継承 | CSS @import |
| BR-04 | CSS/autoモード | ファイル名が`.modules.`を含む場合にCSS Modulesとして処理 | type='css/auto' |
| BR-05 | BOM除去 | CSSファイルの先頭BOM（Byte Order Mark）を除去 | 常時 |
| BR-06 | HMR対応 | CSSエクスポートの変更時にmodule.hot.invalidate()、変更なし時にaccept() | HMRモード |
| BR-07 | publicPath auto | publicPath="auto"時にCSSファイルからのundoPathを計算 | publicPath未指定 |
| BR-08 | チャンクローディング | jsonp/importチャンクローディング方式でCSS動的読み込み | ブラウザ環境 |

### 計算ロジック

CSSコンテンツハッシュ：チャンク内全CSSモジュールのモジュールハッシュをcreateHashで結合し、hashDigestLengthで切り詰める。`chunk.contentHash.css` に格納。

モジュール順序付け：getModulesInOrderメソッドで、チャンクグループ間のpostOrderIndexを比較し、矛盾がある場合は警告を出力しつつ最善の順序を決定する。

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

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

本機能にデータベース操作はない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | WebpackError | CSSモジュール順序の競合 | "Conflicting order between X and Y" 警告を出力 |
| - | TypeError | compilationがCompilationインスタンスでない | "The 'compilation' argument must be an instance of Compilation" |

### リトライ仕様

リトライ処理はない。

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

トランザクション管理はない。

## パフォーマンス要件

大量のCSSファイルがある場合、モジュール順序付け（getModulesInOrder）のアルゴリズムがO(n*m)（n=モジュール数、m=チャンクグループ数）のコストを持つ。

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

CSSインジェクション攻撃を防ぐため、url()内のパス解決は適切にエスケープされる。

## 備考

- webpack 5のネイティブCSS対応機能であり、css-loaderの多くの機能を内蔵する
- CssModuleクラスはNormalModuleとは別の専用モジュールクラス
- CSS_TYPE と CSS_IMPORT_TYPE の2つのソースタイプでCSSコードを区別する
- CssMergeStyleSheetsRuntimeModuleはランタイムでのスタイルシート結合機能を提供する

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | CssModule.js | `lib/CssModule.js` | CSSモジュール固有プロパティ（cssLayer, supports, media, inheritance） |
| 1-2 | CssModulesPlugin.js | `lib/css/CssModulesPlugin.js` | RenderContext型（67-75行目）、CompilationHooks型（89-92行目） |

**読解のコツ**: CssModuleはNormalModuleとは別のクラスであり、CSSの@layer/@supports/@mediaの継承チェーン（inheritance配列）を持つ点が重要。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | CssModulesPlugin.js | `lib/css/CssModulesPlugin.js` | applyメソッド（213-604行目）全体の構造 |

**主要処理フロー**:
1. **218-249行目**: 依存関係ファクトリ/テンプレート登録
2. **254-383行目**: パーサー/ジェネレーター/モジュールクラス登録
3. **385-426行目**: HMR対応（JavascriptModulesPlugin.renderModuleContent）
4. **429-439行目**: afterCodeGeneration - CSSモジュール順序付け
5. **440-474行目**: chunkHash/contentHash - ハッシュ計算
6. **475-523行目**: renderManifest - CSS出力
7. **537-603行目**: ランタイムモジュール登録

#### Step 3: パーサーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | CssParser.js | `lib/css/CssParser.js` | walkCssTokensを利用したCSS構文解析 |
| 3-2 | walkCssTokens.js | `lib/css/walkCssTokens.js` | 低レベルCSSトークナイザー |

#### Step 4: ジェネレーターを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | CssGenerator.js | `lib/css/CssGenerator.js` | CSS/JavaScriptソースの生成 |

#### Step 5: チャンクレンダリングを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | CssModulesPlugin.js | `lib/css/CssModulesPlugin.js` | 613-725行目: getModulesInOrderメソッド |
| 5-2 | CssModulesPlugin.js | `lib/css/CssModulesPlugin.js` | 762-854行目: renderModuleメソッド |
| 5-3 | CssModulesPlugin.js | `lib/css/CssModulesPlugin.js` | 861-906行目: renderChunkメソッド |

**主要処理フロー**:
- **613行目**: getModulesInOrder - チャンクグループ間の順序付け
- **762行目**: renderModule - @layer/@supports/@media ラッパー適用
- **791-804行目**: publicPath autoの解決
- **807-836行目**: 継承チェーンの逆順適用（media -> supports -> layer）

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

```
CssModulesPlugin.apply()
    │
    ├─ 依存関係登録
    │   ├─ CssImportDependency
    │   ├─ CssUrlDependency
    │   ├─ CssIcssImportDependency
    │   ├─ CssIcssExportDependency
    │   └─ CssIcssSymbolDependency
    │
    ├─ normalModuleFactory フック
    │   ├─ createParser → CssParser(mode)
    │   ├─ createGenerator → CssGenerator(options)
    │   └─ createModuleClass → CssModule(data)
    │
    ├─ compilation フック
    │   ├─ afterCodeGeneration → getOrderedChunkCssModules()
    │   ├─ contentHash → createHash()
    │   ├─ renderManifest → renderChunk()
    │   │      ├─ getModulesInOrder()
    │   │      └─ renderModule()
    │   │             └─ @layer/@supports/@media ラッパー
    │   └─ runtimeRequirementInTree
    │          ├─ CssLoadingRuntimeModule
    │          └─ CssMergeStyleSheetsRuntimeModule
    │
    └─ CssParser.parse()
           └─ walkCssTokens()
                  ├─ @import → CssImportDependency
                  ├─ url() → CssUrlDependency
                  ├─ :import → CssIcssImportDependency
                  └─ :export → CssIcssExportDependency
```

### データフロー図

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

CSSファイル ───────────────▶ CssParser ──────────────▶ 依存グラフ
    (.css)                     (walkCssTokens)           (CssImport/Url/Icss)

依存グラフ ────────────────▶ CssGenerator ───────────▶ CSS_TYPE ソース
                               (generate)                JS_TYPE ソース（CSS Modules）

CSS_TYPE ソース ───────────▶ getModulesInOrder() ───▶ 順序付きCSSモジュール列
                               (postOrderIndex比較)

順序付きCSS ───────────────▶ renderChunk() ─────────▶ CSSファイル出力
                               renderModule()            (*.css)
                               (@layer/@supports/@media)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| CssModulesPlugin.js | `lib/css/CssModulesPlugin.js` | ソース | CSSモジュール機能のメインプラグイン |
| CssParser.js | `lib/css/CssParser.js` | ソース | CSSパーサー（依存抽出・CSS Modules処理） |
| CssGenerator.js | `lib/css/CssGenerator.js` | ソース | CSSコードジェネレーター |
| walkCssTokens.js | `lib/css/walkCssTokens.js` | ソース | 低レベルCSSトークナイザー |
| CssLoadingRuntimeModule.js | `lib/css/CssLoadingRuntimeModule.js` | ソース | CSSチャンク動的読み込みランタイム |
| CssMergeStyleSheetsRuntimeModule.js | `lib/css/CssMergeStyleSheetsRuntimeModule.js` | ソース | スタイルシート結合ランタイム |
| CssModule.js | `lib/CssModule.js` | ソース | CSS専用モジュールクラス |
| CssImportDependency.js | `lib/dependencies/CssImportDependency.js` | ソース | @import依存表現 |
| CssUrlDependency.js | `lib/dependencies/CssUrlDependency.js` | ソース | url()依存表現 |
| CssIcssImportDependency.js | `lib/dependencies/CssIcssImportDependency.js` | ソース | ICSS :import依存表現 |
| CssIcssExportDependency.js | `lib/dependencies/CssIcssExportDependency.js` | ソース | ICSS :export依存表現 |
| CssIcssSymbolDependency.js | `lib/dependencies/CssIcssSymbolDependency.js` | ソース | ICSSシンボル依存表現 |
