# 機能設計書 54-CLIツール（@tailwindcss/cli）

## 概要

本ドキュメントは、コマンドラインからTailwind CSSをビルドするツール `@tailwindcss/cli` の機能設計を記述する。入力CSS・出力先の指定、watchモードによるファイル変更監視・自動リビルド、ソースマップ生成、CSS最適化に対応する。

### 本機能の処理概要

**業務上の目的・背景**：ビルドツール（Vite、Webpack等）を使用しないプロジェクトや、CI/CDパイプラインでのCSS生成、シンプルなスタティックサイト構築において、コマンドラインから直接Tailwind CSSのビルドを実行する手段が必要である。`@tailwindcss/cli` はそうしたユースケースに対応する軽量なCLIツールを提供する。

**機能の利用シーン**：`npx @tailwindcss/cli -i input.css -o output.css` のようにコマンドラインから実行し、Tailwind CSSのビルドを行う。`--watch` フラグでファイル変更監視モードに入り、開発時のリアルタイムリビルドも可能。

**主要な処理内容**：
1. コマンドライン引数の解析（--input, --output, --watch, --minify, --optimize, --cwd, --map）
2. 入力CSSの読み込み（ファイル、stdin、またはデフォルトの `@import 'tailwindcss'`）
3. Tailwind CSSコンパイラの初期化（compile関数経由）
4. Rust製Scannerによるソースファイルスキャンと候補クラス抽出
5. ユーティリティCSSのビルド（compiler.build）
6. ソースマップ生成（--map オプション有効時）
7. CSS最適化（--minify / --optimize オプション有効時）
8. watchモード：@parcel/watcherによるファイル変更監視とインクリメンタル/フルリビルド
9. 結果のファイル出力またはstdout出力

**関連システム・外部連携**：@tailwindcss/node（compile・optimize・toSourceMap）、@tailwindcss/oxide（Scanner）、@parcel/watcher（ファイル監視）、Lightning CSS（CSS最適化）

**権限による制御**：特になし。ファイルシステムへの読み書き権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | CLIツールのため関連画面なし |

## 機能種別

バッチ処理 / ファイル変換処理 / ファイル監視

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| --input / -i | string | No | 入力CSSファイルパス。未指定時は `@import 'tailwindcss'` を使用 | ファイルが存在すること（"-"はstdin） |
| --output / -o | string | No | 出力先ファイルパス。デフォルトは"-"（stdout） | 入力と同一パスでないこと |
| --watch / -w | boolean \| string | No | ファイル変更監視モード。"always"で stdin 閉鎖時もウォッチ継続 | - |
| --minify / -m | boolean | No | 出力の最適化+ミニファイ | - |
| --optimize | boolean | No | ミニファイなしの最適化のみ | - |
| --cwd | string | No | 作業ディレクトリ。デフォルトは"." | - |
| --map | boolean \| string | No | ソースマップ生成。trueでインライン、文字列で外部ファイルパス | "-"は不可 |
| --help / -h | boolean | No | ヘルプ表示 | - |

### 入力データソース

- ファイルシステム上のCSSファイル（--inputで指定）
- stdin（--input が "-" の場合）
- デフォルト入力（`@import 'tailwindcss'`）
- ソースファイル群（Scannerがglobパターンでスキャン）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| CSS | string | コンパイル済みCSS文字列 |
| SourceMap | string | ソースマップ（--map有効時） |

### 出力先

- ファイルシステム（--output で指定されたパス）
- stdout（--output が "-" または未指定の場合）
- ソースマップファイル（--map でパス指定時）

## 処理フロー

### 処理シーケンス

```
1. コマンドライン引数の解析
   └─ args() でフラグをパース、パスの絶対パス解決
2. 入力CSS取得
   └─ ファイル読み込み / stdin / デフォルト @import 'tailwindcss'
3. コンパイラ初期化
   └─ compile(css) でTailwind CSSコンパイラ作成
4. Scanner初期化
   └─ compiler.root と compiler.sources からソースパターン構築
5. 候補クラスのスキャン
   └─ scanner.scan() で全候補を抽出
6. ユーティリティCSSのビルド
   └─ compiler.build(candidates) でCSSを生成
7. ソースマップ生成（有効時）
   └─ toSourceMap(compiler.buildSourceMap())
8. CSS最適化（有効時）
   └─ optimize(css) で Lightning CSS による最適化
9. 出力
   └─ ファイル書き込み または stdout出力 + ソースマップ処理
10. watchモード（有効時）
    └─ @parcel/watcher でファイル変更監視 → インクリメンタル/フルリビルド
```

### フローチャート

```mermaid
flowchart TD
    A[CLI起動] --> B[引数解析]
    B --> C{--help?}
    C -->|Yes| D[ヘルプ表示 → 終了]
    C -->|No| E[入力CSS取得]
    E --> F[コンパイラ+Scanner初期化]
    F --> G[候補クラスのスキャン]
    G --> H[compiler.build でCSS生成]
    H --> I{--map有効?}
    I -->|Yes| J[ソースマップ生成]
    I -->|No| K{--minify/--optimize?}
    J --> K
    K -->|Yes| L[Lightning CSSで最適化]
    K -->|No| M[出力]
    L --> M
    M --> N{--watch?}
    N -->|Yes| O[@parcel/watcher でファイル監視]
    O --> P{変更検知}
    P -->|fullRebuildPath変更| Q[フルリビルド]
    P -->|その他ファイル変更| R[インクリメンタルリビルド]
    Q --> H
    R --> S[scanner.scanFiles で差分スキャン]
    S --> T{新規候補あり?}
    T -->|Yes| H
    T -->|No| U[スキップ]
    N -->|No| V[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-54-01 | 入力出力同一検証 | --inputと--outputが同一パスの場合はエラー終了 | 起動時 |
| BR-54-02 | --map値検証 | --map の値が "-" の場合はエラー（インラインには値なしの --map を使用） | 起動時 |
| BR-54-03 | デフォルト入力 | --inputが未指定の場合、`@import 'tailwindcss'` をデフォルト入力とする | 起動時 |
| BR-54-04 | フルリビルド判定 | fullRebuildPaths（入力CSS、プラグイン、設定ファイル）に含まれるファイルが変更された場合にフルリビルド | watchモード時 |
| BR-54-05 | インクリメンタルリビルド | fullRebuildPaths以外のファイル変更時は差分スキャン（scanner.scanFiles）を実行 | watchモード時 |
| BR-54-06 | インクリメンタルスキップ | 差分スキャンで新規候補が0件の場合はビルドをスキップ | watchモード時 |
| BR-54-07 | stdinウォッチ制御 | --watch=always以外の場合、stdinが閉じられたらウォッチャーを停止してプロセス終了 | watchモード時 |
| BR-54-08 | 出力ファイル変更除外 | 変更されたファイルが出力ファイルのみの場合はリビルドをスキップ（無限ループ防止） | watchモード時 |

### 計算ロジック

特になし

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

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 入力ファイル不在 | --inputで指定されたファイルが存在しない場合 | エラーメッセージを表示してprocess.exit(1) |
| - | 入出力同一パス | --inputと--outputが同一の場合 | エラーメッセージを表示してprocess.exit(1) |
| - | コンパイルエラー | CSS構文エラー等 | handleError関数でcatchしてprocess.exit(1)（初回）、watchモード中はエラー表示して監視継続 |

### リトライ仕様

watchモードでは、エラー発生時にプロセスを終了せずエラーメッセージをstderrに出力し、次のファイル変更イベントでリビルドを試行する。

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

該当なし

## パフォーマンス要件

- watchモードでのインクリメンタルリビルドにより、変更ファイルのみの差分スキャンを実行
- @parcel/watcherのデバウンス処理でバッチ的なファイル変更を一括処理
- ウォッチ対象ディレクトリの重複排除（子ディレクトリの除去）

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

- ファイルパスはpath.resolve()で絶対パスに正規化
- stdin入力に対応するが、セキュリティ上の特別な検証は行わない

## 備考

- サブコマンドは現在サポートされていない（サブコマンドを指定するとヘルプを表示してエラー終了）
- stdinへの入力がない場合（TTYモードで引数なし）はヘルプを表示
- 初回ビルドの所要時間をformatDurationで表示

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | args.ts | `packages/@tailwindcss-cli/src/utils/args.ts` | Arg型とResult型の定義、args()関数による引数パースロジック |
| 1-2 | build/index.ts | `packages/@tailwindcss-cli/src/commands/build/index.ts` | options()関数（30-70行目）によるCLIオプション定義 |

**読解のコツ**: options()がsatisfies Arg制約を持つオブジェクトリテラルを返す。type, description, alias, default, valuesの各フィールドがCLIオプションの定義を構成する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | index.ts | `packages/@tailwindcss-cli/src/index.ts` | CLIのメインエントリー。引数パース→ヘルプ表示判定→build.handle()呼び出し |

**主要処理フロー**:
1. **8-16行目**: sharedOptionsとbuild.optionsをマージして引数パース
2. **20-27行目**: サブコマンド対応（現在は未サポート、ヘルプを表示してexit）
3. **39-44行目**: ヘルプ表示（TTYモードで引数なし or --help）
4. **48行目**: build.handle(flags) でビルドコマンドを実行

#### Step 3: ビルドコマンドの処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | build/index.ts | `packages/@tailwindcss-cli/src/commands/build/index.ts` | handle関数（83-413行目）がビルドのメインロジック |

**主要処理フロー**:
- **83-132行目**: 引数の検証とパス解決
- **136-142行目**: 入力CSSの取得（ファイル/stdin/デフォルト）
- **149-210行目**: write関数 - 最適化→ソースマップ処理→ファイル出力
- **219-248行目**: createCompiler関数 - compile()とScanner初期化
- **250行目**: 初回ビルドの実行
- **253-393行目**: watchモードの実装

#### Step 4: ファイル監視メカニズムを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | build/index.ts | `packages/@tailwindcss-cli/src/commands/build/index.ts` | createWatchers関数（416-510行目）とenqueueCallback（455-464行目） |
| 4-2 | disposables.ts | `packages/@tailwindcss-cli/src/utils/disposables.ts` | Disposablesクラスによるウォッチャーのライフサイクル管理 |

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

```
index.ts [CLIエントリー]
    |
    +-- args() [引数パース]
    +-- build.handle(flags)
            |
            +-- createCompiler(css)
            |       +-- compile(css) [@tailwindcss/node]
            |       +-- Scanner(sources) [@tailwindcss/oxide]
            |
            +-- scanner.scan() [全候補スキャン]
            +-- compiler.build(candidates) [CSS生成]
            +-- toSourceMap() [ソースマップ]
            |
            +-- write(css, map, args)
            |       +-- optimize(css) [Lightning CSS最適化]
            |       +-- outputFile() [ファイル書き込み]
            |
            +-- [watchモード]
                    +-- createWatchers()
                    |       +-- @parcel/watcher.subscribe()
                    |
                    +-- handle() [変更イベントハンドラ]
                            +-- [full] createCompiler() → scanner.scan()
                            +-- [incremental] scanner.scanFiles()
                            +-- compiler.build() → write()
```

### データフロー図

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

CSS ソース        ───▶  compile(css)      ───▶  compiler
(ファイル/stdin/            |
 デフォルト)                v
                  Scanner.scan()    ───▶  候補クラス配列
ソースファイル群              |
                            v
                  compiler.build()  ───▶  CSS文字列
                            |
                            v
                  [--map]  toSourceMap()  ───▶  SourceMap
                  [--minify/--optimize]  optimize()  ───▶  最適化CSS
                            |
                            v
                  write()  ───▶  ファイル/stdout
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.ts | `packages/@tailwindcss-cli/src/index.ts` | ソース | CLIのメインエントリーポイント |
| build/index.ts | `packages/@tailwindcss-cli/src/commands/build/index.ts` | ソース | ビルドコマンドの実装 |
| build/utils.ts | `packages/@tailwindcss-cli/src/commands/build/utils.ts` | ソース | drainStdin、outputFile等のユーティリティ |
| help/index.ts | `packages/@tailwindcss-cli/src/commands/help/index.ts` | ソース | ヘルプ表示 |
| args.ts | `packages/@tailwindcss-cli/src/utils/args.ts` | ソース | コマンドライン引数パーサー |
| renderer.ts | `packages/@tailwindcss-cli/src/utils/renderer.ts` | ソース | 出力フォーマッティング |
| disposables.ts | `packages/@tailwindcss-cli/src/utils/disposables.ts` | ソース | リソース管理ユーティリティ |
| compile.ts | `packages/@tailwindcss-node/src/compile.ts` | ソース | Node.js向けコンパイララッパー |
| optimize.ts | `packages/@tailwindcss-node/src/optimize.ts` | ソース | Lightning CSSによるCSS最適化 |
| source-maps.ts | `packages/@tailwindcss-node/src/source-maps.ts` | ソース | ソースマップシリアライズ |
