# 機能設計書 27-hydrate()

## 概要

本ドキュメントは、Vue 3の`hydrate()`関数の機能設計を記述する。サーバーサイドレンダリング（SSR）で生成されたHTML DOMに対して、クライアント側のインタラクティビティ（イベントリスナー、リアクティブ更新等）を付与するための関数である。

### 本機能の処理概要

`hydrate()`は、SSRで事前にレンダリングされたHTML要素に対してVNodeツリーを「合流」させ、既存のDOM要素を再利用しながらVueのリアクティブシステムとイベントハンドリングを接続する。通常の`render()`が新規にDOM要素を生成するのに対し、`hydrate()`は既存のDOMノードを再利用する点が異なる。

**業務上の目的・背景**：SSRアプリケーションにおいて、サーバーが生成したHTMLは静的であり、ユーザーインタラクションに対応できない。hydrationプロセスにより、既存のDOMを破棄して再構築することなく、クライアント側のリアクティビティとイベントハンドリングを効率的に付与し、初期表示の高速化とインタラクティビティの確保を両立する。

**機能の利用シーン**：SSRアプリケーションのクライアント側初期化（`createSSRApp().mount()`内部）、プリレンダリングされたHTMLの活性化、Progressive Enhancement対応。

**主要な処理内容**：
1. `hydrate(vnode, container)`の呼び出し
2. コンテナに子ノードが存在しない場合はフルマウントにフォールバック
3. 子ノードが存在する場合は`hydrateNode`で既存のDOMノードとVNodeをマッチング
4. DOMノードとVNodeの型不一致（ミスマッチ）を検出した場合は警告とフォールバック処理
5. `flushPostFlushCbs()`で保留中のコールバックをフラッシュ
6. `container._vnode = vnode`でVNode参照を記録

**関連システム・外部連携**：`createSSRApp()`（SSR対応アプリケーション作成）、`createHydrationRenderer()`（hydration対応レンダラー生成）、`@vue/server-renderer`（HTML生成）と連携する。

**権限による制御**：権限による制御は存在しない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 画面機能マッピングに直接の関連画面なし。SSR対応アプリケーションの初期化で内部的に使用される |

## 機能種別

DOM操作 / ハイドレーション

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| vnode | VNode\<Node, Element\> | Yes | ハイドレートするVNodeツリー | なし |
| container | (Element \| ShadowRoot) & { _vnode?: VNode } | Yes | SSRで生成されたDOMを含むコンテナ要素 | なし |

### 入力データソース

`createSSRApp().mount()`内部からの呼び出し。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| void | void | 戻り値なし。副作用として既存DOMにリアクティビティを付与する |

### 出力先

引数で指定されたDOMコンテナ要素内の既存DOM要素。

## 処理フロー

### 処理シーケンス

```
1. hydrate(vnode, container) 呼び出し
   └─ ensureHydrationRenderer() でhydration対応レンダラーを遅延生成
2. container.hasChildNodes() チェック
   ├─ 子ノードなし：警告を出力しpatch(null, vnode, container)でフルマウント
   └─ 子ノードあり：hydrateNode(container.firstChild!, vnode, null, null, null)
3. flushPostFlushCbs() で保留コールバックをフラッシュ
4. container._vnode = vnode でVNode参照を記録
```

### フローチャート

```mermaid
flowchart TD
    A[hydrate vnode, container] --> B{container.hasChildNodes?}
    B -->|No| C[警告出力]
    C --> D[patch null, vnode, container でフルマウント]
    B -->|Yes| E[hydrateNode container.firstChild, vnode]
    E --> F{ノードタイプ一致?}
    F -->|Yes| G[DOMノード再利用 + イベント/リアクティビティ接続]
    F -->|No| H[ミスマッチ警告 + handleMismatch]
    D --> I[flushPostFlushCbs]
    G --> I
    H --> I
    I --> J[container._vnode = vnode]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-27-01 | フルマウントフォールバック | コンテナに子ノードが存在しない場合、通常のpatch処理でフルマウントを行う | container.hasChildNodes() === false |
| BR-27-02 | ミスマッチ検出 | VNodeとDOMノードの型が不一致の場合、ミスマッチとして検出し警告を出力する | hydrateNode処理中 |
| BR-27-03 | ミスマッチログ制限 | ミスマッチエラーログはアプリケーション全体で1回のみ出力される（hasLoggedMismatchError） | 本番環境 |
| BR-27-04 | 遅延hydrationレンダラー | ensureHydrationRenderer()によりhydration対応レンダラーは初回使用時に遅延生成される | 初回hydrate呼び出し時 |
| BR-27-05 | DOM再利用 | 既存のDOMノードのel参照をVNodeに設定し、DOM再作成を回避する | hydrateNode処理中 |

### 計算ロジック

該当なし。

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

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

該当なし（クライアントサイドフレームワーク機能）。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 開発/本番警告 | コンテナが空（子ノードなし）の場合 | フルマウントにフォールバック |
| - | コンソールエラー | DOMとVNodeのミスマッチ検出時 | `Hydration completed but contains mismatches.`を本番でも1回出力 |

### リトライ仕様

リトライ機構は存在しない。ミスマッチ時はhandleMismatchにより部分的な再マウントが行われる。

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

該当なし。

## パフォーマンス要件

- 既存DOMの再利用によりDOM生成コストを削減し、TTI（Time to Interactive）を短縮
- ミスマッチ発生時は対象部分のみ再マウントし、全体の再描画を回避

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

- SSRで生成されたHTMLが信頼できるソースからのものであることが前提。改竄されたDOMに対するhydrationは予期しない動作を引き起こす可能性がある

## 備考

- `@vue/runtime-dom`の`hydrate`は`ensureHydrationRenderer().hydrate(...args)`を呼び出すラッパー関数
- `createHydrationFunctions`は`hydration.ts`で定義され、hydrateとhydrateNodeの2つの関数を返す
- `createSSRApp()`は内部で`ensureHydrationRenderer().createApp()`を呼び出す
- SVG/MathML名前空間は`getContainerType`関数で自動検出される

---

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

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

### 推奨読解順序

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

RootHydrateFunction型とDOMNodeTypes列挙を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | hydration.ts | `packages/runtime-core/src/hydration.ts` | `RootHydrateFunction`型（47-50行目）。`(vnode, container) => void` |
| 1-2 | hydration.ts | `packages/runtime-core/src/hydration.ts` | `DOMNodeTypes`列挙型（52-56行目）。ELEMENT=1, TEXT=3, COMMENT=8 |

**読解のコツ**: hydration処理はDOMノードのnodeTypeプロパティを基にVNodeとのマッチングを行う。DOMNodeTypesはこの判定に使用される定数。

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

`@vue/runtime-dom`のhydrate関数とensureHydrationRenderer。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | index.ts | `packages/runtime-dom/src/index.ts` | hydrate関数エクスポート（94-96行目）。ensureHydrationRenderer().hydrate(...args) |
| 2-2 | index.ts | `packages/runtime-dom/src/index.ts` | ensureHydrationRenderer関数（81-87行目）。createHydrationRenderer(rendererOptions) |

**主要処理フロー**:
1. **81-87行目**: `ensureHydrationRenderer()`。enabledHydration未設定の場合に`createHydrationRenderer(rendererOptions)`を呼ぶ
2. **94-96行目**: `hydrate`はensureHydrationRenderer().hydrate(...args)のラッパー

#### Step 3: hydrate関数の内部実装を理解する

createHydrationFunctions内のhydrate関数を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | hydration.ts | `packages/runtime-core/src/hydration.ts` | createHydrationFunctions関数（92-104行目の返り値型定義）、hydrate関数（119-135行目） |

**主要処理フロー**:
- **119行目**: `const hydrate: RootHydrateFunction = (vnode, container) => {`
- **120-129行目**: `!container.hasChildNodes()`の場合、警告後`patch(null, vnode, container)`でフルマウント
- **132行目**: `hydrateNode(container.firstChild!, vnode, null, null, null)`で既存DOMとVNodeのマッチング開始
- **133行目**: `flushPostFlushCbs()`
- **134行目**: `container._vnode = vnode`

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

```
hydrate(vnode, container)  [runtime-dom/src/index.ts:94]
    │
    └─ ensureHydrationRenderer().hydrate(...)
           │
           └─ createHydrationFunctions内のhydrate関数  [hydration.ts:119]
                  │
                  ├─ !hasChildNodes()
                  │      └─ patch(null, vnode, container)  [フルマウント]
                  │
                  └─ hasChildNodes()
                         └─ hydrateNode(firstChild, vnode, ...)
                                ├─ ELEMENT → hydrateElement
                                ├─ TEXT → テキスト比較・更新
                                ├─ COMMENT → コメント処理
                                └─ COMPONENT → mountComponent
```

### データフロー図

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

SSR生成DOM       ───▶ hydrate()                    ───▶ リアクティブDOM
VNode            ───▶   │                                │
                         ├─ hydrateNode                   ├─ vnode.el = node
                         │     └─ DOMノードとVNodeマッチ   ├─ イベントリスナー接続
                         │                                └─ リアクティブ更新有効化
                         └─ flushPostFlushCbs
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.ts | `packages/runtime-dom/src/index.ts` | ソース | hydrate関数エクスポート、ensureHydrationRenderer |
| hydration.ts | `packages/runtime-core/src/hydration.ts` | ソース | createHydrationFunctions、hydrateとhydrateNodeの実装 |
| renderer.ts | `packages/runtime-core/src/renderer.ts` | ソース | createHydrationRenderer、baseCreateRenderer |
| scheduler.ts | `packages/runtime-core/src/scheduler.ts` | ソース | flushPostFlushCbs |
