# 機能設計書 37-ストリーミングレンダリング

## 概要

本ドキュメントは、Next.jsにおけるストリーミングレンダリング機能の設計を記述する。React Suspenseを活用したHTMLストリーミング配信により、ページの段階的な表示を実現し、ユーザーの体感パフォーマンスを向上させる機能である。

### 本機能の処理概要

**業務上の目的・背景**：従来のSSRでは、全てのデータ取得とレンダリングが完了するまでクライアントにHTMLを送信できなかった。ストリーミングレンダリングでは、準備ができた部分から順次HTMLを送信することで、TTFBの短縮とFirst Contentful Paint（FCP）の高速化を実現する。特にデータ取得に時間がかかるコンポーネントがある場合に効果が大きい。

**機能の利用シーン**：App RouterのServer Componentsで非同期データ取得を行うページ、`loading.tsx`によるSuspenseバウンダリを設定したページ、重いデータ取得を含むダッシュボードやフィードページで利用される。

**主要な処理内容**：
1. ReactDOMServer.renderToReadableStreamを使用したストリーミングHTML生成
2. Suspenseバウンダリでの分割ポイント管理
3. TransformStreamを活用したバッファリングとチャンク制御
4. ストリームの連結（chainStreams）による複数ストリームの結合
5. エンコードされたタグ（ENCODED_TAGS）を使用した効率的なバイナリ操作

**関連システム・外部連携**：React Suspense、ReactDOMServer、App Routerレンダリングパイプライン。

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | ストリーミングレンダリングは画面固有ではなく、全ページのレンダリングインフラとして機能する |

## 機能種別

レンダリング処理 / ストリーム処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| element | React.ReactElement | Yes | レンダリング対象のReact要素ツリー | 有効なReact要素 |
| streams | ReadableStream[] | No | 連結するストリームの配列 | - |
| maxBufferByteLength | number | No | バッファフラッシュ閾値（バイト） | 正の整数（デフォルト: Infinity） |

### 入力データソース

- ReactコンポーネントツリーからのReact要素
- サーバーサイドで生成されたHTMLストリーム

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| ReadableStream | ReadableStream<Uint8Array> | チャンク化されたHTMLストリーム |
| string | string | ストリームから変換されたHTML文字列（必要時） |

### 出力先

- HTTPレスポンスのTransfer-Encoding: chunkedとしてクライアントに段階的に送信

## 処理フロー

### 処理シーケンス

```
1. React要素ツリーの準備
   └─ Server ComponentsとSuspenseバウンダリの構築
2. renderToReadableStreamの呼び出し
   └─ ReactDOMServerによるストリーミングHTML生成開始
3. バッファリングTransformStreamの適用
   └─ 小さなチャンクをバッファリングしてフラッシュ効率を最適化
4. ストリームの段階的送信
   └─ Suspenseバウンダリの準備完了順にHTMLチャンクを送信
5. Suspense Fallbackの置換
   └─ 非同期コンポーネント完了後にfallback UIを実際のコンテンツで置換
6. ストリーム完了
   └─ 全てのSuspenseバウンダリが解決された後にストリームを閉じる
```

### フローチャート

```mermaid
flowchart TD
    A[React要素ツリー] --> B[renderToReadableStream]
    B --> C[初期HTMLシェル生成]
    C --> D[クライアントに送信開始]
    D --> E{Suspenseバウンダリ?}
    E -->|Yes| F[Fallback HTMLを送信]
    E -->|No| G[通常HTMLを送信]
    F --> H[非同期データ取得]
    H --> I[実コンテンツ生成]
    I --> J[Fallback置換スクリプト送信]
    G --> K{全バウンダリ解決?}
    J --> K
    K -->|No| E
    K -->|Yes| L[ストリーム完了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-37-01 | バッファリング | maxBufferByteLengthに達するかイベントループの次のティックでバッファをフラッシュする | ストリーミング中 |
| BR-37-02 | ストリーム連結 | chainStreamsは複数のReadableStreamを順次接続し、最後のストリームのみがwritableを閉じる | 複数ストリーム結合時 |
| BR-37-03 | 空ストリーム | ストリームが0個の場合は即座にcloseする空のReadableStreamを返す | streams.length === 0 |
| BR-37-04 | エラーハンドリング | ストリームのpipeToでのエラーはvoidCatchで抑制し、消費側で処理する | ストリームパイプ中 |

### 計算ロジック

特になし。

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

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | StreamError | ストリームのenqueue中にコントローラがエラー状態の場合 | エラーを無視し、消費側で処理する |
| MISSING_ROOT_TAGS_ERROR | Error | HTMLの基本構造タグが欠落している場合 | ルートレイアウトを正しく定義する |

### リトライ仕様

リトライは行わない。ストリーミングエラー時はエラー状態をクライアントに伝搬する。

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

該当なし。

## パフォーマンス要件

- TTFBの短縮：初期HTMLシェルを即座に送信することでTTFBを最小化
- バッファリングによるチャンク最適化：小さなチャンクの個別送信を避け、バッファリングにより効率化
- scheduleImmediateを使用したイベントループの効率的な利用

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

- ストリーミング中のデータはHTTPレスポンスとして送信されるため、TLS/SSL暗号化が推奨される
- AbortSignalによるストリームのキャンセルをサポート

## 備考

- ストリーミングレンダリングはApp Routerのデフォルト動作であり、Pages Routerでも部分的にサポートされる
- `loading.tsx`ファイルはSuspenseバウンダリのfallbackとして自動的に機能する
- Web Streamsの標準APIを使用しており、Node.jsとEdge Runtimeの両方で動作する

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | encoded-tags.ts | `packages/next/src/server/stream-utils/encoded-tags.ts` | エンコードされたHTMLタグ定数を確認する |
| 1-2 | uint8array-helpers.ts | `packages/next/src/server/stream-utils/uint8array-helpers.ts` | バイナリ操作ヘルパーを確認する |

**読解のコツ**: ストリーミング処理ではUint8Array（バイナリデータ）を直接操作する。TextEncoderとTextDecoderを使用してUTF-8文字列との変換を行う。

#### Step 2: コアストリーム操作を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | node-web-streams-helper.ts | `packages/next/src/server/stream-utils/node-web-streams-helper.ts` | ストリーム操作関数群を確認する |

**主要処理フロー**:
1. **37-78行目**: `chainStreams` - 複数のReadableStreamを順次連結する。preventCloseオプションで中間ストリームの完了時にwritableを閉じない
2. **81-88行目**: `streamFromString` - 文字列からReadableStreamを生成
3. **140-158行目**: `streamToString` - ReadableStreamからUTF-8文字列に変換。AbortSignal対応
4. **167-229行目**: `createBufferedTransformStream` - バッファリングTransformStream。scheduleImmediateでフラッシュをスケジュール

#### Step 3: レンダリング統合を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | render.tsx | `packages/next/src/server/render.tsx` | renderToInitialFizzStreamの利用を確認する |

**主要処理フロー**:
- **86行目**: `renderToInitialFizzStream`のインポート - React Fizzストリーミングレンダラーの統合

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

```
App/Pagesレンダリング
    │
    ├─ renderToReadableStream() [ReactDOMServer]
    │      └─ Suspenseバウンダリの段階的解決
    │
    ├─ createBufferedTransformStream()
    │      ├─ transform(chunk) → バッファリング
    │      └─ scheduleImmediate → flush()
    │
    ├─ chainStreams(stream1, stream2, ...)
    │      └─ pipeTo(writable, { preventClose })
    │
    └─ streamToString() [必要時]
           └─ TextDecoder.decode()
```

### データフロー図

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

React要素 ──────▶ renderToReadableStream() ──▶ HTMLストリーム
                        │
                  createBufferedTransformStream()
                        │
                  [バッファリング + scheduleImmediate]
                        │
                  chainStreams() ──────────────▶ 結合ストリーム
                        │
                  HTTPレスポンス ──────────────▶ チャンク化HTML
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| node-web-streams-helper.ts | `packages/next/src/server/stream-utils/node-web-streams-helper.ts` | ソース | ストリーム操作の中核ユーティリティ |
| encoded-tags.ts | `packages/next/src/server/stream-utils/encoded-tags.ts` | ソース | エンコード済みHTMLタグ定数 |
| uint8array-helpers.ts | `packages/next/src/server/stream-utils/uint8array-helpers.ts` | ソース | バイナリ操作ヘルパー |
| render.tsx | `packages/next/src/server/render.tsx` | ソース | Pages Routerレンダリング（ストリーム利用） |
