# 機能設計書 34-サーバーサイドレンダリング（SSR）

## 概要

本ドキュメントは、Next.jsにおけるサーバーサイドレンダリング（SSR）機能の設計を記述する。SSRは各リクエスト時にサーバー上でHTMLを生成し、完全にレンダリングされたページをクライアントに配信する機能である。

### 本機能の処理概要

**業務上の目的・背景**：SEO対応、初期表示速度の向上、ユーザー固有のコンテンツ（認証状態に依存するページ等）の配信が必要な場面で、クライアントサイドレンダリングでは達成できない要件を満たすためにSSRが使用される。リクエストごとに最新のデータでHTMLを生成することで、動的なコンテンツをSEOフレンドリーに提供できる。

**機能の利用シーン**：Pages Routerでは`getServerSideProps`を使用してリクエスト時のデータ取得を行うページ、App RouterではデフォルトのServer Componentsによるレンダリング、`getInitialProps`を使用する従来型のページで利用される。

**主要な処理内容**：
1. リクエスト受信時のサーバーサイドでのReactコンポーネントレンダリング
2. `getServerSideProps`によるリクエスト時データ取得
3. `renderToHTMLImpl`によるHTML文字列生成
4. ReactDOMServerのrenderToReadableStreamを使用したストリーム生成
5. `__NEXT_DATA__`によるサーバーデータのクライアントへの引き渡し

**関連システム・外部連携**：Pages Routerモジュール、App Routerモジュール、Documentコンポーネント、Appコンポーネント、レスポンスキャッシュ。

**権限による制御**：SSR自体に権限制御はないが、`getServerSideProps`内でリクエストのcookieやヘッダーに基づく認証・認可処理を実装可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | エラーページ (_error) | 結果表示画面 | getInitialPropsによるステータスコード取得とSSR |
| 2 | ドキュメント (_document) | 補助画面 | サーバーサイドのみでのドキュメントレンダリング処理 |
| 3 | アプリケーションラッパー (_app) | 補助画面 | getInitialPropsによる初期データ取得 |
| 17 | ルート情報パネル | 参照画面 | Dynamicルートの判定情報を表示 |

## 機能種別

レンダリング処理 / データ取得

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| req | IncomingMessage | Yes | HTTPリクエストオブジェクト | - |
| res | ServerResponse | Yes | HTTPレスポンスオブジェクト | - |
| pathname | string | Yes | リクエストパス | 有効なページパス |
| query | NextParsedUrlQuery | Yes | URLクエリパラメータ | - |
| renderOpts | RenderOpts | Yes | レンダリングオプション | - |

### 入力データソース

- HTTPリクエスト（ヘッダー、cookie、URL、クエリパラメータ）
- `getServerSideProps`の戻り値（props、redirect、notFound）
- ビルドマニフェスト、Reactのloadableマニフェスト

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| RenderResult | RenderResult | レンダリング結果（HTMLストリームまたは文字列） |
| metadata | PagesRenderResultMetadata | revalidate値、リダイレクト情報等のメタデータ |

### 出力先

- HTTPレスポンスとしてクライアントに送信

## 処理フロー

### 処理シーケンス

```
1. リクエスト受信
   └─ ルーティングによりレンダリング対象ページを特定
2. コンポーネント読み込み
   └─ loadComponents()でApp、Document、Componentを読み込み
3. データフェッチ方式の判定
   └─ getServerSideProps / getInitialProps / 自動静的最適化を判別
4. getServerSidePropsの実行（該当する場合）
   └─ ctx（req, res, query, params等）を渡してデータ取得
   └─ 戻り値の検証（props/redirect/notFound）
5. レンダリング実行
   └─ renderPageTree()でAppがComponentをラップ
   └─ ReactDOMServer.renderToReadableStream()でHTML生成
6. Document.getInitialPropsの実行
   └─ renderPage()を通じたHTML取得
7. HTMLの後処理とレスポンス送信
   └─ postProcessHTML()でHTML最適化
   └─ __NEXT_DATA__の埋め込み
```

### フローチャート

```mermaid
flowchart TD
    A[リクエスト受信] --> B[loadComponents]
    B --> C{データフェッチ方式}
    C -->|getServerSideProps| D[getServerSideProps実行]
    C -->|getInitialProps| E[getInitialProps実行]
    C -->|AutoExport| F[静的最適化]
    D --> G{戻り値チェック}
    G -->|redirect| H[リダイレクト]
    G -->|notFound| I[404ページ]
    G -->|props| J[レンダリング]
    E --> J
    F --> J
    J --> K[renderPageTree]
    K --> L[ReactDOMServer.renderToReadableStream]
    L --> M[Document.getInitialProps]
    M --> N[HTML後処理]
    N --> O[レスポンス送信]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-34-01 | SSGとgetInitialPropsの排他 | getStaticPropsとgetInitialPropsは同時に使用できない | 同一ページにSSGとgetInitialPropsが存在する場合 |
| BR-34-02 | SSRとSSGの排他 | getServerSidePropsとgetStaticPropsは同時に使用できない | 同一ページに両方が存在する場合 |
| BR-34-03 | 自動静的最適化 | getInitialProps/getServerSideProps/getStaticPropsのいずれも持たないページは自動的に静的最適化される | defaultAppGetInitialProps かつ ページにgetInitialPropsなし |
| BR-34-04 | export制限 | getServerSidePropsはoutput: exportと併用できない | nextConfigOutput === 'export' |
| BR-34-05 | シリアライズ可能性 | getServerSidePropsの戻り値はJSON.stringifyでシリアライズ可能でなければならない | 常時 |

### 計算ロジック

自動静的最適化の判定:
```
isAutoExport = !hasPageGetInitialProps && defaultAppGetInitialProps && !isSSG && !getServerSideProps
```

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

該当なし。SSR自体はデータベース操作を行わないが、`getServerSideProps`内で開発者がデータベースアクセスを実装する。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | Error | getStaticPropsとgetInitialPropsの競合 | いずれか一方のみを使用する |
| - | Error | getServerSidePropsとgetStaticPropsの競合 | いずれか一方のみを使用する |
| - | Error | getServerSidePropsとgetInitialPropsの競合 | いずれか一方のみを使用する |
| - | Error | getServerSidePropsでprops/redirect/notFound以外のキーが返された場合 | 許可されたキーのみを返す |
| - | Error | コンポーネントが有効なReactコンポーネントでない場合 | デフォルトエクスポートを修正する |

### リトライ仕様

リトライは行わない。サーバーエラー発生時はエラーページを表示する。

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

該当なし。

## パフォーマンス要件

- SSRはリクエストごとにサーバーでHTMLを生成するため、レスポンス時間はgetServerSidePropsの処理時間に依存する
- ReactDOMServer.renderToReadableStreamを使用してストリーミングレスポンスが可能
- キャッシュ制御ヘッダーにより、CDNでのキャッシュを活用できる

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

- getServerSidePropsはサーバーサイドでのみ実行されるため、データベース接続情報等の秘密情報を安全に使用可能
- ただし、propsとして返されたデータはクライアントに送信されるため、機密情報を含めないこと
- Cookieベースの認証処理はgetServerSidePropsのctx.reqから実装可能

## 備考

- Pages Routerでは`getServerSideProps`がSSRの主要なデータ取得手段である
- App Routerでは、Server Componentsがデフォルトでサーバーサイドレンダリングされる
- `Cache-Control: private, no-cache, no-store, max-age=0, must-revalidate`がデフォルトで設定される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | render.tsx | `packages/next/src/server/render.tsx` | RenderOptsPartial、PagesSharedContext、PagesRenderContextの型定義を確認する |

**読解のコツ**: **243-291行目**に`RenderOptsPartial`が定義されている。`getServerSideProps`、`getStaticProps`等のデータフェッチ関数はrenderOptsの一部として渡される。**299-335行目**で共有コンテキスト型が定義されている。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | render.tsx | `packages/next/src/server/render.tsx` | renderToHTMLImpl関数の実装を確認する |

**主要処理フロー**:
1. **444-453行目**: 関数シグネチャ - req, res, pathname, query, renderOpts等を受け取る
2. **519-521行目**: isSSG/isBuildTimeSSGの判定
3. **547-551行目**: isAutoExport（自動静的最適化）の判定
4. **565-601行目**: データフェッチ方式の競合チェック

#### Step 3: コンポーネント読み込みを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | load-components.ts | `packages/next/src/server/load-components.ts` | コンポーネント読み込みの全体フローを確認する |

**主要処理フロー**:
- **160-179行目**: `loadComponentsImpl`の引数定義
- **182-187行目**: App、Documentの読み込み
- **301-308行目**: getServerSideProps、getStaticPropsの取得

#### Step 4: レンダリング実行の流れを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | render.tsx | `packages/next/src/server/render.tsx` | renderPageTree関数を確認する |

**主要処理フロー**:
- **235-241行目**: `renderPageTree` - AppでComponentをラップしてReact要素ツリーを構築
- **137-141行目**: `renderToString` - ReactDOMServerPages.renderToReadableStreamを使用

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

```
PagesRouteModule.render()
    │
    └─ renderToHTMLImpl()
           ├─ loadGetInitialProps(App, appContext)
           │      └─ App.getInitialProps()
           │
           ├─ getServerSideProps(ctx)  [if defined]
           │
           ├─ renderPageTree(App, Component, props)
           │
           ├─ renderToString(element)
           │      └─ ReactDOMServerPages.renderToReadableStream()
           │
           ├─ Document.getInitialProps()
           │      └─ renderPage()
           │
           └─ postProcessHTML()
```

### データフロー図

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

HTTP Request ────▶ renderToHTMLImpl() ──────────▶ RenderResult
                        │
                  getServerSideProps() ──▶ props
                        │
                  renderPageTree() ──▶ React要素ツリー
                        │
                  renderToReadableStream() ──▶ HTML
                        │
                  __NEXT_DATA__ ──▶ クライアント用JSONデータ
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| render.tsx | `packages/next/src/server/render.tsx` | ソース | SSRレンダリングの中核処理 |
| load-components.ts | `packages/next/src/server/load-components.ts` | ソース | コンポーネント読み込み |
| module.ts | `packages/next/src/server/route-modules/pages/module.ts` | ソース | PagesRouteModuleの実装 |
| render-result.ts | `packages/next/src/server/render-result.ts` | ソース | レンダリング結果の型定義 |
| _app.tsx | `packages/next/src/pages/_app.tsx` | ソース | Appコンポーネント |
| _document.tsx | `packages/next/src/pages/_document.tsx` | ソース | Documentコンポーネント |
| node-web-streams-helper.ts | `packages/next/src/server/stream-utils/node-web-streams-helper.ts` | ソース | ストリーム処理ユーティリティ |
