# 機能設計書 57-Node.jsコンパイラ統合（@tailwindcss/node）

## 概要

本ドキュメントは、Node.js環境向けのコンパイララッパー `@tailwindcss/node` の機能設計を記述する。モジュール解決、スタイルシート読み込み、URL書き換え、Lightning CSSによる最適化、ソースマップ処理を提供する。

### 本機能の処理概要

**業務上の目的・背景**：Tailwind CSSコアライブラリはランタイム非依存で設計されているが、Node.js環境で使用する際にはモジュール解決（@import、@plugin）、ファイルシステムアクセス、URL書き換え、Lightning CSSによる最適化等、Node.js固有の機能が必要となる。`@tailwindcss/node` はこれらのNode.js固有機能をラップし、PostCSSプラグイン、Viteプラグイン、Webpackローダー、CLI等の上位層に統一的なインターフェースを提供する。

**機能の利用シーン**：PostCSSプラグイン（No.51）、Viteプラグイン（No.52）、Webpackローダー（No.53）、CLIツール（No.54）等の全てのNode.jsベースのビルドツール統合で内部的に使用される。

**主要な処理内容**：
1. compile/compileAst関数：Tailwind CSSコアのcompile/compileAstにNode.js固有のオプション（loadModule、loadStylesheet）を付与して呼び出す
2. loadModule：EnhancedResolveによるJSモジュール解決、jitiによる.tsファイルサポート、ESM/CJSリゾルバの使い分け
3. loadStylesheet：EnhancedResolveによるCSSモジュール解決、URL書き換え
4. optimize：Lightning CSSによるCSS最適化（ネスティング解除、メディアクエリ最適化、ミニファイ）
5. toSourceMap：DecodedSourceMapのシリアライズ
6. normalizePath：Windowsパスの正規化
7. ESMモジュールキャッシュローダーの登録

**関連システム・外部連携**：tailwindcss コアライブラリ（compile/compileAst）、EnhancedResolve（モジュール解決）、jiti（TypeScriptモジュール読み込み）、Lightning CSS（CSS最適化）、source-map-js（ソースマップ生成）

**権限による制御**：特になし。ファイルシステムへのアクセス権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | インフラストラクチャ層のため特定の画面に紐づかない |

## 機能種別

インフラストラクチャ / モジュール解決 / データ変換

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| css/ast | string / AstNode[] | Yes | CSS文字列またはパース済みAST | - |
| base | string | Yes | ベースディレクトリパス | 有効なディレクトリパス |
| from | string | No | 入力ファイルパス（ソースマップ用） | - |
| onDependency | (path: string) => void | Yes | 依存ファイルコールバック | - |
| shouldRewriteUrls | boolean | No | URL書き換えの有無 | - |
| polyfills | Polyfills | No | 有効にするポリフィル | - |
| customCssResolver | Resolver | No | カスタムCSSリゾルバ | - |
| customJsResolver | Resolver | No | カスタムJSリゾルバ | - |

### 入力データソース

- ファイルシステム上のCSS/JSモジュール
- 上位層（PostCSS/Vite/Webpack/CLI）からの引数

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| compiler | Compiler | build/buildSourceMap関数等を持つコンパイラオブジェクト |
| optimized | TransformResult | 最適化後のCSS（code + map） |
| sourceMap | SourceMap | シリアライズされたソースマップ |

### 出力先

上位層（PostCSS/Vite/Webpack/CLI等）への戻り値

## 処理フロー

### 処理シーケンス

```
1. compile/compileAst 呼び出し
   └─ createCompileOptions でNode.js固有オプションを構築
2. loadModule（JSモジュール解決）
   └─ a. __tw_resolve カスタムフック（スタンドアロンCLI用）
   └─ b. customJsResolver（Vite等のカスタムリゾルバ）
   └─ c. EnhancedResolve ESM/CJSリゾルバ
   └─ d. import() / jiti.import()（.tsファイル対応）
   └─ e. getModuleDependencies（依存ファイル収集）
3. loadStylesheet（CSSモジュール解決）
   └─ a. __tw_resolve カスタムフック
   └─ b. customCssResolver
   └─ c. EnhancedResolve CSSリゾルバ
   └─ d. ファイル読み込み + URL書き換え
4. ensureSourceDetectionRootExists
   └─ source(…)パスの存在検証
5. optimize（CSS最適化）
   └─ Lightning CSS transform × 2パス
   └─ MagicStringによるメディアクエリ修正
   └─ ソースマップの再マッピング
```

### フローチャート

```mermaid
flowchart TD
    A[compile/compileAst呼び出し] --> B[createCompileOptions]
    B --> C[tailwindcss.compile/compileAst]
    C --> D{@import解決}
    D --> E[loadStylesheet]
    E --> F{__tw_resolve?}
    F -->|Yes| G[バンドル内パス解決]
    F -->|No| H{customCssResolver?}
    H -->|Yes| I[カスタム解決]
    H -->|No| J[EnhancedResolve CSS]
    G --> K[ファイル読み込み]
    I --> K
    J --> K
    K --> L{shouldRewriteUrls?}
    L -->|Yes| M[rewriteUrls]
    L -->|No| N[返却]
    M --> N
    C --> O{@plugin/JS解決}
    O --> P[loadModule]
    P --> Q[resolveJsId]
    Q --> R{import / jiti.import}
    R --> S[getModuleDependencies]
    S --> T[依存ファイルコールバック]
    C --> U[ensureSourceDetectionRootExists]
    U --> V[compiler返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-57-01 | ESM優先CJS後退 | JSモジュール解決時はESMリゾルバを先に試行し、失敗時にCJSリゾルバにフォールバック | loadModule時 |
| BR-57-02 | jiti遅延初期化 | ネイティブimport()が失敗した場合のみjitiを初期化し、.tsファイルの解決に使用 | importModule時 |
| BR-57-03 | source()パス検証 | compile後にsource(...)のパスが存在し、ディレクトリであることを検証 | compile/compileAst完了後 |
| BR-57-04 | 2パス最適化 | Lightning CSSの最適化を2回実行し、ネスティング解除後の隣接ルール結合を最適化 | optimize時 |
| BR-57-05 | メディアクエリ修正 | `@media not (` を `@media not all and (` に変換（メディアクエリレベル3互換性） | optimize後 |
| BR-57-06 | URL書き換え | shouldRewriteUrls有効時、CSSのURL参照をルートディレクトリからの相対パスに書き換え | loadStylesheet時 |
| BR-57-07 | 依存ファイルトラッキング | 相対パスJSモジュールの全トランジティブ依存をgetModuleDependenciesで収集 | loadModule時 |
| BR-57-08 | ESMキャッシュローダー登録 | Bun以外のNode.js環境でModule.register()によるESMキャッシュローダーを登録 | パッケージ読み込み時 |
| BR-57-09 | ターゲットブラウザ | Safari 16.4, Firefox 128, Chrome 111をターゲットに最適化 | optimize時 |

### 計算ロジック

Lightning CSSターゲットバージョンのビットエンコーディング：`(major << 16) | (minor << 8)`

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

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | モジュール解決エラー | JSモジュールのパス解決に失敗 | Error("Could not resolve '...' from '...'") をthrow |
| - | スタイルシート解決エラー | CSSモジュールのパス解決に失敗 | Error("Could not resolve '...' from '...'") をthrow |
| - | source()パスエラー | source(...)で指定されたパスが存在しないまたはディレクトリでない | Error メッセージをthrow |
| - | Lightning CSS警告 | 最適化中に無効なCSSが検出された場合 | errorRecovery: trueで続行し、警告をconsole.warnで出力 |

### リトライ仕様

明示的なリトライは行わない。

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

該当なし

## パフォーマンス要件

- EnhancedResolve の CachedInputFileSystem（キャッシュ: 4000ms）によるファイルシステムアクセスの高速化
- useSyncFileSystemCalls: true による同期ファイルシステムコール
- jiti の遅延初期化（必要時のみ）
- Lightning CSS の 2パス最適化による出力サイズ最小化

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

- pathToFileURL でファイルパスをURL形式に変換してからimport（パストラバーサル防止）
- globalThis.__tw_resolve / __tw_load はスタンドアロンCLI内でのみ設定される

## 備考

- PostCSSプラグイン、Viteプラグイン、Webpackローダー、CLI、スタンドアロンCLIの全てがこのパッケージを共通基盤として使用
- Lightning CSSの `errorRecovery: true` により、:deep(), :slotted(), :global() 等のフレームワーク固有の疑似クラスに関する警告はフィルタされる
- NODE_PATH 環境変数によるモジュールパスの拡張に対応

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | compile.ts | `packages/@tailwindcss-node/src/compile.ts` | CompileOptions型（22-31行目）とResolver型（20行目）を確認 |
| 1-2 | optimize.ts | `packages/@tailwindcss-node/src/optimize.ts` | OptimizeOptions型（5-22行目）とTransformResult型（24-27行目）を確認 |
| 1-3 | source-maps.ts | `packages/@tailwindcss-node/src/source-maps.ts` | SourceMap型（6-10行目）を確認 |

**読解のコツ**: CompileOptionsがcustomCssResolver/customJsResolverを持ち、ViteプラグインからのカスタムリゾルバをNode.js標準のEnhancedResolveと統合している。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | index.ts | `packages/@tailwindcss-node/src/index.ts` | パッケージの公開API（re-export）とESMキャッシュローダー登録 |

**主要処理フロー**:
1. **4-8行目**: compile, instrumentation, normalize-path, optimize, source-mapsの再公開
2. **13-21行目**: Bun以外の環境でModule.register()によるESMキャッシュローダー登録

#### Step 3: コンパイル関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | compile.ts | `packages/@tailwindcss-node/src/compile.ts` | compile/compileAst（94-104行目）: createCompileOptionsでオプション構築 |
| 3-2 | compile.ts | `packages/@tailwindcss-node/src/compile.ts` | createCompileOptions（33-64行目）: loadModule/loadStylesheet関数の構築 |
| 3-3 | compile.ts | `packages/@tailwindcss-node/src/compile.ts` | loadModule（118-156行目）: JSモジュール解決の全フロー |
| 3-4 | compile.ts | `packages/@tailwindcss-node/src/compile.ts` | loadStylesheet（158-175行目）: CSSモジュール解決 |

**主要処理フロー**:
- **118-156行目**: loadModuleの処理フロー
  - 非相対パス: resolveJsId → importModule → {path, base, module}
  - 相対パス: resolveJsId → importModule（cacheBust付き）→ getModuleDependencies → onDependency
- **181-195行目**: importModuleの処理
  - __tw_load → import() → jiti.import()（フォールバック）
- **199-278行目**: リゾルバの定義
  - cssResolver: extensions=['.css'], mainFields=['style']
  - esmResolver: extensions=['.js','.json','.node','.ts'], conditionNames=['node','import']
  - cjsResolver: extensions=['.js','.json','.node','.ts'], conditionNames=['node','require']

#### Step 4: 最適化を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | optimize.ts | `packages/@tailwindcss-node/src/optimize.ts` | optimize関数（29-143行目）: Lightning CSSの2パス最適化 |

**主要処理フロー**:
- **33-56行目**: 内部optimize関数 - Lightning CSSのtransform呼び出し
- **60行目**: 1パス目の最適化
- **63-72行目**: 警告フィルタ（:deep, :slotted, :global）
- **116行目**: 2パス目の最適化
- **124行目**: MagicStringによる `@media not (` → `@media not all and (` の修正
- **129-135行目**: ソースマップの再マッピング（remapping）

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

```
compile(css, options) / compileAst(ast, options)
    |
    +-- createCompileOptions(options)
    |       +-- loadModule(id, base, onDependency, customJsResolver)
    |       |       +-- resolveJsId(id, base, customJsResolver)
    |       |       |       +-- __tw_resolve()
    |       |       |       +-- customJsResolver()
    |       |       |       +-- esmResolver.resolve() → cjsResolver.resolve()
    |       |       +-- importModule(path)
    |       |       |       +-- __tw_load()
    |       |       |       +-- import()
    |       |       |       +-- jiti.import()
    |       |       +-- getModuleDependencies(path)
    |       |
    |       +-- loadStylesheet(id, base, onDependency, customCssResolver)
    |               +-- resolveCssId(id, base, customCssResolver)
    |               |       +-- __tw_resolve()
    |               |       +-- customCssResolver()
    |               |       +-- cssResolver.resolve()
    |               +-- fs.readFile()
    |               +-- rewriteUrls()
    |
    +-- tailwindcss.compile/compileAst()
    +-- ensureSourceDetectionRootExists()
    +-- return compiler

optimize(input, options)
    +-- Lightning CSS transform() [1パス目]
    +-- Lightning CSS transform() [2パス目]
    +-- MagicString.replaceAll()
    +-- remapping() [ソースマップ再マッピング]

toSourceMap(map)
    +-- serializeSourceMap() [SourceMapGenerator]
    +-- return { raw, inline, comment }
```

### データフロー図

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

CSS文字列/AST       ───▶  compile/compileAst()  ───▶  compiler
                                  |
JSモジュールID      ───▶  loadModule()           ───▶  {path, base, module}
                                  |
CSSモジュールID     ───▶  loadStylesheet()       ───▶  {path, base, content}
                                  |
CSS文字列          ───▶  optimize()             ───▶  {code, map}
                                  |
DecodedSourceMap   ───▶  toSourceMap()          ───▶  {raw, inline, comment}
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.ts | `packages/@tailwindcss-node/src/index.ts` | ソース | パッケージの公開APIとESMキャッシュローダー登録 |
| compile.ts | `packages/@tailwindcss-node/src/compile.ts` | ソース | compile/compileAst + モジュール解決 |
| optimize.ts | `packages/@tailwindcss-node/src/optimize.ts` | ソース | Lightning CSSによるCSS最適化 |
| source-maps.ts | `packages/@tailwindcss-node/src/source-maps.ts` | ソース | ソースマップのシリアライズ |
| normalize-path.ts | `packages/@tailwindcss-node/src/normalize-path.ts` | ソース | Windowsパス正規化 |
| env.ts | `packages/@tailwindcss-node/src/env.ts` | ソース | DEBUG環境変数の解決 |
| urls.ts | `packages/@tailwindcss-node/src/urls.ts` | ソース | CSS内URL書き換え |
| get-module-dependencies.ts | `packages/@tailwindcss-node/src/get-module-dependencies.ts` | ソース | トランジティブ依存収集 |
| instrumentation.ts | `packages/@tailwindcss-node/src/instrumentation.ts` | ソース | パフォーマンス計測 |
