# 機能設計書 53-Webpackローダー（@tailwindcss/webpack）

## 概要

本ドキュメントは、WebpackビルドシステムにTailwind CSSを統合するローダー `@tailwindcss/webpack` の機能設計を記述する。CSSファイルの変換、候補クラスのスキャン、ユーティリティCSS生成を行うWebpackローダーとして動作する。

### 本機能の処理概要

**業務上の目的・背景**：Webpackは企業のプロダクション環境で広く使われているバンドラーであり、Next.js等のフレームワークでも内部的に利用されている。`@tailwindcss/webpack` は、WebpackのローダーAPIを活用して、CSSファイルの処理パイプラインにTailwind CSSを統合する手段を提供する。

**機能の利用シーン**：webpack.config.jsにおいて `.css` ファイルに対するローダーとして `@tailwindcss/webpack` を登録し、CSSファイルのビルド時にTailwind CSSの処理パイプラインを自動実行する。

**主要な処理内容**：
1. Tailwind CSSディレクティブの検出（正規表現によるクイックベイルチェック）
2. Tailwind CSSコンパイラの初期化（compile関数経由）
3. フルリビルド判定（依存ファイルのmtime比較）
4. Rust製Scannerによるソースファイルスキャンと候補クラス抽出
5. 候補クラスからユーティリティCSSのビルド（compiler.build）
6. Lightning CSSによるCSS最適化（本番環境時）
7. Webpack依存関係の登録（addDependency, addContextDependency）

**関連システム・外部連携**：Webpack Loader API、@tailwindcss/node（compile・optimize）、@tailwindcss/oxide（Scanner）、Lightning CSS（CSS最適化）

**権限による制御**：特になし。NODE_ENV環境変数およびoptionsにより最適化の有無が制御される。

## 関連画面

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

## 機能種別

データ変換処理（CSSソース -> ユーティリティCSS生成 -> 変換済みCSS出力）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| base | string | No | クラス候補のスキャン対象ベースディレクトリ。デフォルトはprocess.cwd() | 有効なディレクトリパスであること |
| optimize | boolean \| { minify?: boolean } | No | CSS最適化・ミニファイの有無。デフォルトはNODE_ENV==='production' | - |

### 入力データソース

- WebpackローダーAPIから渡されるCSSソース文字列（source引数）
- this.resourcePathで取得される入力ファイルパス
- ファイルシステム上のソースファイル群（Scannerがglobパターンでスキャン）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| result | string | コンパイル済みCSS文字列 |

### 出力先

Webpackローダーのcallback経由で次のローダーへ渡される

## 処理フロー

### 処理シーケンス

```
1. クイックベイルチェック
   └─ 正規表現で@import/@theme/@apply等のディレクティブを検出
2. キャッシュからコンテキスト取得
   └─ inputFile + base + optimize をキーとしてLRUキャッシュを参照
3. コンパイラ初期化（初回またはフルリビルド時）
   └─ compile(source)でコンパイラ作成
4. Features検査
   └─ Tailwind CSS機能が使われていなければ早期リターン
5. フルリビルド判定
   └─ 依存ファイルのmtime比較
6. Scanner初期化またはリセット
   └─ compiler.rootとcompiler.sourcesからソースパターン構築
7. 候補クラスのスキャンと蓄積
   └─ scanner.scan()で候補クラスを抽出しSetに追加
8. Webpack依存関係の登録
   └─ addDependency()とaddContextDependency()で依存関係を通知
9. ユーティリティCSSのビルド
   └─ compiler.build(candidates)でCSSを生成
10. CSS最適化（optimize有効時）
    └─ Lightning CSSで最適化
11. callback(null, result)で結果返却
```

### フローチャート

```mermaid
flowchart TD
    A[Webpack Loader呼び出し] --> B{Tailwind CSSディレクティブあり?}
    B -->|No| C[callback で元のソースを返却]
    B -->|Yes| D[キャッシュからコンテキスト取得]
    D --> E{コンパイラ初期化済み?}
    E -->|No| F[compile でコンパイラ作成]
    E -->|Yes| G[Features検査]
    F --> G
    G --> H{Tailwind CSS機能使用?}
    H -->|No| C
    H -->|Yes| I[フルリビルド判定]
    I --> J{リビルド必要?}
    J -->|Yes| K[コンパイラ再作成]
    J -->|No| L[Scanner初期化/更新]
    K --> L
    L --> M[候補クラスのスキャン]
    M --> N[Webpack依存関係登録]
    N --> O[compiler.build でCSS生成]
    O --> P{optimize有効?}
    P -->|Yes| Q[Lightning CSSで最適化]
    P -->|No| R[callback で結果返却]
    Q --> R
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-53-01 | 正規表現ベイルチェック | `/@(import\|reference\|theme\|variant\|config\|plugin\|apply\|tailwind)\b/` で高速にディレクティブの有無を判定 | ローダー呼び出し時 |
| BR-53-02 | CSS Moduleポリフィル制御 | .module.cssファイルでは@propertyポリフィルを無効化する | inputFileが.module.cssの場合 |
| BR-53-03 | Features検査 | AtApply, JsPluginCompat, ThemeFunction, Utilitiesのいずれも使われていなければ処理をスキップ | コンパイラ初期化後 |
| BR-53-04 | 候補クラス蓄積 | scanner.scan()の結果をcontext.candidates（Set）に蓄積し、重複を排除 | スキャン時 |
| BR-53-05 | source()パス検証 | source(...)で指定されたパスがディレクトリであることをstatSyncで検証 | Utilities機能使用時 |
| BR-53-06 | エラー時キャッシュクリア | エラー発生時はキャッシュエントリを削除し、次回フルリビルドを強制 | try-catchブロック |

### 計算ロジック

キャッシュキーの生成：`${inputFile}:${opts.base ?? ''}:${JSON.stringify(opts.optimize)}`

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

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

該当なし（データベース操作は行わない）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | コンパイルエラー | CSS構文エラーやディレクティブの解決失敗 | キャッシュエントリを削除し、callback(error)でWebpackにエラーを通知 |
| - | source()パスエラー | source(...)パスがディレクトリでない場合 | Errorを投げてcatchブロックで処理 |
| ENOENT | ファイル不在 | source()パスが存在しない場合 | ENOENTエラーは無視（ディレクトリ未作成は許容） |

### リトライ仕様

明示的なリトライは行わない。エラー時はキャッシュをクリアし、次回ビルドでフルリビルドを実行する。

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

該当なし

## パフォーマンス要件

- LRUキャッシュ（maxSize: 50）により複数CSSファイルのコンパイルコンテキストをキャッシュ
- 候補クラスをSetで蓄積し、インクリメンタルなスキャンを実現
- 正規表現によるクイックベイルチェックで非Tailwind CSSファイルの処理を高速にスキップ

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

- path.resolve()でファイルパスを絶対パスに正規化
- clearRequireCacheにより依存モジュールのキャッシュを適切にクリア

## 備考

- PostCSSプラグイン（No.51）と比較して、PostCSS AST変換が不要でCSS文字列を直接扱う点が異なる
- クイックベイルチェックにPostCSSのwalkAtRulesではなく正規表現を使用しており、より高速
- 非同期ローダー（this.async()）として実装されている

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | index.ts | `packages/@tailwindcss-webpack/src/index.ts` | LoaderOptions型（19-31行目）とCacheEntry型（33-39行目）の定義を確認 |

**読解のコツ**: PostCSSプラグイン版のCacheEntryと比較して、candidates（Set<string>）が追加されている。これはWebpack版では候補クラスを自前で蓄積するためである。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | index.ts | `packages/@tailwindcss-webpack/src/index.ts` | tailwindLoader関数（57-282行目）がWebpackローダーのエントリーポイント |

**主要処理フロー**:
1. **57-66行目**: 非同期コールバック取得、オプション解決
2. **73-83行目**: 正規表現によるクイックベイルチェック
3. **92-115行目**: createCompiler内部関数 - compile(source)でコンパイラ作成
4. **118行目**: context.compiler ??= await createCompiler() でコンパイラの遅延初期化
5. **121-125行目**: Features.None検査による早期リターン
6. **127-165行目**: フルリビルド判定（mtime比較）
7. **170-179行目**: 追加のFeatures検査
8. **182-254行目**: Scanner初期化、候補スキャン、依存関係登録
9. **257-270行目**: compiler.build + optimize

#### Step 3: Webpack依存関係の登録を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | index.ts | `packages/@tailwindcss-webpack/src/index.ts` | addDependency/addContextDependency呼び出し（211-254行目） |

**主要処理フロー**:
- **133-135行目**: fullRebuildPathsの各ファイルをthis.addDependency()で登録
- **214-221行目**: scanner.filesの各ファイルをthis.addDependency()で登録
- **224-234行目**: scanner.globsの各パターンをthis.addContextDependency()で登録

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

```
tailwindLoader(source) [Webpackローダー]
    |
    +-- getContextFromCache() [LRUキャッシュ参照]
    |
    +-- createCompiler()
    |       +-- compile(source) [@tailwindcss/node]
    |
    +-- Scanner.scan() [@tailwindcss/oxide]
    |
    +-- this.addDependency()      [Webpack依存登録]
    +-- this.addContextDependency() [Webpackディレクトリ依存登録]
    |
    +-- compiler.build(candidates) [ユーティリティCSS生成]
    |
    +-- optimize(css)  [Lightning CSS最適化]
    |
    +-- callback(null, result) [結果返却]
```

### データフロー図

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

CSS ソース文字列  ───▶  compile(source)   ───▶  compiler (build関数)
                                |
                                v
ソースファイル群   ───▶  Scanner.scan()    ───▶  候補クラスSet
                                |
                                v
                        compiler.build()  ───▶  CSS文字列
                                |
                                v
                [optimize有効]  optimize()  ───▶  最適化CSS
                                |
                                v
                        callback(null, css) ───▶ Webpackローダーチェーン
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.ts | `packages/@tailwindcss-webpack/src/index.ts` | ソース | Webpackローダーのメインエントリーポイント |
| compile.ts | `packages/@tailwindcss-node/src/compile.ts` | ソース | Node.js向けコンパイララッパー |
| optimize.ts | `packages/@tailwindcss-node/src/optimize.ts` | ソース | Lightning CSSによるCSS最適化 |
| normalize-path.ts | `packages/@tailwindcss-node/src/normalize-path.ts` | ソース | パス正規化ユーティリティ |
| instrumentation.ts | `packages/@tailwindcss-node/src/instrumentation.ts` | ソース | デバッグ用パフォーマンス計測 |
