# 機能設計書 117-静的エクスポート

## 概要

本ドキュメントは、Next.jsの`output: 'export'`設定による完全な静的サイト出力機能の設計を記載する。ビルド済みアプリケーションをHTML/CSS/JSの静的ファイルとして書き出し、任意の静的ファイルホスティングサービスへのデプロイを可能にする。

### 本機能の処理概要

**業務上の目的・背景**：サーバーを必要としない静的サイトホスティング（GitHub Pages、Cloudflare Pages、Netlify等）へのデプロイ需要に対応するため、Next.jsアプリケーションを完全な静的ファイルとして出力する機能が必要である。本機能はビルド成果物からHTML、JSON、CSS、JSファイルを生成し、CDN配信に最適化された静的サイトを出力する。

**機能の利用シーン**：GitHub PagesやCloudflare Pagesへのデプロイ時、CDN配信のみで運用するサイトの構築時、サーバーレス環境で静的コンテンツを配信する場面で利用される。

**主要な処理内容**：
1. ビルド成果物からエクスポート対象ページの特定
2. 各ページのHTMLレンダリングとファイル出力
3. 静的リソース（public/、.next/static/）のコピー
4. プリレンダリング済みページのコピー
5. セグメントデータファイルの出力（App Router）
6. 404.htmlの生成

**関連システム・外部連携**：静的ファイルホスティングサービス（CDN）と連携する。

**権限による制御**：特に権限制御はない。next.config.jsの設定で有効化される。

## 関連画面

本機能はビルド出力であり、直接関連する画面は存在しない。

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | `next build`実行時に静的エクスポートを生成 |

## 機能種別

ビルド出力・静的サイト生成

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| output | 'export' | Yes | next.config.jsのoutput設定 | 'export'文字列 |
| exportPathMap | function | No | カスタムエクスポートパスマップ関数 | - |
| trailingSlash | boolean | No | 末尾スラッシュの有無 | - |
| distDir | string | No | ビルド出力ディレクトリ | 有効なパス |

### 入力データソース

- next.config.js / next.config.ts（設定ファイル）
- ビルド成果物（`.next`ディレクトリ）
- PagesManifest、PrerenderManifest、AppPathRoutesManifest

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| out/ | ディレクトリ | 静的エクスポート出力先 |
| out/*.html | ファイル | レンダリング済みHTMLファイル |
| out/_next/static/ | ディレクトリ | 静的アセット（JS/CSS） |
| out/_next/data/{buildId}/*.json | ファイル | Pages Router用JSONデータ |
| out/**/*.txt | ファイル | App Router用RSCペイロード |
| out/404.html | ファイル | 404エラーページ |

### 出力先

- `out/`ディレクトリ（デフォルト）、またはnext.config.jsの`distDir`設定に基づくディレクトリ

## 処理フロー

### 処理シーケンス

```
1. 環境変数の読み込み
   └─ loadEnvConfigで.envファイルを読み込み
2. Next設定の読み込み
   └─ loadConfigでnext.config.jsを読み込み
3. ビルド成果物の確認
   └─ BUILD_ID_FILEの存在確認、各種マニフェストの読み込み
4. エクスポート対象の決定
   └─ PagesManifest + AppPathRoutesManifest + exportPathMapからページ一覧を構築
5. バリデーション
   └─ SSGフォールバック、i18n、Server Actions、インターセプトルート等の制限チェック
6. 出力ディレクトリの初期化
   └─ outDirの作成、既存ファイルの削除
7. 静的リソースのコピー
   └─ static/、.next/static/、public/のコピー
8. ページのバッチレンダリング
   └─ ワーカープロセスでページをバッチ単位でレンダリング・出力
9. プリレンダリング済みページのコピー
   └─ PrerenderManifestに基づくHTML/JSONファイルのコピー
10. エクスポート結果の記録
    └─ EXPORT_DETAILファイルの書き出し
```

### フローチャート

```mermaid
flowchart TD
    A[exportApp開始] --> B[環境変数・設定読み込み]
    B --> C[ビルド成果物確認]
    C --> D{BUILD_ID存在?}
    D -->|No| E[エラー: ビルドなし]
    D -->|Yes| F[エクスポート対象決定]
    F --> G[バリデーション]
    G --> H{制限違反?}
    H -->|Yes| I[ExportErrorスロー]
    H -->|No| J[出力ディレクトリ初期化]
    J --> K[静的リソースコピー]
    K --> L[ページバッチレンダリング]
    L --> M{RDCキャッシュ対象あり?}
    M -->|Yes| N[RDCキャッシュ構築]
    N --> O[最終フェーズレンダリング]
    M -->|No| P[プリレンダリング済みコピー]
    O --> P
    P --> Q[EXPORT_DETAIL書き出し]
    Q --> R[完了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | ビルド必須 | エクスポート前にnext buildが完了している必要がある | 常時 |
| BR-02 | API Routes除外 | API RoutesはNode.js関数のためエクスポート対象外 | Pages Router API Routes |
| BR-03 | SSGフォールバック禁止 | fallback: trueのページはエクスポートできない | SSGページ |
| BR-04 | Server Actions禁止 | output: 'export'時はServer Actionsが使用できない | App Router |
| BR-05 | インターセプトルート禁止 | インターセプトルートはエクスポートできない | App Router |
| BR-06 | i18n非互換 | i18n設定はexportモードと互換性がない | Pages Router |
| BR-07 | 動的ルート除外 | SSGのdynamicRoutesはデフォルトでエクスポート対象外 | 動的SSGルート |
| BR-08 | PPR非対応 | Partial Prerenderingはexportモードで使用できない | PPR有効時 |
| BR-09 | 404自動生成 | /404パスが未定義の場合、/_errorから404.htmlを自動生成 | Pages Router |
| BR-10 | 404.html互換 | GitHub Pages等の互換のため/404.htmlも出力される | 常時 |

### 計算ロジック

- バッチサイズの決定: `Math.ceil(exportPaths.length / numWorkers)`、最小25ページ/バッチ（`staticGenerationMinPagesPerWorker`設定で変更可能）

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

本機能はデータベースを使用しない。

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| - | - | - | データベース操作なし |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| NEXT_EXPORT_ERROR | ビルド未実行 | BUILD_ID_FILEが存在しない | next buildの事前実行を促すエラー |
| NEXT_EXPORT_ERROR | 予約パス競合 | outDirがpublicまたはstaticディレクトリ | 別の出力先を指定 |
| NEXT_EXPORT_ERROR | SSGフォールバック使用 | fallback: trueのページが存在 | fallback: falseに変更 |
| NEXT_EXPORT_ERROR | Server Actions使用 | output: exportでServer Actionsを使用 | Server Actionsを削除 |
| NEXT_EXPORT_ERROR | インターセプトルート使用 | output: exportでインターセプトルートを使用 | インターセプトルートを削除 |
| NEXT_EXPORT_ERROR | エクスポート失敗 | 個別ページのレンダリングエラー | 失敗ページ一覧を表示 |

### リトライ仕様

リトライ機能は実装されていない。ビルドの再実行が必要。

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

- エクスポート開始時にEXPORT_DETAILにsuccess: falseを書き込み
- 全ページ完了後にsuccess: trueに更新
- 中断時はsuccess: falseのまま

## パフォーマンス要件

- ワーカープロセスによる並行レンダリング（numWorkersで制御）
- バッチ処理による効率的なページ出力
- staticGenerationMinPagesPerWorkerで最小バッチサイズ制御

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

- 環境変数はビルド時に埋め込まれ、出力ファイルに含まれる可能性がある
- NEXT_PUBLIC_プレフィックス付き環境変数はクライアントサイドに公開される
- 静的ファイルとして配信されるため、サーバーサイドの機密データは含まれない

## 備考

- `output: 'export'`はnext.config.jsに設定する方法と、`next export`コマンドを直接実行する方法がある
- Image Optimizationはデフォルトローダーではエクスポートモードで使用できない（`images.unoptimized = true`設定が必要）
- rewrites、redirects、headersはエクスポート時には適用されない

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | types.ts | `packages/next/src/export/types.ts` | ExportAppOptions, ExportPathEntry, ExportPageInput, ExportRouteResult等の型定義 |

**読解のコツ**: ExportAppOptionsがエクスポート全体の設定、ExportPathEntryが個別ページ情報、ExportRouteResultがレンダリング結果を表す。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | index.ts | `packages/next/src/export/index.ts` | exportApp関数（メインエントリーポイント） |

**主要処理フロー**:
- **77-79行目**: ExportErrorクラスの定義
- **191-196行目**: exportAppImpl関数の開始（ディレクトリ解決、環境変数読み込み）
- **236-242行目**: BUILD_ID_FILE存在確認
- **244-254行目**: カスタムルート（rewrites/redirects/headers）の警告
- **289-313行目**: エクスポート対象ページの構築（APIルート・特殊ページの除外）
- **391-472行目**: バリデーション（i18n, Image Optimization, Server Actions, インターセプトルート）
- **678-734行目**: exportPagesInBatches関数（ワーカーによるバッチレンダリング）
- **756-793行目**: 初期フェーズとRDCキャッシュフェーズの2段階レンダリング
- **870-1003行目**: プリレンダリング済みページのコピー処理
- **1076-1087行目**: exportApp関数（トレーススパンのラッパー）

#### Step 3: ワーカーの処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | worker.ts | `packages/next/src/export/worker.ts` | exportPageImpl関数（個別ページのレンダリング処理） |

**主要処理フロー**:
- **15行目**: `NEXT_IS_EXPORT_WORKER`環境変数の設定
- **69-72行目**: exportPageImpl関数（ページのルート種別判定とレンダリング実行）

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

```
exportApp (export/index.ts)
    |
    +-- loadEnvConfig / loadConfig
    |
    +-- マニフェスト読み込み
    |       +-- PagesManifest
    |       +-- PrerenderManifest
    |       +-- AppPathRoutesManifest
    |
    +-- エクスポート対象決定
    |       +-- exportPathMap構築
    |
    +-- バリデーション
    |
    +-- 静的リソースコピー
    |       +-- recursiveCopy (static/, .next/static/, public/)
    |
    +-- exportPagesInBatches
    |       +-- createStaticWorker
    |       +-- worker.exportPages (バッチ単位)
    |               +-- exportPageImpl (worker.ts)
    |                       +-- exportAppRoute / exportAppPage / exportPagesPage
    |
    +-- プリレンダリング済みコピー
    |       +-- HTML/JSON/RSCファイルのコピー
    |       +-- セグメントデータファイルのコピー
    |
    +-- EXPORT_DETAIL書き出し
```

### データフロー図

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

next.config.js -------> exportApp ---------> 設定読み込み
.next/ (ビルド成果物) --> マニフェスト解析 --> エクスポート対象決定
                              |
                              v
                    exportPagesInBatches -----> out/*.html
                         (ワーカー)             out/_next/data/*.json
                              |                 out/**/*.txt (RSC)
                              v
                    プリレンダリング済み -------> out/404.html
                    ページのコピー               out/[prerendered].html
                              |
public/ -------> recursiveCopy -----------> out/[public files]
static/ -------> recursiveCopy -----------> out/static/
.next/static/ -> recursiveCopy -----------> out/_next/static/
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.ts | `packages/next/src/export/index.ts` | ソース | エクスポートメイン処理（exportApp関数） |
| types.ts | `packages/next/src/export/types.ts` | ソース | エクスポート関連の型定義 |
| worker.ts | `packages/next/src/export/worker.ts` | ソース | ページレンダリングワーカー |
| routes/app-page.ts | `packages/next/src/export/routes/app-page.ts` | ソース | App Routerページのエクスポート |
| routes/app-route.ts | `packages/next/src/export/routes/app-route.ts` | ソース | App Router Route Handlerのエクスポート |
| routes/pages.ts | `packages/next/src/export/routes/pages.ts` | ソース | Pages Routerページのエクスポート |
| routes/types.ts | `packages/next/src/export/routes/types.ts` | ソース | ルートエクスポートの型定義 |
| helpers/get-params.ts | `packages/next/src/export/helpers/get-params.ts` | ソース | パスからのパラメータ抽出 |
| helpers/create-incremental-cache.ts | `packages/next/src/export/helpers/create-incremental-cache.ts` | ソース | インクリメンタルキャッシュ作成 |
| utils.ts | `packages/next/src/export/utils.ts` | ソース | エクスポートユーティリティ |
