# 帳票設計書 10-SSR Webストリーム

## 概要

本ドキュメントは、Vue.jsのserver-rendererパッケージにおける`renderToWebStream`関数が出力するWeb Streams APIのReadableStreamの設計仕様を記述する。VueアプリケーションをWeb ReadableStreamとして出力し、TextEncoderでエンコードされたバイトストリームを生成する。

### 本帳票の処理概要

server-rendererの`renderToWebStream`関数は、Vue AppインスタンスまたはVNodeを入力として受け取り、Web Streams APIの`ReadableStream`を生成して返す。内部では`renderToSimpleStream`を使用してSSRBufferを逐次的に展開し、TextEncoderでUTF-8バイト列にエンコードした上で`ReadableStreamDefaultController.enqueue`でチャンクを送出する。

**業務上の目的・背景**：Web Streams APIはブラウザ標準のストリームインターフェースであり、Node.js以外の環境（Deno、CloudFlare Workers、Vercel Edge Functions等のEdge Runtime）でも利用可能である。renderToWebStreamはこれらの環境でVueのSSRストリーミングを可能にする。

**帳票の利用シーン**：Web Streams APIをサポートする環境（Edge Runtime、Deno、モダンNode.js等）でVueアプリケーションのSSRレンダリングをストリーミングで行う場面。

**主要な出力内容**：
1. Web ReadableStream - TextEncoderでエンコードされたUint8Arrayチャンクを含むストリーム

**帳票の出力タイミング**：サーバーサイド/Edge RuntimeでHTTPリクエストを受信し、ストリーミングSSRレンダリングが必要な場面で実行される。

**帳票の利用者**：Edge Runtimeフレームワーク（Nuxt on Edge等）、Deno環境、Web Streams対応のNode.jsサーバー。

## 帳票種別

レンダリング結果（ストリーム出力）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | SSRサーバー（Edge/Web） | 全てのルート | HTTPリクエスト受信時に実行 |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | Web ReadableStream（Uint8Arrayチャンク） |
| 用紙サイズ | 該当なし |
| 向き | 該当なし |
| ファイル名 | インメモリ（HTTPレスポンスとして送信） |
| 出力方法 | 関数戻り値（ReadableStream）をResponse等で送出 |
| 文字コード | UTF-8（TextEncoderによるエンコード） |

### PDF固有設定

該当なし

### Excel固有設定

該当なし

## 帳票レイアウト

### レイアウト概要

出力はWeb ReadableStreamで、TextEncoderでエンコードされたHTMLチャンク（Uint8Array）が逐次的にenqueueされる。

```
┌─────────────────────────────────────┐
│  ReadableStream (Web Streams API)   │
│                                     │
│  chunk1: Uint8Array (エンコード済み) │
│  chunk2: Uint8Array (エンコード済み) │
│  chunk3: Uint8Array (エンコード済み) │
│  controller.close() (終了)          │
└─────────────────────────────────────┘
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | stream | Web ReadableStream | new ReadableStream({...}) | ReadableStream |
| 2 | encoder | TextEncoder（UTF-8エンコード用） | new TextEncoder() | TextEncoder |

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | chunks | エンコード済みHTMLチャンク | encoder.encode(content) -> controller.enqueue() | Uint8Array | - |

### フッター部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | close | ストリーム終了 | controller.close() | void |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| input | Vue AppインスタンスまたはVNode | Yes |
| context | SSRContext | No（デフォルト: {}） |

### ソート順

該当なし

### 改ページ条件

該当なし

## データベース参照仕様

該当なし（インメモリレンダリング）

### 参照テーブル一覧

該当なし

### テーブル別参照項目詳細

該当なし

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| encoder | new TextEncoder() | - | UTF-8エンコード |
| encodedChunk | encoder.encode(content) | - | HTML文字列をUint8Arrayに変換 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[renderToWebStream呼び出し] --> B{ReadableStream利用可能?}
    B -->|No| C[エラーをスロー]
    B -->|Yes| D[TextEncoder生成]
    D --> E[new ReadableStream生成]
    E --> F[start: renderToSimpleStream呼び出し]
    F --> G[stream返却（即座に）]
    G --> H[非同期:renderComponentVNode]
    H --> I[非同期:unrollBuffer]
    I --> J{content != null?}
    J -->|Yes| K[encoder.encode -> controller.enqueue]
    J -->|No| L[controller.close - 終了]
    K --> I
    L --> M[完了]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| ReadableStream未サポート | グローバルスコープにReadableStreamがない | ReadableStream constructor is not available in the global scope... | pipeToWebWritableを使用 |
| レンダリングエラー | コンポーネント内でエラー発生 | controller.error(err) | コンポーネントのエラーを修正 |
| キャンセル | クライアントがストリームをキャンセル | cancelled=trueで以降のenqueueをスキップ | 正常な動作（クライアント切断等） |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 1リクエストにつき1回 |
| 目標出力時間 | TTFBの改善（チャンク単位で逐次送出） |
| 同時出力数上限 | サーバーリソースに依存 |

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

renderToStringと同様のセキュリティ考慮事項が適用される。ストリームのキャンセル処理が実装されており、クライアント切断時にサーバーリソースの無駄な消費を防止する。Edge Runtime環境では、ランタイムのセキュリティモデル（サンドボックス等）に従ったデータアクセスが行われる。

## 備考

- `ReadableStream`コンストラクターがグローバルスコープで利用可能でない場合はエラーがスローされ、代替として`pipeToWebWritable`の使用が推奨される。
- TextEncoderで文字列をUint8Arrayにエンコードするため、バイナリレベルでのストリーミングとなる。
- `cancel`コールバックが実装されており、クライアントがストリームをキャンセルした場合は`cancelled`フラグが立ち、以降のenqueueはスキップされる。
- `pipeToWebWritable`は同等の機能を持つが、既存のWritableStreamインスタンスに書き込む形式。CloudFlare Workers等での`writer.ready`互換性対応も含まれる。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | renderToStream.ts | `packages/server-renderer/src/renderToStream.ts` | SimpleReadable型（16-19行目）- push/destroyインターフェース（Web版でも同じ抽象） |
| 1-2 | render.ts | `packages/server-renderer/src/render.ts` | SSRBuffer型（42行目）、SSRContext型（47-58行目） |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | renderToStream.ts | `packages/server-renderer/src/renderToStream.ts` | renderToWebStream関数（145-180行目）がエントリーポイント |

**主要処理フロー**:
1. **149-155行目**: ReadableStreamコンストラクターの存在確認。なければエラー
2. **157行目**: TextEncoder生成
3. **158行目**: cancelledフラグ初期化（false）
4. **160-175行目**: new ReadableStream({start(controller) {...}, cancel() {...}})
5. **162-174行目**: start内でrenderToSimpleStreamを呼び出し。push: enqueue/close、destroy: error
6. **164行目**: cancelledチェック（キャンセル済みなら何もしない）
7. **165-168行目**: content != null の場合、encoder.encode(content)してcontroller.enqueue
8. **169行目**: content == null の場合、controller.close()
9. **176-178行目**: cancel()で cancelled = true

#### Step 3: 基盤処理（renderToSimpleStream）を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | renderToStream.ts | `packages/server-renderer/src/renderToStream.ts` | renderToSimpleStream関数（56-92行目）- No.9と同じ基盤 |

#### Step 4: 代替API（pipeToWebWritable）を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | renderToStream.ts | `packages/server-renderer/src/renderToStream.ts` | pipeToWebWritable関数（182-214行目）- WritableStreamへのパイプ出力、writer.ready互換性対応 |

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

```
renderToWebStream (renderToStream.ts:145)
    |
    +-- ReadableStream利用可能チェック
    |
    +-- new TextEncoder()
    |
    +-- new ReadableStream({ start(controller), cancel() })
            |
            +-- renderToSimpleStream (renderToStream.ts:56)
                    |
                    +-- [VNode入力時] createApp -> 再帰呼び出し
                    |
                    +-- createVNode(input._component, input._props)
                    +-- input.provide(ssrContextKey, context)
                    |
                    +-- renderComponentVNode (render.ts)
                    |       +-- SSRBuffer を生成
                    |
                    +-- unrollBuffer (renderToStream.ts:21)
                    |       +-- push: encoder.encode(content) -> controller.enqueue()
                    |       +-- push(null): controller.close()
                    |
                    +-- resolveTeleports (renderToString.ts)
                    |
                    +-- [エラー時] controller.error(err)
```

### データフロー図

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

App / VNode          ──▶  renderToSimpleStream     ──▶  ReadableStream (Web)
                                |
SSRContext                 renderComponentVNode      ──▶  SSRBuffer
                                |
                           unrollBuffer
                                |
                           TextEncoder.encode        ──▶  Uint8Array
                                |
                           controller.enqueue        ──▶  ReadableStream チャンク
                                |
                           controller.close          ──▶  ストリーム終了
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| renderToStream.ts | `packages/server-renderer/src/renderToStream.ts` | ソース | renderToWebStream、pipeToWebWritable、renderToSimpleStream、unrollBuffer |
| renderToString.ts | `packages/server-renderer/src/renderToString.ts` | ソース | resolveTeleports関数 |
| render.ts | `packages/server-renderer/src/render.ts` | ソース | renderComponentVNode、SSRBuffer/SSRContext型 |
