# 帳票設計書 20-BUILD_ID

## 概要

本ドキュメントは、Next.jsビルドプロセスにおいて生成される `BUILD_ID` ファイルの設計仕様を定義する。BUILD_IDはビルドの一意な識別子を格納するプレーンテキストファイルであり、デプロイ時のキャッシュバスティング、アセットバージョニング、ビルド間の一意性保証に使用される。

### 本帳票の処理概要

BUILD_IDは、`generateBuildId` 関数により生成される一意な文字列を `writeBuildId` 関数によりファイルに書き込むことで作成される。デフォルトでは nanoid ライブラリによりランダムな文字列が生成されるが、`next.config.js` の `generateBuildId` オプションにより開発者がカスタムのビルドIDを指定することも可能である。

**業務上の目的・背景**：Webアプリケーションのデプロイにおいて、ビルドごとに一意な識別子を持つことは重要である。静的アセットのキャッシュバスティング（`/_next/static/[buildId]/`）、クライアントとサーバー間のバージョン整合性チェック、CDNキャッシュの無効化などに BUILD_ID が使用される。一意なIDにより、デプロイ間でアセットの混同が発生しないことを保証する。

**帳票の利用シーン**：`next build` コマンド実行時にビルドプロセスの初期段階で生成される。生成後はビルドプロセス全体を通じて参照され、アセットパスの構成、マニフェストの生成、ルーターの初期化などで広く使用される。`next start` でのサーバー起動時にも読み込まれる。

**主要な出力内容**：
1. ビルドの一意な識別子（nanoidによるランダム文字列、またはカスタム値）

**帳票の出力タイミング**：`next build` コマンド実行時、ビルドプロセスの初期段階で `getBuildId` 関数により生成され、ビルド後半で `writeBuildId` により書き込まれる。

**帳票の利用者**：Next.jsフレームワーク内部の多数のコンポーネント（サーバー、ルーター、ビルドプロセス、クライアントサイドアセットローダー等）。開発者がデプロイメント管理やデバッグ目的で参照する場合もある。

## 帳票種別

ビルドメタ情報（プレーンテキスト形式）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| N/A | CLIコマンド | `next build` | ビルド実行 |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | プレーンテキスト（拡張子なし） |
| 用紙サイズ | N/A（データファイル） |
| 向き | N/A |
| ファイル名 | `BUILD_ID` |
| 出力方法 | ファイルシステムへの書き込み |
| 文字コード | UTF-8 |

### ファイル内容

```
a1b2c3d4e5f6g7h8i9j0k
```

ビルドIDの文字列のみが格納される。改行なし。

## 帳票レイアウト

### レイアウト概要

単一行のプレーンテキスト。

```
┌─────────────────────────────────────┐
│  [nanoidで生成されたランダム文字列]   │
│  例: a1b2c3d4e5f6g7h8i9j0k         │
└─────────────────────────────────────┘
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | buildId | ビルドの一意な識別子 | nanoid() またはカスタム generateBuildId | 文字列 |

### 明細部

N/A（単一値）

### フッター部

N/A

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| ビルド実行 | `next build` が実行されること | Yes |
| generateBuildIdオプション | カスタムビルドID生成関数（未設定時はnanoid使用） | No |
| adフィルタ | ビルドIDに'ad'（大文字小文字不問）が含まれないこと | Yes（広告ブロッカー対策） |

### ソート順

N/A（単一値）

### 改ページ条件

N/A

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

N/A

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| デフォルトビルドID | `nanoid()` | N/A | nanoidライブラリでランダム文字列生成 |
| カスタムビルドID | `config.generateBuildId()` の戻り値 | N/A | ユーザー定義の生成関数 |
| adフィルタ | `while (!buildId \|\| /ad/i.test(buildId)) { buildId = fallback() }` | N/A | 'ad'を含む場合は再生成 |
| トリム処理 | `buildId.trim()` | N/A | 前後の空白を除去 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[next build実行] --> B[getBuildId呼び出し]
    B --> C{generateモード?}
    C -->|Yes| D[既存BUILD_IDファイルから読み込み]
    C -->|No| E[generateBuildId呼び出し]
    E --> F{config.generateBuildId設定あり?}
    F -->|Yes| G[カスタム関数実行]
    F -->|No| H[nanoidで生成]
    G --> I{戻り値がnull?}
    I -->|Yes| H
    I -->|No| J[値の型チェック]
    H --> K{buildIdに'ad'を含む?}
    K -->|Yes| H
    K -->|No| L[trim処理]
    J --> L
    L --> M[ビルドプロセスでbuildIdを使用]
    M --> N[writeBuildId呼び出し]
    N --> O[.next/BUILD_IDに書き込み]
    O --> P[終了]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| 型エラー | generateBuildIdの戻り値が文字列でない | `generateBuildId did not return a string. https://nextjs.org/docs/messages/generatebuildid-not-a-string` | generateBuildId関数が文字列を返すよう修正 |
| ファイル読み込みエラー | generateモードでBUILD_IDファイルが存在しない | ファイルシステムエラー | ビルドを先に実行（compileモード） |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 1ファイル（単一値） |
| 目標出力時間 | 即座（nanoid生成は高速） |
| 同時出力数上限 | 1 |

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

BUILD_IDはアセットURLの一部として公開されるため、機密情報は含めるべきではない。nanoidによるデフォルト生成ではランダムな文字列が使用されるため予測不可能である。カスタムgenerateBuildIdを使用する場合、Git SHAなどの情報が含まれる可能性があるが、これ自体はセキュリティリスクとはならない。'ad'フィルタは広告ブロッカーによる誤検出を防止するためのもの。

## 備考

- 定数名 `BUILD_ID_FILE` は `constants.ts` の117行目で定義（値: `'BUILD_ID'`）。
- `generateBuildId` 関数は `build/generate-build-id.ts` で定義される。
- `writeBuildId` 関数は `build/write-build-id.ts` で定義。`fs.promises.writeFile` でUTF-8書き込み。
- nanoidはNext.jsにバンドルされている（`next/dist/compiled/nanoid/index.cjs`）。
- generateモード（`experimentalBuildMode === 'generate'`）では、既存のBUILD_IDファイルから読み込む（compileモードで先に生成済みの前提）。
- buildIdはビルドプロセス全体で広く参照される（静的アセットパス、マニフェスト、ルーター設定等）。
- 'ad' を含むIDが再生成される理由は、広告ブロッカーが '/ad/' を含むURLをブロックする場合があるため（コード内コメントに記載）。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | constants.ts | `packages/next/src/shared/lib/constants.ts` | 117行目: `BUILD_ID_FILE` 定数（値: `'BUILD_ID'`） |

**読解のコツ**: BUILD_IDは単なるプレーンテキストファイルであり、構造化されたデータではない。ファイルの内容は文字列1行のみ。

#### Step 2: ビルドID生成処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | generate-build-id.ts | `packages/next/src/build/generate-build-id.ts` | 1-22行目: `generateBuildId` 関数。カスタム生成関数の呼び出し、nanoidフォールバック、'ad'フィルタ、型チェック、trim処理 |
| 2-2 | index.ts | `packages/next/src/build/index.ts` | 897-909行目: `getBuildId` 関数。generateモード判定とgenerateBuildId呼び出し |

**主要処理フロー**:
1. **1行目**: `generateBuildId(generate, fallback)` - generate関数とfallback関数を受け取る
2. **5行目**: `await generate()` でカスタム生成関数を実行
3. **7行目**: 戻り値がnullの場合はフォールバック（nanoid）
4. **10行目**: `while (!buildId || /ad/i.test(buildId))` - 'ad'を含む場合は再生成
5. **15-18行目**: 文字列型チェック。非文字列の場合はエラーthrow
6. **21行目**: `buildId.trim()` で前後空白除去して返却

#### Step 3: ビルドID書き込み処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | write-build-id.ts | `packages/next/src/build/write-build-id.ts` | 1-11行目: `writeBuildId` 関数。`fs.promises.writeFile` でdistDir/BUILD_IDに書き込み |

**主要処理フロー**:
- **9行目**: `const buildIdPath = join(distDir, BUILD_ID_FILE)` でパス構築
- **10行目**: `await promises.writeFile(buildIdPath, buildId, 'utf8')` で書き込み

#### Step 4: ビルドID利用箇所を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | index.ts | `packages/next/src/build/index.ts` | 2822行目: `writeBuildId(distDir, buildId)` の呼び出し |
| 4-2 | next-server.ts | `packages/next/src/server/next-server.ts` | サーバー起動時にBUILD_IDを読み込み |
| 4-3 | filesystem.ts | `packages/next/src/server/lib/router-utils/filesystem.ts` | ルーターファイルシステムでBUILD_ID参照 |

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

```
next build (packages/next/src/build/index.ts)
    |
    +-- getBuildId()
    |       |
    |       +-- [generateモード] fs.readFile(distDir/BUILD_ID)
    |       |
    |       +-- [通常] generateBuildId(config.generateBuildId, nanoid)
    |               |
    |               +-- config.generateBuildId() [カスタム関数]
    |               |       +-- null の場合 -> nanoid()
    |               |
    |               +-- nanoid() [デフォルト]
    |               +-- /ad/i フィルタ
    |               +-- trim()
    |
    +-- ... (buildIdをビルドプロセス全体で使用)
    |
    +-- writeBuildId(distDir, buildId)
            |
            +-- fs.promises.writeFile(distDir/BUILD_ID, buildId, 'utf8')
```

### データフロー図

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

config.generateBuildId   generateBuildId()              .next/BUILD_ID
  (カスタム関数)      -->  (ID生成・バリデーション)  -->
  or nanoid()              /ad/i フィルタ
                           trim()

                           writeBuildId()
  buildId文字列        -->  fs.writeFile()            --> .next/BUILD_ID

                           next start / next dev
  BUILD_IDファイル     -->  fs.readFile()             --> サーバー内部でbuildId使用
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| generate-build-id.ts | `packages/next/src/build/generate-build-id.ts` | ソース | ビルドID生成ロジック |
| write-build-id.ts | `packages/next/src/build/write-build-id.ts` | ソース | ビルドIDファイル書き込み |
| constants.ts | `packages/next/src/shared/lib/constants.ts` | ソース | BUILD_ID_FILE定数定義 |
| index.ts | `packages/next/src/build/index.ts` | ソース | getBuildId関数、writeBuildId呼び出し |
| next-server.ts | `packages/next/src/server/next-server.ts` | ソース | サーバー起動時のBUILD_ID読み込み |
| filesystem.ts | `packages/next/src/server/lib/router-utils/filesystem.ts` | ソース | ルーターでのBUILD_ID参照 |
| route-module.ts | `packages/next/src/server/route-modules/route-module.ts` | ソース | ルートモジュールでのBUILD_ID参照 |
| index.ts | `packages/next/src/export/index.ts` | ソース | エクスポート処理でのBUILD_ID使用 |
