# 機能設計書 57-compileStyle() / compileStyleAsync()

## 概要

本ドキュメントは、@vue/compiler-sfcパッケージにおけるcompileStyle()およびcompileStyleAsync()関数の処理について記述する。SFCの`<style>`ブロックを処理し、スコープ付きCSS、CSSモジュール、CSSプリプロセッサ対応、CSS変数（v-bind）の変換を行う。

### 本機能の処理概要

compileStyle()/compileStyleAsync()は、SFCのスタイルブロックのソースコードを受け取り、PostCSSプラグインチェーンを通じて変換する。scoped属性による属性セレクタの付与、CSSモジュールによるクラス名のハッシュ化、v-bind()によるJavaScript変数のCSS変数への変換、コンテンツのトリミングを行う。

**業務上の目的・背景**：VueのSFCにおけるスコープ付きスタイルは、コンポーネントごとのスタイル分離を実現する重要な機能である。compileStyle()はPostCSSベースのプラグインチェーンでこれらの変換を処理し、コンポーネント単位のCSS分離とモジュール化を可能にする。

**機能の利用シーン**：SFCビルド時にparse()の後に各styleブロックごとに呼び出される。同期版のcompileStyle()と非同期版のcompileStyleAsync()があり、CSSモジュール機能を使用する場合は非同期版が必要。

**主要な処理内容**：
1. CSSプリプロセッサの実行（SASS/SCSS、Less、Stylus等）
2. CSS変数プラグイン（v-bind in CSS）の適用
3. コンテンツトリミングプラグインの適用
4. スコープ付きCSSプラグインの適用（scoped属性時）
5. CSSモジュールプラグインの適用（module属性時）
6. PostCSSパイプラインの実行
7. ソースマップの処理
8. 依存関係ファイルの追跡

**関連システム・外部連携**：PostCSSによるCSS変換パイプライン。postcss-modulesによるCSSモジュール処理。SASS/Less/Stylus等のCSSプリプロセッサ。

**権限による制御**：該当なし（コンパイル時処理）

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | App（メイン画面） | API連携 | @vue/replコンポーネントを介した`<style>`ブロックのスコープCSS生成 |

## 機能種別

スタイルコンパイル処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| options.source | string | Yes | スタイルのソースコード | - |
| options.filename | string | Yes | ファイル名 | - |
| options.id | string | Yes | スコープID | - |
| options.scoped | boolean | No | スコープ付きスタイルか | デフォルト: false |
| options.trim | boolean | No | コンテンツトリミング | デフォルト: true |
| options.isProd | boolean | No | プロダクションモード | デフォルト: false |
| options.inMap | RawSourceMap | No | 入力ソースマップ | - |
| options.preprocessLang | PreprocessLang | No | プリプロセッサ言語（scss, sass, less, stylus, styl） | - |
| options.preprocessOptions | any | No | プリプロセッサオプション | - |
| options.preprocessCustomRequire | Function | No | カスタムrequire関数 | - |
| options.postcssOptions | any | No | PostCSSオプション | - |
| options.postcssPlugins | any[] | No | 追加PostCSSプラグイン | - |
| options.modules | boolean | No | CSSモジュール有効化（非同期版のみ） | デフォルト: false |
| options.modulesOptions | CSSModulesOptions | No | CSSモジュールオプション | - |

### 入力データソース

parse()により生成されたSFCDescriptor.stylesブロックの情報。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| code | string | 変換後のCSSコード |
| map | RawSourceMap \| undefined | ソースマップ |
| rawResult | Result \| LazyResult \| undefined | PostCSSの生の結果 |
| errors | Error[] | エラーの配列 |
| modules | Record<string, string> \| undefined | CSSモジュールのクラスマッピング（非同期版のみ） |
| dependencies | Set<string> | 依存ファイルのパス集合 |

### 出力先

SFCStyleCompileResultsとして返却される。ビルドツールがCSSファイルまたはインラインスタイルとして出力する。

## 処理フロー

### 処理シーケンス

```
1. CSSプリプロセッサの実行
   └─ preprocessLangが指定されている場合
      - processors[preprocessLang]でプリプロセッサを取得
      - ソースコードをプリプロセス
      - ソースマップと依存ファイルを取得

2. PostCSSプラグインチェーンの構築
   └─ cssVarsPlugin: CSS変数（v-bind）の変換（最初に適用）
   └─ trimPlugin: 空白のトリミング（trimオプション有効時）
   └─ scopedPlugin: スコープ付きCSS変換（scopedオプション有効時）
   └─ postcssModules: CSSモジュール変換（modules有効時、非同期のみ）
   └─ ユーザー指定のpostcssPlugins

3. PostCSSオプションの構築
   └─ to/from: ファイル名
   └─ map: ソースマップ設定（inline: false, annotation: false）

4. PostCSSパイプラインの実行
   └─ postcss(plugins).process(source, options)
   └─ 同期モード: 結果を直接取得
   └─ 非同期モード: Promiseとして返却

5. 依存関係の追跡
   └─ プリプロセッサの依存ファイル + PostCSSのdependencyメッセージ
   └─ ファイル自身（filename）は除外

6. 結果の返却
   └─ code: result.css
   └─ map: result.map.toJSON()
   └─ errors: プリプロセスエラー + PostCSSエラー
   └─ dependencies: 依存ファイルの集合
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{プリプロセッサあり?}
    B -->|Yes| C[プリプロセッサ実行]
    B -->|No| D[プラグインチェーン構築]
    C --> D
    D --> E[cssVarsPlugin追加]
    E --> F{trim有効?}
    F -->|Yes| G[trimPlugin追加]
    F -->|No| H{scoped有効?}
    G --> H
    H -->|Yes| I[scopedPlugin追加]
    H -->|No| J{modules有効?}
    I --> J
    J -->|Yes| K[postcssModules追加]
    J -->|No| L[PostCSS実行]
    K --> L
    L --> M{非同期モード?}
    M -->|Yes| N[Promise返却]
    M -->|No| O[同期結果返却]
    N --> P[終了]
    O --> P
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-57-01 | modules非同期制限 | CSSモジュール機能はcompileStyleAsync()でのみ使用可能 | modules=true && isAsync=false の場合エラー |
| BR-57-02 | ブラウザmodules制限 | ブラウザビルドではCSSモジュールは使用不可 | __GLOBAL__ \|\| __ESM_BROWSER__ && modules=true |
| BR-57-03 | プラグイン順序 | cssVarsPlugin → trimPlugin → scopedPlugin → postcssModules → ユーザープラグインの順で適用 | 常時 |
| BR-57-04 | scopeId形式 | scopeIdは'data-v-'プレフィックス付きのフルフォーマット | scoped=true |
| BR-57-05 | 自己依存除外 | ファイル自身は依存関係リストから除外 | dependencies.delete(filename) |

### 計算ロジック

scopeId生成:
- `shortId = id.replace(/^data-v-/, '')`
- `longId = 'data-v-' + shortId`

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

該当なし（コンパイル時処理）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | Error | ブラウザビルドでCSSモジュール使用 | サーバー側でコンパイルする |
| - | Error | compileStyle()でCSSモジュール使用 | compileStyleAsync()を使用する |
| - | Error | ブラウザビルドでpreprocessCustomRequire未指定 | preprocessCustomRequireを提供する |
| - | Error | プリプロセッサ実行エラー | プリプロセッサの入力を修正する |

### リトライ仕様

該当なし

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

該当なし（コンパイル時処理）

## パフォーマンス要件

- 同期版compileStyle()は同期プラグインのみを使用し、不要な非同期オーバーヘッドを回避
- PostCSSのLazyResultにより、必要になるまで処理を遅延

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

該当なし（コンパイル時処理）

## 備考

- compileStyle()は同期版、compileStyleAsync()は非同期版で、内部的にはdoCompileStyle()を共有
- CSSモジュールのgetJSONコールバックでクラスマッピングを取得する
- 依存ファイルの追跡は、Stylus等のプリプロセッサが含むファイルとPostCSSの依存メッセージの両方を統合する

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | compileStyle.ts | `packages/compiler-sfc/src/compileStyle.ts` | SFCStyleCompileOptions、SFCAsyncStyleCompileOptions、SFCStyleCompileResults型定義 |
| 1-2 | compileStyle.ts | `packages/compiler-sfc/src/compileStyle.ts` | CSSModulesOptions型定義 |

**読解のコツ**: compileStyle()とcompileStyleAsync()は同じdoCompileStyle()を呼び出すが、isAsyncフラグで同期/非同期を切り替える。CSSモジュール機能は非同期モードでのみ利用可能。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | compileStyle.ts | `packages/compiler-sfc/src/compileStyle.ts` | compileStyle()とcompileStyleAsync() |

**主要処理フロー**:
1. **71-78行目**: compileStyle() - 同期版エントリーポイント。isAsync: falseでdoCompileStyleを呼び出し
2. **80-87行目**: compileStyleAsync() - 非同期版エントリーポイント。isAsync: trueでdoCompileStyleを呼び出し

#### Step 3: doCompileStyle関数の詳細

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | compileStyle.ts | `packages/compiler-sfc/src/compileStyle.ts` | doCompileStyle関数 |

**主要処理フロー**:
- **89-103行目**: パラメータのデストラクチャリング
- **104-109行目**: プリプロセッサの取得と実行
- **111-112行目**: shortId/longId計算
- **114-142行目**: PostCSSプラグインチェーンの構築（cssVarsPlugin→trim→scoped→modules）
- **144-155行目**: PostCSSオプション構築（ソースマップ設定含む）
- **182-203行目**: PostCSSパイプライン実行（同期/非同期分岐）
- **213-220行目**: 結果の構築と返却

#### Step 4: PostCSSプラグインの理解

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | pluginTrim.ts | `packages/compiler-sfc/src/style/pluginTrim.ts` | trimPlugin - 空白トリミング |
| 4-2 | pluginScoped.ts | `packages/compiler-sfc/src/style/pluginScoped.ts` | scopedPlugin - スコープ付きCSS変換 |
| 4-3 | cssVars.ts | `packages/compiler-sfc/src/style/cssVars.ts` | cssVarsPlugin - v-bind() CSS変数変換 |

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

```
compileStyle / compileStyleAsync (エントリーポイント)
    │
    └─ doCompileStyle
           │
           ├─ preprocess (CSSプリプロセッサ)
           │      └─ processors[preprocessLang]
           │            (sass/scss/less/stylus)
           │
           ├─ PostCSSプラグインチェーン
           │      ├─ cssVarsPlugin (v-bind変換)
           │      ├─ trimPlugin (空白除去)
           │      ├─ scopedPlugin (スコープ付与)
           │      └─ postcssModules (CSSモジュール)
           │
           └─ postcss(plugins).process()
                  └─ 同期: result.css取得
                  └─ 非同期: Promise<result>返却
```

### データフロー図

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

CSSソースコード    ───▶ doCompileStyle            ───▶ SFCStyleCompileResults
                         │                            ├─ code (CSS)
                         ├─ プリプロセッサ             ├─ map
                         │   SCSS → CSS               ├─ errors
                         │                            ├─ modules
                         ├─ PostCSSパイプライン         │   (CSSモジュールマップ)
                         │   v-bind → var()           └─ dependencies
                         │   scoped → [data-v-xxx]
                         │   module → ハッシュ化
                         │
                         └─ 依存関係追跡
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| compileStyle.ts | `packages/compiler-sfc/src/compileStyle.ts` | ソース | スタイルコンパイラのメイン実装 |
| pluginTrim.ts | `packages/compiler-sfc/src/style/pluginTrim.ts` | ソース | 空白トリミングPostCSSプラグイン |
| pluginScoped.ts | `packages/compiler-sfc/src/style/pluginScoped.ts` | ソース | スコープ付きCSS PostCSSプラグイン |
| cssVars.ts | `packages/compiler-sfc/src/style/cssVars.ts` | ソース | CSS変数（v-bind）PostCSSプラグイン |
| preprocessors.ts | `packages/compiler-sfc/src/style/preprocessors.ts` | ソース | CSSプリプロセッサ統合 |
