# 機能設計書 51-PostCSSプラグイン（@tailwindcss/postcss）

## 概要

本ドキュメントは、PostCSSビルドパイプラインにTailwind CSSを統合するプラグイン `@tailwindcss/postcss` の機能設計を記述する。入力CSSの解析、候補クラスのスキャン、ユーティリティCSS生成、最適化を行い、PostCSS ASTとして出力する。

### 本機能の処理概要

**業務上の目的・背景**：PostCSSは広く使われているCSS処理ツールであり、多くのプロジェクトがPostCSSプラグインチェーンを通じてCSSをビルドしている。`@tailwindcss/postcss` は、既存のPostCSSベースのビルドパイプライン（Next.js、Nuxt、Parcel等）にTailwind CSSを組み込むための標準的な統合手段を提供する。これにより、既存プロジェクトへのTailwind CSS導入を容易にする。

**機能の利用シーン**：PostCSS設定ファイル（postcss.config.js等）において `@tailwindcss/postcss` をプラグインとして登録し、CSSビルド時に自動的にTailwind CSSの処理パイプラインを実行する。Next.jsやその他PostCSSベースのフレームワークと共に使用される。

**主要な処理内容**：
1. PostCSS ASTの受信と、Tailwind CSSディレクティブ（@import, @theme, @apply等）の検出
2. PostCSS ASTからTailwind CSS内部ASTへの変換（postCssAstToCssAst）
3. Tailwind CSSコンパイラの初期化とAST入力のコンパイル（compileAst）
4. Rust製Scannerによるソースファイルスキャンと候補クラス抽出
5. 候補クラスからユーティリティCSSのビルド（compiler.build）
6. Lightning CSSによるCSS最適化（本番環境時）
7. Tailwind CSS ASTからPostCSS ASTへの逆変換（cssAstToPostCssAst）
8. PostCSSルートノードの更新

**関連システム・外部連携**：PostCSSプラグインシステム、@tailwindcss/node（コンパイラ・最適化）、@tailwindcss/oxide（Scannerによるファイルスキャン）、Lightning CSS（CSS最適化）

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 3 | レイアウト | 主画面 | postcss.config.jsで@tailwindcss/postcssが登録されており、PostCSSビルド時にTailwind CSSの処理を統合する |
| 5 | レイアウト | 主画面 | postcss.config.jsでtailwindcssプラグインが登録されており、PostCSSビルド時にTailwind CSSの処理を統合する（v3互換構成） |

## 機能種別

データ変換処理（CSS入力 -> ユーティリティCSS生成 -> PostCSS AST出力）

## 入力仕様

### 入力パラメータ

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

### 入力データソース

- PostCSSプラグインチェーンから渡されるPostCSS AST（Root オブジェクト）
- ファイルシステム上のCSSファイル（result.opts.fromで指定）
- ソースファイル群（Scannerがglobパターンでスキャン）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| root | postcss.Root | Tailwind CSSユーティリティを含む変換済みPostCSS ASTルートノード |
| result.messages | Message[] | 依存関係メッセージ（dependency, dir-dependency） |

### 出力先

PostCSSプラグインチェーンの次のプラグインへ渡されるPostCSS AST

## 処理フロー

### 処理シーケンス

```
1. クイックベイルチェック
   └─ @import/@theme/@apply等のディレクティブが存在しなければ早期リターン
2. キャッシュからコンテキスト取得
   └─ inputFile + opts.base + optimize をキーとしてLRUキャッシュを参照
3. コンパイラ初期化（初回またはフルリビルド時）
   └─ PostCSS AST → Tailwind CSS AST変換 → compileAst呼び出し
4. フルリビルド判定
   └─ 依存ファイルのmtime比較による変更検知
5. Scanner初期化またはリセット
   └─ compiler.rootとcompiler.sourcesからソースパターンを構築
6. 候補クラスのスキャン
   └─ scanner.scan()で候補クラスを抽出
7. 依存関係の登録
   └─ スキャンしたファイルとglobパターンをPostCSSメッセージとして登録
8. ユーティリティCSSのビルド
   └─ compiler.build(candidates)でASTを生成
9. 最適化（optimize有効時）
   └─ toCss → Lightning CSS → postcss.parse
10. PostCSS AST更新
    └─ root.removeAll() → 変換済みノードのappend
```

### フローチャート

```mermaid
flowchart TD
    A[PostCSS Once hook] --> B{Tailwind CSSディレクティブあり?}
    B -->|No| C[早期リターン]
    B -->|Yes| D[キャッシュからコンテキスト取得]
    D --> E{コンパイラ初期化済み?}
    E -->|No| F[PostCSS AST → TW AST変換]
    F --> G[compileAst でコンパイラ作成]
    E -->|Yes| H[依存ファイルの変更検知]
    G --> H
    H --> I{フルリビルド必要?}
    I -->|Yes| J[コンパイラ再作成]
    I -->|No| K[既存コンパイラ使用]
    J --> L[Scanner初期化]
    K --> L
    L --> M[候補クラスのスキャン]
    M --> N[依存関係の登録]
    N --> O[compiler.build で CSS生成]
    O --> P{optimize有効?}
    P -->|Yes| Q[Lightning CSSで最適化]
    P -->|No| R[cssAstToPostCssAst変換]
    Q --> S[PostCSS ASTを更新]
    R --> S
    S --> T[完了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-51-01 | クイックベイルチェック | @import, @reference, @theme, @variant, @config, @plugin, @apply, @tailwindのいずれも存在しないCSSファイルは処理をスキップする | PostCSS Onceフック実行時 |
| BR-51-02 | CSS Moduleポリフィル制御 | .module.cssファイルでは@propertyポリフィルを無効化する（グローバル*ルールがCSS Moduleのpure性を破壊するため） | inputFileが.module.cssの場合 |
| BR-51-03 | フルリビルド判定 | 依存ファイル（CSS、プラグイン、設定ファイル）のmtimeが変更された場合、フルリビルドを行う | 2回目以降のビルド時 |
| BR-51-04 | 最適化制御 | optimize未指定時はNODE_ENV==='production'で最適化を有効にする | ビルド時 |
| BR-51-05 | インデント制御 | PostCSS ASTのデフォルトインデントを2スペースに設定する | PostCSS AST更新時 |

### 計算ロジック

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

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

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | コンパイルエラー | CSS構文エラーやディレクティブの解決失敗 | context.compilerをnullにリセットし、依存関係メッセージを保持してからroot.error()でPostCSSエラーとして投げる |
| - | ファイル不在 | 依存ファイルが存在しない | mtimeチェック時にnullとして扱い、入力ファイルの場合はフルリビルドを強制 |

### リトライ仕様

エラー発生時はcontext.compilerをnullにリセットし、次回ビルド時にフルリビルドを強制する。明示的なリトライは行わない。

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

該当なし

## パフォーマンス要件

- LRUキャッシュ（maxSize: 50）により、複数CSSファイルのコンパイルコンテキストをキャッシュ
- インクリメンタルビルド戦略により、依存ファイルに変更がなければコンパイラを再利用
- ASTの変更がなければPostCSS AST変換をスキップ（context.tailwindCssAst比較）

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

- onDependencyコールバックで収集したパスはpath.resolve()で絶対パスに正規化される
- 外部プラグインやコンフィグのrequireキャッシュはフルリビルド時にクリアされる

## 備考

- PostCSS v8以上が前提
- `fixRelativePathsPlugin` がプラグインチェーンの先頭で実行され、postcss-importとの互換性を確保する
- Lightning CSSによる最適化は2パス実行で隣接ルールの結合を最適化する

---

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

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

### 推奨読解順序

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

まず、プラグインが扱うデータ構造（キャッシュエントリ、オプション型）を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | index.ts | `packages/@tailwindcss-postcss/src/index.ts` | CacheEntry型（21-29行目）とPluginOptions型（50-69行目）の定義を確認 |
| 1-2 | ast.ts | `packages/@tailwindcss-postcss/src/ast.ts` | PostCSS AST <-> Tailwind CSS AST の相互変換関数を確認 |

**読解のコツ**: CacheEntryの各フィールドが何をキャッシュしているかを把握すること。mtimesは依存ファイルの更新時刻、compilerはPromise型（非同期初期化のため）、scannerはRust製のScanner。

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

PostCSSプラグインのエントリーポイントであるtailwindcss関数を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | index.ts | `packages/@tailwindcss-postcss/src/index.ts` | tailwindcss関数（71-363行目）がPostCSSプラグインとして登録される構造を確認 |

**主要処理フロー**:
1. **71-74行目**: プラグインオプションのデフォルト値設定（base, optimize, shouldRewriteUrls）
2. **76-78行目**: PostCSSプラグインオブジェクトの返却。pluginsとして2つのプラグインを登録
3. **82-83行目**: fixRelativePathsPluginが先に実行される
4. **86行目**: メインの処理は `async Once(root, { result, postcss })` フック内
5. **96-115行目**: クイックベイルチェック - Tailwind CSSディレクティブの有無を確認
6. **124-151行目**: createCompiler内部関数 - PostCSS AST→TW AST変換→compileAst
7. **162-198行目**: フルリビルド判定（依存ファイルのmtime比較）
8. **211-231行目**: Scanner初期化とソース設定
9. **233-235行目**: 候補クラスのスキャン
10. **287-316行目**: ユーティリティCSSビルドとPostCSS AST変換
11. **320-331行目**: PostCSS ASTルートの更新

#### Step 3: AST変換層を理解する

PostCSS ASTとTailwind CSS ASTの相互変換を担う層。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ast.ts | `packages/@tailwindcss-postcss/src/ast.ts` | postCssAstToCssAst（126-189行目）: PostCSS Root → AstNode[] への変換 |
| 3-2 | ast.ts | `packages/@tailwindcss-postcss/src/ast.ts` | cssAstToPostCssAst（9-124行目）: AstNode[] → PostCSS Root への変換 |

**主要処理フロー**:
- **126-189行目**: PostCSS decl/rule/atrule/comment を Tailwind CSS のdecl/rule/atRule/comment に変換。SourceLocation情報も保持。
- **9-124行目**: Tailwind CSS ASTノードをPostCSS ASTノードに変換。ソースマップ用のSource/LineTable情報も変換。

#### Step 4: コンパイラ統合層を理解する

@tailwindcss/nodeが提供するcompileAst関数の実装。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | compile.ts | `packages/@tailwindcss-node/src/compile.ts` | compileAst関数（94-98行目）: オプション構築と内部compile呼び出し |
| 4-2 | optimize.ts | `packages/@tailwindcss-node/src/optimize.ts` | optimize関数（29-143行目）: Lightning CSSによる2パス最適化 |

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

```
tailwindcss() [PostCSSプラグイン登録]
    |
    +-- fixRelativePathsPlugin() [相対パス修正]
    |
    +-- Once(root, {result, postcss}) [メイン処理]
            |
            +-- getContextFromCache() [LRUキャッシュ参照]
            |
            +-- createCompiler()
            |       +-- postCssAstToCssAst(root) [PostCSS→TW AST]
            |       +-- compileAst(ast, options)  [@tailwindcss/node]
            |
            +-- Scanner.scan()  [@tailwindcss/oxide]
            |
            +-- compiler.build(candidates) [ユーティリティCSS生成]
            |
            +-- [optimize有効時]
            |       +-- toCss(tailwindCssAst) [AST→CSS文字列]
            |       +-- optimizeCss(css)      [Lightning CSS最適化]
            |       +-- postcss.parse()       [CSS→PostCSS AST]
            |
            +-- [optimize無効時]
            |       +-- cssAstToPostCssAst()  [TW AST→PostCSS AST]
            |
            +-- root.removeAll() / root.append() [PostCSS AST更新]
```

### データフロー図

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

PostCSS Root AST  ───▶  postCssAstToCssAst()  ───▶  Tailwind CSS AstNode[]
                                |
                                v
                        compileAst(ast)   ───▶  compiler (build関数を持つ)
                                |
                                v
ソースファイル群   ───▶  Scanner.scan()    ───▶  候補クラス配列
                                |
                                v
                        compiler.build()  ───▶  Tailwind CSS AstNode[]
                                |
                                v
                [optimize有効]  toCss() → optimizeCss() → postcss.parse()
                [optimize無効]  cssAstToPostCssAst()
                                |
                                v
                        root.append()     ───▶  更新済みPostCSS Root AST
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.ts | `packages/@tailwindcss-postcss/src/index.ts` | ソース | PostCSSプラグインのメインエントリーポイント |
| ast.ts | `packages/@tailwindcss-postcss/src/ast.ts` | ソース | PostCSS AST <-> Tailwind CSS AST の相互変換 |
| compile.ts | `packages/@tailwindcss-node/src/compile.ts` | ソース | Node.js向けコンパイララッパー |
| optimize.ts | `packages/@tailwindcss-node/src/optimize.ts` | ソース | Lightning CSSによるCSS最適化 |
| instrumentation.ts | `packages/@tailwindcss-node/src/instrumentation.ts` | ソース | デバッグ用パフォーマンス計測 |
| index.ts | `packages/@tailwindcss-node/src/index.ts` | ソース | @tailwindcss/nodeの公開API |
