# 機能設計書 64-SSRヘルパー関数群

## 概要

本ドキュメントは、Vue 3の`@vue/server-renderer`パッケージが提供するSSRヘルパー関数群の設計仕様を記述する。これらの関数はテンプレートコンパイラが生成するSSR最適化コードから呼び出され、SSR出力のHTML文字列生成を効率化する。

### 本機能の処理概要

SSRヘルパー関数群は、Vueテンプレートコンパイラ（`@vue/compiler-ssr`）がSSRモードでコンパイルしたコードから呼び出される一連のランタイムヘルパー関数である。属性のレンダリング、リスト処理、テキスト補間、スロット・コンポーネント・Teleport・Suspenseのレンダリング、ディレクティブのSSRプロパティ取得、v-modelヘルパー等を含む。

**業務上の目的・背景**：VueのSSRでは、テンプレートコンパイラがSSR向けに最適化されたレンダリング関数を生成する。この最適化コードは仮想DOMを経由せず直接HTML文字列を生成するため、高速なSSRレンダリングが可能となる。SSRヘルパー関数群は、この最適化コードが呼び出すランタイム関数として、HTML属性のレンダリング、エスケープ処理、リスト反復等の共通処理を提供する。

**機能の利用シーン**：テンプレートコンパイラが生成するSSR最適化コードから内部的に呼び出される。開発者が直接使用することは通常ない。

**主要な処理内容**：
1. `ssrRenderAttrs()`: HTML属性文字列を生成する（class/style/動的属性の処理を含む）
2. `ssrRenderAttr()`: 静的キーの属性をレンダリングする
3. `ssrRenderDynamicAttr()`: 動的キーの属性をレンダリングする（ブーリアン属性、安全性チェック含む）
4. `ssrRenderClass()`: クラス属性の正規化とエスケープ
5. `ssrRenderStyle()`: スタイル属性の正規化とエスケープ
6. `ssrRenderList()`: v-forに対応するリスト反復処理
7. `ssrInterpolate()`: テキスト補間のエスケープ処理
8. `ssrRenderComponent()`: コンポーネントのSSRレンダリング
9. `ssrRenderSlot()` / `ssrRenderSlotInner()`: スロットコンテンツのSSRレンダリング
10. `ssrRenderTeleport()`: TeleportコンポーネントのSSRレンダリング
11. `ssrRenderSuspense()`: SuspenseコンポーネントのSSRレンダリング
12. `ssrGetDirectiveProps()`: ディレクティブのSSRプロパティ取得
13. `ssrRenderDynamicModel()` / `ssrGetDynamicModelProps()`: v-modelのSSRヘルパー
14. `ssrLooseEqual()` / `ssrLooseContain()`: v-model比較ヘルパー

**関連システム・外部連携**：`@vue/compiler-ssr`が生成するコードから呼び出される。`@vue/shared`の`escapeHtml`、`normalizeClass`、`normalizeStyle`等に依存。

**権限による制御**：特になし。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | サーバーサイドで実行される内部API。直接的な画面関連なし |

## 機能種別

HTML生成ユーティリティ（SSR向け内部ヘルパー関数群）

## 入力仕様

### 入力パラメータ

#### ssrRenderAttrs()

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| props | `Record<string, unknown>` | Yes | レンダリング対象のプロパティオブジェクト | - |
| tag | `string` | No | HTML要素のタグ名 | - |

#### ssrRenderList()

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| source | `unknown` | Yes | 反復対象（配列、文字列、数値、オブジェクト、イテラブル） | - |
| renderItem | `(value, key, index?) => void` | Yes | 各要素のレンダリング関数 | - |

#### ssrInterpolate()

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| value | `unknown` | Yes | 補間対象の値 | - |

#### ssrRenderComponent()

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| comp | `Component` | Yes | レンダリング対象コンポーネント | - |
| props | `Props \| null` | No | コンポーネントprops | - |
| children | `Slots \| SSRSlots \| null` | No | 子要素/スロット | - |
| parentComponent | `ComponentInternalInstance \| null` | No | 親コンポーネントインスタンス | - |
| slotScopeId | `string` | No | スロットスコープID | - |

### 入力データソース

テンプレートコンパイラが生成するSSR最適化コードから直接呼び出される。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| ssrRenderAttrs戻り値 | `string` | HTML属性文字列（例: ` class="foo" id="bar"`） |
| ssrRenderAttr戻り値 | `string` | 単一属性文字列（例: ` id="bar"`） |
| ssrRenderClass戻り値 | `string` | エスケープ済みクラス文字列 |
| ssrRenderStyle戻り値 | `string` | エスケープ済みスタイル文字列 |
| ssrInterpolate戻り値 | `string` | エスケープ済みテキスト文字列 |
| ssrRenderComponent戻り値 | `SSRBuffer \| Promise<SSRBuffer>` | レンダリング済みバッファ |
| ssrRenderList戻り値 | `void` | renderItemコールバック経由で出力 |

### 出力先

SSRバッファ（`push`関数経由）またはHTML文字列として直接返却。

## 処理フロー

### 処理シーケンス

#### ssrRenderAttrs()
```
1. propsオブジェクトの各キーをイテレーション
   ├─ key/ref/innerHTML/textContent/ref_key/ref_for → スキップ
   ├─ onXxx（イベントハンドラ） → スキップ
   ├─ textarea要素のvalue → スキップ
   ├─ .(ドット)プレフィックス（プロパティ強制） → スキップ
   ├─ ^(キャレット)プレフィックス → 属性名から除去
   ├─ class/className → ssrRenderClass()で処理
   ├─ style → ssrRenderStyle()で処理
   └─ その他 → ssrRenderDynamicAttr()で処理
```

#### ssrRenderList()
```
1. ソースの型を判定
   ├─ 配列/文字列 → for文で反復、renderItem(value, index)
   ├─ 数値 → 1からsourceまで反復、renderItem(i+1, i)
   └─ オブジェクト
       ├─ Symbol.iterator有り → Array.fromでイテレーション
       └─ 通常オブジェクト → Object.keysでイテレーション
```

### フローチャート

```mermaid
flowchart TD
    A[ssrRenderAttrs呼び出し] --> B[propsの各keyをループ]
    B --> C{スキップ対象?}
    C -->|Yes| B
    C -->|No| D{key種別}
    D -->|class/className| E[ssrRenderClass]
    D -->|style| F[ssrRenderStyle]
    D -->|その他| G[ssrRenderDynamicAttr]
    E --> H[ret += 属性文字列]
    F --> H
    G --> H
    H --> B
    B -->|完了| I[return ret]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-64-01 | 属性フィルタリング | key/ref/innerHTML/textContent/ref_key/ref_for/イベントハンドラはSSR出力から除外 | ssrRenderAttrs |
| BR-64-02 | ブーリアン属性 | isBooleanAttr()で判定し、trueなら属性名のみ出力、falseなら出力しない | ssrRenderDynamicAttr |
| BR-64-03 | 安全な属性名チェック | isSSRSafeAttrName()で属性名の安全性を検証し、安全でない場合は警告を出して出力しない | ssrRenderDynamicAttr |
| BR-64-04 | HTMLエスケープ | 属性値は必ずescapeHtml()でエスケープする | ssrRenderAttr/ssrRenderDynamicAttr |
| BR-64-05 | リスト反復の整数チェック | 数値ソースの場合、開発モードでは整数チェックを行い警告を出す | ssrRenderList |
| BR-64-06 | v-modelの型別処理 | radio→looseEqual比較、checkbox→配列ならssrLooseContain/値ならtruthy判定、text→value属性出力 | ssrRenderDynamicModel |

### 計算ロジック

特になし。

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

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 警告 | 安全でない属性名がSSR出力に含まれる場合 | console.warnで警告。属性は出力されない |
| - | 警告 | v-forの数値ソースが整数でない場合（開発モード） | warnで警告 |

### リトライ仕様

該当なし。

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

該当なし。

## パフォーマンス要件

- 各ヘルパー関数は文字列連結で直接HTML文字列を生成するため、仮想DOM経由よりも高速
- `ssrRenderAttrs()`は`makeMap()`でスキップ対象を事前計算し、ルックアップを高速化

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

- `escapeHtml()`による属性値のエスケープ処理でXSSを防止
- `isSSRSafeAttrName()`による安全でない属性名のフィルタリング
- `ssrInterpolate()`でテキスト補間値をエスケープ

## 備考

- これらのヘルパー関数は`@vue/server-renderer`の`internal`モジュールからエクスポートされる
- テンプレートコンパイラ（`@vue/compiler-ssr`）はこれらの関数名をハードコードしてSSRコードを生成する
- CSSカスタムプロパティ（`--`プレフィックス）はhyphenate変換されずそのまま出力される

---

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

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

### 推奨読解順序

#### Step 1: エクスポート構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | internal.ts | `packages/server-renderer/src/internal.ts` | 全SSRヘルパー関数のエクスポート一覧（1-25行目）。ssrRenderVNode、ssrRenderComponent、ssrRenderSlot等 |

**読解のコツ**: `internal.ts`は全てのSSRヘルパーを再エクスポートするバレルモジュール。ここを起点に各ヘルパーの定義元を辿る。

#### Step 2: 属性レンダリング系を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ssrRenderAttrs.ts | `packages/server-renderer/src/helpers/ssrRenderAttrs.ts` | ssrRenderAttrs()（27-54行目）: propsの各キーを処理しHTML属性文字列を生成 |
| 2-2 | ssrRenderAttrs.ts | `packages/server-renderer/src/helpers/ssrRenderAttrs.ts` | ssrRenderDynamicAttr()（57-79行目）: 動的属性のレンダリング。ブーリアン属性・安全性チェック |
| 2-3 | ssrRenderAttrs.ts | `packages/server-renderer/src/helpers/ssrRenderAttrs.ts` | ssrRenderClass()（90-92行目）、ssrRenderStyle()（94-103行目） |

**主要処理フロー**:
- **23-25行目**: shouldIgnoreProp: key/ref/innerHTML/textContent/ref_key/ref_forをスキップ
- **34-41行目**: isOn(key)チェック、textarea value、.プレフィックスのスキップ
- **44行目**: ^プレフィックス除去
- **45-51行目**: class→ssrRenderClass、style→ssrRenderStyle、その他→ssrRenderDynamicAttr

#### Step 3: リスト・補間・コンポーネント系を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ssrRenderList.ts | `packages/server-renderer/src/helpers/ssrRenderList.ts` | ssrRenderList()（4-34行目）: 配列/文字列/数値/オブジェクト/イテラブルの各ソース型に対応 |
| 3-2 | ssrInterpolate.ts | `packages/server-renderer/src/helpers/ssrInterpolate.ts` | ssrInterpolate()（3-5行目）: escapeHtml(toDisplayString(value)) |
| 3-3 | ssrRenderComponent.ts | `packages/server-renderer/src/helpers/ssrRenderComponent.ts` | ssrRenderComponent()（10-22行目）: createVNode→renderComponentVNode |

#### Step 4: スロット・Teleport・Suspense系を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | ssrRenderSlot.ts | `packages/server-renderer/src/helpers/ssrRenderSlot.ts` | ssrRenderSlot()（20-41行目）: フラグメントコメントでラップ。ssrRenderSlotInner()（43-129行目）: スロット関数呼び出しとフォールバック処理 |
| 4-2 | ssrRenderTeleport.ts | `packages/server-renderer/src/helpers/ssrRenderTeleport.ts` | ssrRenderTeleport()（9-43行目）: テレポートマーカーの挿入とバッファ管理 |
| 4-3 | ssrRenderSuspense.ts | `packages/server-renderer/src/helpers/ssrRenderSuspense.ts` | ssrRenderSuspense()（3-12行目）: defaultスロットのレンダリング |

#### Step 5: v-model・ディレクティブ系を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | ssrVModelHelpers.ts | `packages/server-renderer/src/helpers/ssrVModelHelpers.ts` | ssrRenderDynamicModel()（11-27行目）: type別のv-model SSR処理。ssrGetDynamicModelProps()（30-46行目） |
| 5-2 | ssrGetDirectiveProps.ts | `packages/server-renderer/src/helpers/ssrGetDirectiveProps.ts` | ssrGetDirectiveProps()（3-26行目）: ディレクティブのgetSSRProps呼び出し |

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

```
[SSR最適化コード (compiler-ssr生成)]
    │
    ├─ ssrRenderAttrs(props, tag)
    │      ├─ ssrRenderClass(value)
    │      │      └─ normalizeClass() → escapeHtml()
    │      ├─ ssrRenderStyle(value)
    │      │      └─ normalizeStyle() → stringifyStyle() → escapeHtml()
    │      └─ ssrRenderDynamicAttr(key, value, tag)
    │             └─ escapeHtml()
    │
    ├─ ssrRenderList(source, renderItem)
    │
    ├─ ssrInterpolate(value)
    │      └─ toDisplayString() → escapeHtml()
    │
    ├─ ssrRenderComponent(comp, props, children, parent)
    │      └─ createVNode() → renderComponentVNode()
    │
    ├─ ssrRenderSlot(slots, name, props, fallback, push, parent)
    │      └─ ssrRenderSlotInner()
    │
    ├─ ssrRenderTeleport(parentPush, renderFn, target, disabled, parent)
    │      └─ createBuffer() → contentRenderFn()
    │
    ├─ ssrRenderSuspense(push, { default: renderContent })
    │
    ├─ ssrGetDirectiveProps(instance, dir, value, arg, modifiers)
    │
    └─ ssrRenderDynamicModel(type, model, value)
           └─ ssrLooseEqual() / ssrLooseContain()
```

### データフロー図

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

コンポーネント
props/attrs ────▶ ssrRenderAttrs() ────────────▶ HTML属性文字列
                         │
テンプレート式 ──▶ ssrInterpolate() ───────────▶ エスケープ済みテキスト
                         │
v-forソース ────▶ ssrRenderList() ─────────────▶ 反復レンダリング出力
                         │
子コンポーネント ─▶ ssrRenderComponent() ──────▶ SSRBuffer
                         │
スロット定義 ────▶ ssrRenderSlot() ────────────▶ スロットHTML出力
                         │
Teleport ────────▶ ssrRenderTeleport() ────────▶ マーカー + バッファ
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| internal.ts | `packages/server-renderer/src/internal.ts` | ソース | SSRヘルパー関数群のエクスポートバレル |
| ssrRenderAttrs.ts | `packages/server-renderer/src/helpers/ssrRenderAttrs.ts` | ソース | 属性レンダリングヘルパー |
| ssrRenderList.ts | `packages/server-renderer/src/helpers/ssrRenderList.ts` | ソース | リスト反復ヘルパー |
| ssrInterpolate.ts | `packages/server-renderer/src/helpers/ssrInterpolate.ts` | ソース | テキスト補間ヘルパー |
| ssrRenderComponent.ts | `packages/server-renderer/src/helpers/ssrRenderComponent.ts` | ソース | コンポーネントレンダリングヘルパー |
| ssrRenderSlot.ts | `packages/server-renderer/src/helpers/ssrRenderSlot.ts` | ソース | スロットレンダリングヘルパー |
| ssrRenderTeleport.ts | `packages/server-renderer/src/helpers/ssrRenderTeleport.ts` | ソース | Teleportレンダリングヘルパー |
| ssrRenderSuspense.ts | `packages/server-renderer/src/helpers/ssrRenderSuspense.ts` | ソース | Suspenseレンダリングヘルパー |
| ssrGetDirectiveProps.ts | `packages/server-renderer/src/helpers/ssrGetDirectiveProps.ts` | ソース | ディレクティブSSRプロパティ取得 |
| ssrVModelHelpers.ts | `packages/server-renderer/src/helpers/ssrVModelHelpers.ts` | ソース | v-model SSRヘルパー |
| ssrCompile.ts | `packages/server-renderer/src/helpers/ssrCompile.ts` | ソース | ランタイムSSRコンパイル |
