# 帳票設計書 35-遅延モジュール検出レポート（Slow Module Detection Report）

## 概要

本ドキュメントは、Next.js開発サーバーにおいてビルド時間が閾値を超えたモジュールのインポートチェーンをツリー形式でコンソールに出力するレポートの設計仕様を定義する。

### 本帳票の処理概要

本帳票は、Next.jsの開発モードにおいて、webpackコンパイル中にビルド時間が設定された閾値（`buildTimeThresholdMs`）を超えたモジュールを検出し、そのインポートチェーン（依存グラフ）をツリー形式でコンソールに出力するものである。

**業務上の目的・背景**：開発サーバーでのHMR（Hot Module Replacement）やページ遷移時のコンパイル速度が遅い場合、どのモジュールがボトルネックになっているかを特定するのは困難である。本レポートは、遅延モジュールとそのインポート元をツリー形式で可視化することで、開発者がパフォーマンスボトルネックを迅速に特定し対処できるようにする。

**帳票の利用シーン**：(1) 開発サーバーでのコンパイル速度が遅い場合のボトルネック特定、(2) 大規模プロジェクトでのモジュール最適化、(3) サードパーティライブラリのインポートコスト分析。

**主要な出力内容**：
1. 遅延モジュールのファイルパス（プロジェクトルートからの相対パス、またはnode_modules内のパッケージ名）
2. 各遅延モジュールのビルド所要時間（ミリ秒）
3. インポートチェーンのツリー表示（ルートモジュールから遅延モジュールまでの依存パス）

**帳票の出力タイミング**：開発モード（`next dev`）でwebpackが使用されている場合、各コンパイル完了時（`finishModules`フック）に自動出力される。

**帳票の利用者**：フロントエンドエンジニア、パフォーマンスエンジニア。

## 帳票種別

コンソール出力（標準出力へのツリー形式テキスト表示）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| N/A | 開発サーバー | `next dev` | コンパイル完了時に自動出力 |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | テキスト（コンソール出力、ANSIカラーコード付き） |
| 用紙サイズ | N/A（コンソール出力） |
| 向き | N/A |
| ファイル名 | N/A（ファイル出力なし、標準出力のみ） |
| 出力方法 | console.log経由の標準出力 |
| 文字コード | UTF-8 |

### PDF固有設定

N/A

### Excel固有設定

N/A

## 帳票レイアウト

### レイアウト概要

ツリー形式でインポートチェーンを表示する。

```
🐌 Detected slow modules while compiling server:
 ├─ ./src/app/page.tsx
 │  ├─ ./src/components/HeavyComponent.tsx (1500ms)
 │  │  ├─ some-large-library/dist/index.js (800ms)
 ├─ ./src/app/dashboard/page.tsx
 │  ├─ @acme/analytics/dist/tracker.js (2000ms)
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | 検出メッセージ | 遅延モジュール検出の通知メッセージ | compilerType | 緑色テキスト: `🐌 Detected slow modules while compiling {compilerType}:` |

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | ツリー罫線 | インポートチェーンの深さを表す罫線 | depth引数 | `│  ` + `├─ ` の繰り返し | 可変 |
| 2 | モジュールパス | モジュールのファイルパス | module.resource | 青色テキスト（最大120文字、超過時は中間省略） | 最大120文字 |
| 3 | ビルド時間 | モジュールのビルド所要時間 | moduleBuildTimes WeakMap | 黄色テキスト: `({N}ms)` | 可変 |

### フッター部

N/A

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| 実験的機能の有効化 | `experimental.slowModuleDetection` が設定されていること | Yes |
| 開発モード | `next dev` で実行中であること | Yes |
| webpackバンドラー | webpackを使用していること（Turbopackでは未対応） | Yes |
| ビルド時間閾値 | モジュールのビルド時間が `buildTimeThresholdMs` を超えること | Yes |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | ツリー構造順 | ルートモジュールから深さ優先探索順 |

### 改ページ条件

N/A

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

N/A（webpackのモジュールグラフを参照）

### 参照テーブル一覧

N/A

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

N/A

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| ビルド時間 | performance.now() - startTime | Math.ceil | buildModule〜succeedModuleフック間の時間 |
| 表示パス | resource.replace(process.cwd(), '.') | N/A | カレントディレクトリからの相対パスに変換 |
| node_modulesパス | NODE_MODULES_PATH_PATTERN.match(displayPath)[1] | N/A | node_modules以降のパッケージパスを抽出 |
| パス切り詰め | truncatePath(path, PATH_TRUNCATION_LENGTH - prefix.length) | N/A | 120文字超過時に中間を`...`で省略 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[webpack コンパイル開始] --> B[buildModule フック: 開始時刻記録]
    B --> C[succeedModule フック: ビルド時間計算]
    C --> D{ビルド時間 >= 閾値?}
    D -->|Yes| E[pendingModules に追加]
    D -->|No| F[スキップ]
    E --> G[finishModules フック: レポート生成]
    G --> H[prepareReport: インポートチェーン構築]
    H --> I[issuerModule で親を辿る]
    I --> J[moduleParents/moduleChildren マップ構築]
    J --> K[generateReport: ツリー文字列生成]
    K --> L[rootModules（親なし）からツリー表示]
    L --> M[console.log で出力]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| 内部不整合（開始時刻なし） | succeedModuleフックでstartTimeが見つからない | `Invariant (SlowModuleDetectionPlugin): Unable to find the start time for a module build. This is a Next.js internal bug.` | Next.jsの内部バグ。Issue報告が必要 |
| 内部不整合（循環依存） | モジュールグラフに循環が検出された | `Invariant (SlowModuleDetectionPlugin): Circular dependency detected in module graph. This is a Next.js internal bug.` | Next.jsの内部バグ。Issue報告が必要 |
| 内部不整合（後から記録） | isFinalized後にrecordModuleBuildTimeが呼ばれた | `Invariant (SlowModuleDetectionPlugin): Module is recorded after the report is generated. This is a Next.js internal bug.` | Next.jsの内部バグ。Issue報告が必要 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 遅延モジュール数件〜数十件 |
| 目標出力時間 | 即時（ツリー構築・文字列整形のみ） |
| 同時出力数上限 | コンパイルごとに1回 |

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

コンソール出力のみであり、ファイルには記録されない。モジュールパスが表示されるため、プロジェクト構造やサードパーティライブラリの使用状況が漏洩する可能性がある。開発モード専用機能のため、本番環境では出力されない。有効化時にwebpackの並列処理が無効化される（`NEXT_WEBPACK_PARALLELISM`設定は無視される）点に注意。

## 備考

- 実験的機能であり、`next.config.js`の`experimental.slowModuleDetection`で有効化する
- `buildTimeThresholdMs`プロパティでビルド時間の閾値をミリ秒単位で指定
- Turbopack使用時はこの機能は利用できない（`experimental.slowModuleDetection`はTurbopack非対応機能として警告される）
- 有効化時はwebpackの並列処理が無効化される（正確なビルド時間計測のため）
- パス表示は最大120文字（`PATH_TRUNCATION_LENGTH`定数）で、超過時は中間が`...`で省略される
- node_modules内のモジュールはパッケージ名以降のみ表示（pnpmスタイルのパスにも対応）

---

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

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

### 推奨読解順序

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

プラグインで使用される内部データ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | slow-module-detection-plugin.ts | `packages/next/src/build/webpack/plugins/slow-module-detection-plugin.ts` | ModuleBuildTimeAnalyzerOptions型（行17-20）とModuleBuildTimeAnalyzerクラス（行68-215）の構造 |

**読解のコツ**: 主要なデータ構造は `modules`（Map）、`moduleParents`（Map）、`moduleChildren`（Map）、`moduleBuildTimes`（WeakMap）の4つ。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | slow-module-detection-plugin.ts | `packages/next/src/build/webpack/plugins/slow-module-detection-plugin.ts` | SlowModuleDetectionPluginクラス（行217-244）のapplyメソッド |

**主要処理フロー**:
1. **行221**: compilation.tapでコンパイルフックに登録
2. **行225**: buildModuleフックで開始時刻を記録
3. **行229-236**: succeedModuleフックでビルド時間を計算・記録
4. **行239-241**: finishModulesフックでレポート生成

#### Step 3: レポート生成処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | slow-module-detection-plugin.ts | `packages/next/src/build/webpack/plugins/slow-module-detection-plugin.ts` | prepareReport（行107-154）とgenerateReport（行156-214）メソッド |

**主要処理フロー**:
- **行108-126**: 各遅延モジュールからissuerModuleを辿ってルートまでチェーンを構築
- **行129-153**: チェーン内のモジュールをmodules/moduleParents/moduleChildrenマップに登録
- **行162-164**: ルートモジュール（親なし）を特定
- **行166-201**: formatModuleNode再帰関数でツリー文字列を生成
- **行203-213**: ルートモジュールからツリーを構築してconsole.logで出力

#### Step 4: 設定と有効化条件を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | webpack-config.ts | `packages/next/src/build/webpack-config.ts` | 行921で `slowModuleDetection && dev` の条件判定、行2197でプラグイン登録 |
| 4-2 | config-shared.ts | `packages/next/src/server/config-shared.ts` | 行805-810で `slowModuleDetection` 設定の型定義 |

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

```
next dev (webpack コンパイル)
    │
    └─ SlowModuleDetectionPlugin.apply() (行220)
           │
           ├─ compilation.hooks.buildModule.tap()     → startTime 記録
           ├─ compilation.hooks.succeedModule.tap()   → ビルド時間計算・記録
           └─ compilation.hooks.finishModules.tap()
                  └─ ModuleBuildTimeAnalyzer.generateReport()
                         ├─ prepareReport() → インポートチェーン構築
                         │      └─ moduleGraph.getIssuer() → 親モジュール辿り
                         ├─ formatModuleNode() → ツリー文字列生成（再帰）
                         │      ├─ getModuleDisplayName() → パス表示名取得
                         │      └─ truncatePath() → パス切り詰め
                         └─ console.log() → 出力
```

### データフロー図

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

webpack modules ──────────────▶ buildModule hook
                                    └─ startTime 記録
                                         │
                                succeedModule hook
                                    └─ duration 計算
                                         │
                               {duration >= threshold?}
                                    │ Yes
                                    ▼
                               pendingModules 追加
                                    │
                               finishModules hook
                                    ├─ prepareReport()     ──▶ modules/parents/children Map
                                    └─ generateReport()    ──▶ コンソール出力 (stdout)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| slow-module-detection-plugin.ts | `packages/next/src/build/webpack/plugins/slow-module-detection-plugin.ts` | ソース | プラグイン本体・レポート生成ロジック |
| webpack-config.ts | `packages/next/src/build/webpack-config.ts` | ソース | プラグインの登録・有効化条件 |
| config-shared.ts | `packages/next/src/server/config-shared.ts` | ソース | `slowModuleDetection`設定の型定義 |
| config-schema.ts | `packages/next/src/server/config-schema.ts` | ソース | 設定スキーマバリデーション |
| turbopack-warning.ts | `packages/next/src/lib/turbopack-warning.ts` | ソース | Turbopack使用時の非対応警告 |
| picocolors.ts | `packages/next/src/lib/picocolors.ts` | ソース | ANSIカラーコード関数（yellow, green, blue） |
