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

## はじめに

このガイドラインは、webpackのコードベースを効率的に理解するための手引きです。
JavaScriptに精通していないエンジニアでも、段階的に学習できるよう構成されています。

webpack（バージョン 5.105.3）は、ECMAScript/CommonJS/AMDモジュールをブラウザ向けにバンドルするためのモジュールバンドラーです。プラグインベースのアーキテクチャにより、高い拡張性を実現しています。

**対象読者:**
- プロジェクトに新規参画するエンジニア
- 他言語からの経験者
- コードレビューを行う担当者

---

## 1. 言語基礎

> このセクションでは、JavaScriptの基本構文と概念を解説します。

### 1.1 プログラム構造

webpackは **Node.js** 上で動作するJavaScriptプロジェクトです。モジュールシステムには **CommonJS** を採用しています。

各ファイルの冒頭には `"use strict";` 宣言が付き、厳密モードで動作します。また、MITライセンスのコメントが必ず記載されています。

```javascript
// ファイル: lib/EntryPlugin.js:1-7
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";
```

### 1.2 データ型と変数

webpackでは `const` を優先的に使用し、再代入が必要な場合のみ `let` を使います。`var` は使用されません。

型安全性は **JSDoc** による型注釈で担保されています。TypeScriptは使用せず、JSDocコメントによる型定義をTypeScriptコンパイラで検証する方式を採用しています。

```javascript
// ファイル: lib/Compiler.js:242-249
/** @type {string | undefined} */
this.name = undefined;
/** @type {Compilation | undefined} */
this.parentCompilation = undefined;
/** @type {Compiler} */
this.root = this;
/** @type {string} */
this.outputPath = "";
```

JSDocの `@typedef` で複合型を定義する例：

```javascript
// ファイル: lib/Compiler.js:65-69
/**
 * @typedef {object} CompilationParams
 * @property {NormalModuleFactory} normalModuleFactory
 * @property {ContextModuleFactory} contextModuleFactory
 */
```

### 1.3 制御構造

webpackでは標準的なJavaScriptの制御構造（`if/else`, `for...of`, `switch` 等）が使われます。特に `for...of` ループが頻出し、イテラブルオブジェクト（Set, Map, Array）の反復処理に多用されます。

```javascript
// ファイル: lib/BannerPlugin.js:101-109
for (const chunk of compilation.chunks) {
	if (options.entryOnly && !chunk.canBeInitial()) {
		continue;
	}

	for (const file of chunk.files) {
		if (!matchObject(file)) {
			continue;
		}
		// ...
	}
}
```

### 1.4 関数/メソッド定義

関数定義には主に以下の3パターンが使われます：

**1. アロー関数（ユーティリティ・ヘルパー）:**

```javascript
// ファイル: lib/Compiler.js:124-128
const isSorted = (array) => {
	for (let i = 1; i < array.length; i++) {
		if (array[i - 1] > array[i]) return false;
	}
	return true;
};
```

**2. クラスメソッド（主要なロジック）:**

```javascript
// ファイル: lib/EntryPlugin.js:33-51
apply(compiler) {
	compiler.hooks.compilation.tap(
		PLUGIN_NAME,
		(compilation, { normalModuleFactory }) => {
			compilation.dependencyFactories.set(
				EntryDependency,
				normalModuleFactory
			);
		}
	);
}
```

**3. 静的メソッド（ファクトリ関数）:**

```javascript
// ファイル: lib/EntryPlugin.js:59-69
static createDependency(entry, options) {
	const dep = new EntryDependency(entry);
	dep.loc = {
		name:
			typeof options === "object"
				? /** @type {string} */ (options.name)
				: options
	};
	return dep;
}
```

### 1.5 モジュール/インポート

CommonJSの `require()` と `module.exports` を使用します。

```javascript
// ファイル: lib/Compiler.js:8-16
const parseJson = require("json-parse-even-better-errors");
const asyncLib = require("neo-async");
const {
	AsyncParallelHook,
	AsyncSeriesHook,
	SyncBailHook,
	SyncHook
} = require("tapable");
const { SizeOnlySource } = require("webpack-sources");
```

遅延ロード（Lazy Loading）パターンも頻繁に使用されます。パフォーマンス向上のため、モジュールの読み込みをアクセス時まで遅延させます：

```javascript
// ファイル: lib/util/memoize.js:17-34
const memoize = (fn) => {
	let cache = false;
	/** @type {T | undefined} */
	let result;
	return () => {
		if (cache) {
			return /** @type {T} */ (result);
		}
		result = fn();
		cache = true;
		// Allow to clean up memory for fn
		// and all dependent resources
		/** @type {FunctionReturning<T> | undefined} */
		(fn) = undefined;
		return /** @type {T} */ (result);
	};
};
```

`lib/index.js` では `memoize` を活用して全エクスポートを遅延ロードしています：

```javascript
// ファイル: lib/webpack.js:37
const getValidateSchema = memoize(() => require("./validateSchema"));
```

---

## 2. プロジェクト固有の概念

> このセクションでは、当プロジェクト特有の概念を解説します。

### 2.1 フレームワーク固有の概念

#### Tapable（フックシステム）

webpackの中核をなすライブラリが **tapable** です。イベント駆動のプラグインアーキテクチャを実現するためのフックシステムを提供します。

| フックの種類 | 説明 | 用途 |
|-------------|------|------|
| `SyncHook` | 同期フック。登録順に呼び出される | 通知のみ（戻り値なし） |
| `SyncBailHook` | 同期フック。ハンドラがnon-undefinedを返すと停止 | 条件分岐・フィルタリング |
| `SyncWaterfallHook` | 前のハンドラの戻り値が次の引数になる | 値の変換チェーン |
| `AsyncSeriesHook` | 非同期直列フック | 順序のある非同期処理 |
| `AsyncParallelHook` | 非同期並列フック | 並列実行可能な処理 |
| `AsyncSeriesBailHook` | 非同期直列ベイルフック | 条件付き非同期処理 |
| `HookMap` | 名前付きフックの動的マップ | パーサーフック等 |

```javascript
// ファイル: lib/Compiler.js:163-238
constructor(context, options = /** @type {WebpackOptions} */ ({})) {
	this.hooks = Object.freeze({
		/** @type {SyncHook<[]>} */
		initialize: new SyncHook([]),
		/** @type {AsyncSeriesHook<[Stats]>} */
		done: new AsyncSeriesHook(["stats"]),
		/** @type {AsyncSeriesHook<[Compiler]>} */
		beforeRun: new AsyncSeriesHook(["compiler"]),
		/** @type {AsyncParallelHook<[Compilation]>} */
		make: new AsyncParallelHook(["compilation"]),
		// ...
	});
}
```

フックへのプラグイン登録は `tap`（同期）、`tapAsync`（コールバック非同期）、`tapPromise`（Promise非同期）メソッドで行います：

```javascript
// ファイル: lib/EntryPlugin.js:34-42
// 同期フックへの登録
compiler.hooks.compilation.tap(
	PLUGIN_NAME,
	(compilation, { normalModuleFactory }) => {
		compilation.dependencyFactories.set(
			EntryDependency,
			normalModuleFactory
		);
	}
);

// ファイル: lib/EntryPlugin.js:47-51
// 非同期フックへの登録
compiler.hooks.make.tapAsync(PLUGIN_NAME, (compilation, callback) => {
	compilation.addEntry(context, dep, options, (err) => {
		callback(err);
	});
});
```

#### webpack-sources

ソースコード生成のためのライブラリで、効率的な文字列連結とソースマップ管理を提供します。

```javascript
// ファイル: lib/BannerPlugin.js:120-126
compilation.updateAsset(file, (old) => {
	const cached = cache.get(old);
	if (!cached || cached.comment !== comment) {
		const source = options.footer
			? new ConcatSource(old, "\n", comment)
			: new ConcatSource(comment, "\n", old);
		// ...
	}
});
```

### 2.2 プロジェクト独自のパターン

#### プラグインパターン

webpackのすべてのプラグインは共通のインターフェースに従います：

1. `constructor` でオプションを受け取り、バリデーションを実行
2. `apply(compiler)` メソッドでフックに登録
3. `PLUGIN_NAME` 定数でフック登録名を統一

```javascript
// ファイル: lib/BannerPlugin.js:49-135（パターンの全体像）
const PLUGIN_NAME = "BannerPlugin";

class BannerPlugin {
	constructor(options) {
		validate(options);         // スキーマバリデーション
		this.options = options;
	}

	apply(compiler) {
		compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
			compilation.hooks.processAssets.tap(
				{ name: PLUGIN_NAME, stage },
				() => { /* アセット処理ロジック */ }
			);
		});
	}
}
```

#### スキーマバリデーションパターン

設定オプションは JSON Schema で定義し、ランタイムでバリデーションを実行します：

```javascript
// ファイル: lib/BannerPlugin.js:23-31
const validate = createSchemaValidation(
	require("../schemas/plugins/BannerPlugin.check"),
	() => require("../schemas/plugins/BannerPlugin.json"),
	{
		name: "Banner Plugin",
		baseDataPath: "options"
	}
);
```

#### シリアライズパターン

永続キャッシュのため、多くのクラスがシリアライズ可能です。`makeSerializable` ユーティリティで登録されます：

```javascript
// 典型的なパターン（多くの Dependency/Module クラスで使用）
const makeSerializable = require("./util/makeSerializable");

class SomeClass {
	serialize(context) {
		const { write } = context;
		write(this.property1);
		write(this.property2);
		super.serialize(context);
	}

	deserialize(context) {
		const { read } = context;
		this.property1 = read();
		this.property2 = read();
		super.deserialize(context);
	}
}

makeSerializable(SomeClass, "webpack/lib/SomeClass");
```

---

## 3. 命名規則

> このセクションでは、プロジェクト全体で使用される命名規則を解説します。

### 3.1 ファイル・ディレクトリ命名

| パターン | 意味 | 例 |
|---------|------|-----|
| `{Name}Plugin.js` | webpackプラグイン | `BannerPlugin.js`, `DefinePlugin.js` |
| `{Name}Module.js` | モジュール種別の実装 | `NormalModule.js`, `ExternalModule.js`, `CssModule.js` |
| `{Name}Dependency.js` | 依存関係の種別 | `EntryDependency.js`, `ConstDependency.js` |
| `{Name}RuntimeModule.js` | ランタイムコード生成 | `AsyncModuleRuntimeModule.js` |
| `{Name}Factory.js` | ファクトリクラス | `NormalModuleFactory.js`, `ContextModuleFactory.js` |
| `{Name}Template.js` | コード生成テンプレート | `MainTemplate.js`, `ModuleTemplate.js` |
| `{camelCase}.js` | ユーティリティ関数 | `memoize.js`, `createHash.js`, `cleverMerge.js` |

### 3.2 クラス・関数・変数命名

| プレフィックス/サフィックス | 意味 | 例 |
|---------------------------|------|-----|
| `Plugin` サフィックス | プラグインクラス | `EntryPlugin`, `BannerPlugin` |
| `Module` サフィックス | モジュールを表すクラス | `NormalModule`, `ContextModule` |
| `Dependency` サフィックス | 依存関係を表すクラス | `EntryDependency`, `ConstDependency` |
| `RuntimeModule` サフィックス | ランタイムモジュール | `AsyncModuleRuntimeModule` |
| `PLUGIN_NAME` 定数 | フック登録時のプラグイン識別名 | `const PLUGIN_NAME = "BannerPlugin"` |
| `get` プレフィックス | ゲッター関数（遅延ロード） | `getValidateSchema`, `getContext` |
| `create` プレフィックス | ファクトリ関数 | `createCompiler`, `createHash` |
| `apply` | プラグインのエントリーポイント | `plugin.apply(compiler)` |
| `is` / `has` / `can` プレフィックス | 真偽値を返す判定メソッド | `canBeInitial()`, `isInstalled()` |
| `_` プレフィックス | プライベート/内部プロパティ | `this._hashUpdate`, `this._deferInterop` |
| `UPPER_SNAKE_CASE` | 定数 | `PLUGIN_NAME`, `STAGE_ADVANCED` |

### 3.3 プログラム分類一覧

| 分類 | ディレクトリ | 説明 |
|------|-------------|------|
| コアクラス | `lib/` 直下 | Compiler, Compilation, Module, Chunk 等 |
| プラグイン | `lib/` 直下 (`*Plugin.js`) | 機能拡張プラグイン |
| 依存関係 | `lib/dependencies/` | モジュール間依存の定義（124ファイル） |
| ランタイム | `lib/runtime/` | ブラウザ実行時コード生成（33ファイル） |
| 最適化 | `lib/optimize/` | バンドル最適化処理（19ファイル） |
| ユーティリティ | `lib/util/` | 汎用ユーティリティ（60+ファイル） |
| シリアライズ | `lib/serialization/` | 永続キャッシュ用シリアライズ（15ファイル） |
| 設定 | `lib/config/` | 設定の正規化・デフォルト値適用 |
| Node.js固有 | `lib/node/` | Node.js環境向け実装 |
| Web固有 | `lib/web/` | ブラウザ環境向け実装 |
| コンテナ | `lib/container/` | Module Federation機能 |
| CSS | `lib/css/` | CSS処理機能 |
| JavaScript | `lib/javascript/` | JavaScriptパーサー・ジェネレーター |
| WASM | `lib/wasm-sync/`, `lib/wasm-async/` | WebAssembly処理 |

---

## 4. ディレクトリ構造

> このセクションでは、プロジェクトのディレクトリ構造を解説します。

```
webpack-main/
├── bin/                    # CLI エントリーポイント
│   └── webpack.js          # webpack コマンド
├── lib/                    # コアライブラリ（メインソースコード）
│   ├── index.js            # パッケージエントリーポイント
│   ├── webpack.js          # webpack() 関数
│   ├── Compiler.js         # コンパイラ（ビルド全体管理）
│   ├── Compilation.js      # コンパイレーション（1回のビルド）
│   ├── Module.js           # モジュール基底クラス
│   ├── NormalModule.js     # 通常モジュール
│   ├── Chunk.js            # チャンク（出力単位）
│   ├── ChunkGraph.js       # チャンクグラフ
│   ├── ModuleGraph.js      # モジュールグラフ
│   ├── Dependency.js       # 依存関係基底クラス
│   ├── *Plugin.js          # 各種プラグイン
│   ├── asset/              # アセットモジュール処理
│   ├── async-modules/      # 非同期モジュール処理
│   ├── cache/              # キャッシュ戦略
│   ├── config/             # 設定の正規化・デフォルト
│   ├── container/          # Module Federation
│   ├── css/                # CSS処理
│   ├── debug/              # デバッグ機能
│   ├── dependencies/       # 依存関係クラス群（124ファイル）
│   ├── electron/           # Electron対応
│   ├── errors/             # エラークラス
│   ├── esm/                # ESM対応
│   ├── hmr/                # Hot Module Replacement
│   ├── ids/                # モジュール/チャンクID生成
│   ├── javascript/         # JavaScriptパーサー
│   ├── json/               # JSONモジュール処理
│   ├── library/            # ライブラリ出力形式
│   ├── logging/            # ロギング
│   ├── node/               # Node.js固有処理
│   ├── optimize/           # 最適化プラグイン群（19ファイル）
│   ├── performance/        # パフォーマンス警告
│   ├── prefetch/           # プリフェッチ
│   ├── rules/              # ローダールール処理
│   ├── runtime/            # ランタイムモジュール群（33ファイル）
│   ├── schemes/            # URLスキーム処理
│   ├── serialization/      # シリアライズ基盤（15ファイル）
│   ├── sharing/            # モジュール共有
│   ├── stats/              # 統計情報出力
│   ├── url/                # URL処理
│   ├── util/               # ユーティリティ群（60+ファイル）
│   ├── wasm/               # WASM共通
│   ├── wasm-async/         # 非同期WASM
│   ├── wasm-sync/          # 同期WASM
│   ├── web/                # Web環境向け
│   └── webworker/          # WebWorker対応
├── hot/                    # HMR クライアントランタイム
├── schemas/                # JSON Schemaによる設定バリデーション
│   ├── WebpackOptions.json # メイン設定スキーマ
│   └── plugins/            # プラグインごとのスキーマ
├── declarations/           # TypeScript型宣言
├── test/                   # テストスイート
│   ├── cases/              # 機能テストケース
│   ├── configCases/        # 設定テストケース
│   ├── hotCases/           # HMRテストケース
│   ├── statsCases/         # 統計出力テストケース
│   ├── watchCases/         # ウォッチモードテストケース
│   └── *.test.js           # テストランナー
├── examples/               # サンプルプロジェクト（81件）
├── tooling/                # 開発用ツール
└── assembly/               # WebAssemblyソース
```

### 各ディレクトリの役割

| ディレクトリ | 役割 | 主要ファイル |
|-------------|------|-------------|
| `bin/` | CLIエントリーポイント | `webpack.js` |
| `lib/` | コアライブラリ（191ファイル） | `Compiler.js`, `Compilation.js`, `webpack.js` |
| `lib/dependencies/` | モジュール間の依存関係定義 | `ConstDependency.js`, `EntryDependency.js` |
| `lib/runtime/` | バンドル出力に埋め込むランタイムコード | `AsyncModuleRuntimeModule.js` |
| `lib/optimize/` | チャンク分割・ツリーシェイキング等の最適化 | `SplitChunksPlugin.js`, `ModuleConcatenationPlugin.js` |
| `lib/util/` | データ構造・ハッシュ・比較関数等の汎用ユーティリティ | `memoize.js`, `createHash.js`, `SortableSet.js` |
| `lib/serialization/` | 永続キャッシュのためのシリアライズ基盤 | `Serializer.js`, `BinaryMiddleware.js` |
| `lib/config/` | webpack設定の正規化とデフォルト値適用 | `defaults.js`, `normalization.js`, `target.js` |
| `schemas/` | JSON Schemaによる設定バリデーション定義 | `WebpackOptions.json` |
| `hot/` | HMR時にブラウザ/Node.jsで動作するクライアントコード | `dev-server.js`, `lazy-compilation-node.js` |
| `test/` | Jest によるテストスイート | `TestCases.basictest.js`, `jest.config.js` |
| `examples/` | 各機能のサンプル設定 | `code-splitting/`, `module-federation/` |

---

## 5. アーキテクチャ

> このセクションでは、プロジェクトのアーキテクチャパターンを解説します。

### 5.1 全体アーキテクチャ

webpackは **イベント駆動プラグインアーキテクチャ** を採用しています。コア機能は最小限に抑え、ほぼすべての機能がプラグインとして実装されています。中核のフロー制御は `Compiler` と `Compilation` が担い、各処理フェーズでフックを発火させることで、プラグインに処理を委譲します。

```mermaid
graph TD
    A[webpack.js: webpack関数] --> B[Compiler]
    B --> C[Compilation]
    C --> D[NormalModuleFactory]
    C --> E[ContextModuleFactory]
    D --> F[NormalModule]
    D --> G[Parser / JavascriptParser]
    G --> H[Dependency群]
    C --> I[ChunkGraph]
    C --> J[ModuleGraph]
    I --> K[Chunk]
    C --> L[最適化プラグイン群]
    L --> M[コード生成]
    M --> N[アセット出力]

    subgraph プラグインシステム
        O[Plugin.apply] -->|tap| P[Compiler.hooks]
        O -->|tap| Q[Compilation.hooks]
        O -->|tap| R[NormalModuleFactory.hooks]
    end

    P -.-> B
    Q -.-> C
    R -.-> D
```

### 5.2 レイヤー構成

| レイヤー | 責務 | 代表的なファイル |
|---------|------|-----------------|
| CLI層 | コマンドライン解析、webpack-cliへの委譲 | `bin/webpack.js` |
| API層 | webpack関数のエントリーポイント、設定の正規化 | `lib/webpack.js`, `lib/index.js` |
| コンパイラ層 | ビルドプロセス全体のライフサイクル管理 | `lib/Compiler.js`, `lib/Watching.js` |
| コンパイレーション層 | 1回のビルドにおけるモジュール解決・グラフ構築 | `lib/Compilation.js` |
| モジュール層 | 個々のモジュールの読み込み・パース・コード生成 | `lib/NormalModule.js`, `lib/Module.js` |
| 依存関係層 | モジュール間の依存関係の表現と解決 | `lib/dependencies/*.js`, `lib/Dependency.js` |
| 最適化層 | チャンク分割・ツリーシェイキング・マングリング | `lib/optimize/*.js` |
| ランタイム層 | バンドル出力に埋め込むブートストラップコード | `lib/runtime/*.js`, `lib/RuntimeGlobals.js` |
| シリアライズ層 | 永続キャッシュのためのオブジェクト直列化 | `lib/serialization/*.js` |
| ユーティリティ層 | データ構造・ハッシュ・比較関数等の共通機能 | `lib/util/*.js` |

### 5.3 データフロー

webpackのビルドは以下のフェーズで進行します：

```
1. 初期化（Configuration）
   webpack() → getNormalizedWebpackOptions() → applyWebpackOptionsDefaults()
   → new Compiler() → plugin.apply() → WebpackOptionsApply.process()

2. コンパイル（Compilation）
   Compiler.run() → beforeRun → run → compile
   → new Compilation() → make（エントリーからモジュール解決開始）

3. モジュール構築（Module Building）
   addEntry() → addModuleTree() → handleModuleCreation()
   → NormalModuleFactory.create() → NormalModule.build()
   → Parser.parse() → 依存関係の収集 → 再帰的にモジュール解決

4. チャンク最適化（Chunk Optimization）
   seal() → optimizeModules → optimizeChunks → SplitChunksPlugin
   → ModuleConcatenationPlugin → MangleExportsPlugin

5. コード生成（Code Generation）
   codeGeneration() → createChunkAssets() → RuntimeModule.generate()
   → processAssets

6. 出力（Emit）
   emit → emitAssets → afterEmit → done
```

---

## 6. 主要コンポーネント

> このセクションでは、主要なコンポーネントとその連携を解説します。

### 6.1 エントリーポイント

**パッケージエントリー: `lib/index.js`**

すべての公開APIを遅延ロードで提供するファサードです。`memoize` を使って、実際にアクセスされるまでモジュールの読み込みを遅延させます。

```javascript
// ファイル: lib/index.js:6-9
const util = require("util");
const memoize = require("./util/memoize");
```

**webpack関数: `lib/webpack.js`**

ユーザーが呼び出す主要関数。設定の正規化、Compilerの生成、プラグインの適用を行います。

```javascript
// ファイル: lib/webpack.js:76-117
const createCompiler = (rawOptions, compilerIndex) => {
	let options = getNormalizedWebpackOptions(rawOptions);
	applyWebpackOptionsBaseDefaults(options);
	// ...
	const compiler = new Compiler(
		/** @type {string} */ (options.context),
		options
	);
	new NodeEnvironmentPlugin({
		infrastructureLogging: options.infrastructureLogging
	}).apply(compiler);
	if (Array.isArray(options.plugins)) {
		for (const plugin of options.plugins) {
			if (typeof plugin === "function") {
				(plugin).call(compiler, compiler);
			} else if (plugin) {
				plugin.apply(compiler);
			}
		}
	}
	// ...
	compiler.hooks.initialize.call();
	return compiler;
};
```

**CLIエントリー: `bin/webpack.js`**

webpack-cliがインストールされているか確認し、未インストールの場合はインストールを促すインタラクティブな処理を行います。

### 6.2 ビジネスロジック

webpackの「ビジネスロジック」はモジュールバンドリングプロセスそのものです。

**Compiler (`lib/Compiler.js`)**: ビルドプロセス全体を管理する最上位オブジェクト。ファイルシステム、キャッシュ、プラグインフックを保持します。

**Compilation (`lib/Compilation.js`)**: 1回のビルドを表現する約180KBの巨大クラス。モジュールグラフの構築、依存解決、最適化、コード生成のすべてを統括します。

**NormalModuleFactory (`lib/NormalModuleFactory.js`)**: リクエスト文字列からモジュールを生成するファクトリ。ローダールールのマッチング、resolverによるパス解決を行います。

**NormalModule (`lib/NormalModule.js`)**: 通常のJavaScript/アセットモジュール。ローダーの実行、ソースのパース、コード生成を担当します。

### 6.3 データアクセス

webpackはデータベースを使用しませんが、以下の「データストア」を持ちます：

**ModuleGraph**: モジュール間の依存関係を表現するグラフ構造。

**ChunkGraph**: チャンクとモジュールの関係を管理。どのモジュールがどのチャンクに含まれるかを追跡します。

**シリアライズ基盤 (`lib/serialization/`)**: 永続キャッシュのためのミドルウェアパターン。

```javascript
// ファイル: lib/serialization/ の構成
// Serializer → ObjectMiddleware → BinaryMiddleware → FileMiddleware
// ミドルウェアチェーンでオブジェクトをバイナリに変換し、ファイルに書き出す
```

### 6.4 ユーティリティ/共通機能

`lib/util/` に60以上のユーティリティモジュールがあります。

| ユーティリティ | 説明 |
|---------------|------|
| `memoize.js` | 関数の結果をキャッシュする汎用メモ化 |
| `createHash.js` | ハッシュ関数の生成（md4, xxhash64等） |
| `SortableSet.js` | ソート可能なSet実装 |
| `LazySet.js` | 遅延評価セット |
| `AsyncQueue.js` | 非同期タスクキュー |
| `cleverMerge.js` | 設定オブジェクトの高度なマージ |
| `comparators.js` | 多様な比較関数 |
| `makeSerializable.js` | クラスのシリアライズ登録 |
| `identifier.js` | モジュールパスの正規化 |
| `Semaphore.js` | 並行処理制御 |

---

## 7. よく使われるパターン

> このセクションでは、コード内で頻出するパターンを解説します。

### パターン一覧

| パターン | 説明 | 出現頻度 | 代表的なファイル |
|---------|------|---------|-----------------|
| プラグインパターン | `apply(compiler)` でフックに登録 | 高 | `lib/*Plugin.js` 全般 |
| メモ化パターン | 遅延ロード・キャッシュ | 高 | `lib/util/memoize.js`, `lib/index.js` |
| フックパターン | tapableによるイベント駆動 | 高 | `lib/Compiler.js`, `lib/Compilation.js` |
| ファクトリパターン | オブジェクト生成の委譲 | 中 | `lib/NormalModuleFactory.js` |
| シリアライズパターン | `serialize`/`deserialize` | 中 | `lib/dependencies/*.js` |
| ミドルウェアパターン | 変換チェーン | 中 | `lib/serialization/Serializer.js` |
| WeakMapキャッシュ | メモリリーク防止キャッシュ | 中 | `lib/BannerPlugin.js` |
| スキーマバリデーション | JSON Schemaによる入力検証 | 中 | `schemas/`, `lib/util/create-schema-validation.js` |

### 各パターンの詳細

#### パターン1: プラグインパターン

**目的:** webpackの機能をモジュール化し、フックシステムを通じて拡張可能にする

**実装例:**
```javascript
// ファイル: lib/EntryPlugin.js:13-70
const PLUGIN_NAME = "EntryPlugin";

class EntryPlugin {
	constructor(context, entry, options) {
		this.context = context;
		this.entry = entry;
		this.options = options || "";
	}

	apply(compiler) {
		// Phase 1: Compilation生成時にファクトリを登録
		compiler.hooks.compilation.tap(
			PLUGIN_NAME,
			(compilation, { normalModuleFactory }) => {
				compilation.dependencyFactories.set(
					EntryDependency,
					normalModuleFactory
				);
			}
		);

		// Phase 2: make フックでエントリーを追加
		const { entry, options, context } = this;
		const dep = EntryPlugin.createDependency(entry, options);

		compiler.hooks.make.tapAsync(PLUGIN_NAME, (compilation, callback) => {
			compilation.addEntry(context, dep, options, (err) => {
				callback(err);
			});
		});
	}
}
```

**解説:** プラグインは「2段階登録」パターンを取ることが多い。まず `compilation` フックで依存関係ファクトリを登録し、次に `make` フックで実際の処理を実行する。

#### パターン2: メモ化パターン

**目的:** モジュールの遅延ロードによる起動時間短縮とメモリ効率の向上

**実装例:**
```javascript
// ファイル: lib/util/memoize.js:17-34
const memoize = (fn) => {
	let cache = false;
	let result;
	return () => {
		if (cache) {
			return result;
		}
		result = fn();
		cache = true;
		(fn) = undefined; // メモリ解放
		return result;
	};
};
```

**解説:** 初回呼び出し時のみ関数を実行し、以降はキャッシュした結果を返す。`fn = undefined` により元の関数とその参照を解放し、メモリリークを防ぐ。

#### パターン3: WeakMapキャッシュパターン

**目的:** オブジェクトの寿命に紐づくキャッシュで、ガベージコレクションを妨げない

**実装例:**
```javascript
// ファイル: lib/BannerPlugin.js:94-95
/** @type {WeakMap<Source, { source: ConcatSource, comment: string }>} */
const cache = new WeakMap();
```

**解説:** `WeakMap` をキーにSourceオブジェクトを使うことで、Sourceが不要になった時に自動的にキャッシュも解放される。

---

## 8. 業務フロー追跡の実践例

> このセクションでは、実際の業務フローをコードで追跡する方法を解説します。

### 8.1 フロー追跡の基本手順

1. エントリーポイントを特定
2. 処理の流れを追跡（呼び出し関係を追う）
3. データの変換を確認
4. 最終的な出力を確認

### 8.2 フロー追跡の実例

#### 例1: webpack関数の呼び出しからビルド完了まで

**概要:** `webpack(config)` を呼び出してからバンドルファイルが出力されるまでの全体フロー

**処理フロー:**
```
webpack(config) → createCompiler() → compiler.run() → compile()
→ new Compilation() → compilation.addEntry() → モジュール解決
→ seal() → 最適化 → コード生成 → emit → done
```

**詳細な追跡:**

1. **webpack関数の呼び出し** (`lib/webpack.js:76-117`)
   ```javascript
   const createCompiler = (rawOptions, compilerIndex) => {
   	let options = getNormalizedWebpackOptions(rawOptions);
   	applyWebpackOptionsBaseDefaults(options);
   	const compiler = new Compiler(options.context, options);
   	// プラグインの適用
   	new NodeEnvironmentPlugin({...}).apply(compiler);
   	for (const plugin of options.plugins) {
   		plugin.apply(compiler);
   	}
   	// デフォルトオプションの適用とフック発火
   	compiler.hooks.environment.call();
   	compiler.hooks.afterEnvironment.call();
   	new WebpackOptionsApply().process(options, compiler, interception);
   	compiler.hooks.initialize.call();
   	return compiler;
   };
   ```

2. **Compilerのhooks定義** (`lib/Compiler.js:163-238`)
   ```javascript
   this.hooks = Object.freeze({
   	initialize: new SyncHook([]),
   	done: new AsyncSeriesHook(["stats"]),
   	beforeRun: new AsyncSeriesHook(["compiler"]),
   	run: new AsyncSeriesHook(["compiler"]),
   	emit: new AsyncSeriesHook(["compilation"]),
   	compilation: new SyncHook(["compilation", "params"]),
   	make: new AsyncParallelHook(["compilation"]),
   	// ...
   });
   ```

3. **エントリーの追加** (`lib/EntryPlugin.js:47-51`)
   ```javascript
   compiler.hooks.make.tapAsync(PLUGIN_NAME, (compilation, callback) => {
   	compilation.addEntry(context, dep, options, (err) => {
   		callback(err);
   	});
   });
   ```

4. **アセットの出力** (`lib/BannerPlugin.js:99-133`)
   ```javascript
   compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
   	compilation.hooks.processAssets.tap(
   		{ name: PLUGIN_NAME, stage },
   		() => {
   			// 各チャンクのファイルにバナーを追加
   		}
   	);
   });
   ```

#### 例2: プラグインが処理に介入する流れ

**概要:** BannerPluginがビルド出力にバナーコメントを追加するフロー

**処理フロー:**
```
BannerPlugin.apply() → compiler.hooks.compilation に登録
→ Compilation作成時に processAssets フックに登録
→ アセット処理フェーズでバナー追加
```

**詳細な追跡:**

1. **プラグインの登録** (`lib/BannerPlugin.js:55-62`)
   ```javascript
   constructor(options) {
   	validate(options);     // スキーマバリデーション
   	this.options = options;
   	this.banner = this._initBanner();
   }
   ```

2. **apply でフックに登録** (`lib/BannerPlugin.js:87-134`)
   ```javascript
   apply(compiler) {
   	compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
   		compilation.hooks.processAssets.tap(
   			{ name: PLUGIN_NAME, stage },
   			() => {
   				for (const chunk of compilation.chunks) {
   					for (const file of chunk.files) {
   						compilation.updateAsset(file, (old) => {
   							return new ConcatSource(comment, "\n", old);
   						});
   					}
   				}
   			}
   		);
   	});
   }
   ```

### 8.3 フロー追跡チェックリスト

- [ ] エントリーポイントを特定したか（`lib/webpack.js` → `Compiler.run()`）
- [ ] 呼び出し関係を把握したか（フック発火順序を追跡）
- [ ] データの変換ポイントを確認したか（Module → Chunk → Asset）
- [ ] エラーハンドリングを確認したか（`WebpackError` サブクラスの使用）
- [ ] 最終的な出力を確認したか（`emit` フックでのファイル書き出し）

---

## 9. 設計書の参照順序

> このセクションでは、プロジェクト理解のための設計書参照順序を案内します。

### 9.1 目的別ロードマップ

#### 全体像を把握したい場合
1. `README.md` — プロジェクト概要と機能一覧
2. `CONTRIBUTING.md` — 開発ガイドライン
3. `lib/webpack.js` — webpack関数の全体フロー
4. `lib/Compiler.js` — フックの定義とビルドライフサイクル

#### 特定機能を理解したい場合
1. 該当する `lib/*Plugin.js` — 機能の実装
2. 関連する `lib/dependencies/*Dependency.js` — 依存関係の定義
3. 関連する `schemas/plugins/*.json` — 設定スキーマ
4. 関連する `test/configCases/` — 設定例とテストケース

#### 改修作業を行う場合
1. `_SETUP.md` — 開発環境セットアップ
2. 対象機能の `*Plugin.js` または対象ディレクトリのソース
3. `test/` 配下の関連テスト — 既存テストの確認
4. `TESTING_DOCS.md` — テスト方針の確認

#### プラグインを開発したい場合
1. `lib/EntryPlugin.js` — 最小プラグインの参考実装
2. `lib/BannerPlugin.js` — 典型的なプラグインパターン
3. `lib/Compiler.js` のフック定義 — 利用可能なフック一覧
4. `lib/Compilation.js` のフック定義 — コンパイレーション時のフック一覧

### 9.2 ドキュメント一覧

| ドキュメント | 概要 | 参照タイミング |
|-------------|------|---------------|
| `README.md` | プロジェクト概要、機能一覧、使い方 | 最初に読む |
| `CONTRIBUTING.md` | 開発への参加方法、コーディング規約 | 開発開始時 |
| `_SETUP.md` | 開発環境のセットアップ手順 | 環境構築時 |
| `TESTING_DOCS.md` | テスト方針、テストの書き方 | テスト作成時 |
| `CHANGELOG.md` | バージョン履歴と変更点 | バージョン確認時 |
| `GOVERNANCE.md` | プロジェクトガバナンス | 意思決定プロセス確認時 |
| `WORKING_GROUP.md` | ワーキンググループの情報 | 組織体制確認時 |
| `types.d.ts` | TypeScript型定義（約500KB） | API型の確認時 |
| `declarations.d.ts` | WebpackOptions等の型宣言 | 設定型の確認時 |

---

## 10. トラブルシューティング

> このセクションでは、コードリーディング時によくある問題と解決法を解説します。

### よくある疑問と回答

#### Q: `lib/Compilation.js` が約180KBもあり巨大すぎて読めません。どこから読めばよいですか？
A: まずコンストラクタのフック定義部分を読み、どのようなフックがあるかを把握してください。次に `addEntry()` → `_addEntryItem()` → `addModuleTree()` の流れを追うと、モジュールグラフ構築の全体像が見えてきます。`seal()` メソッドが最適化・コード生成フェーズのエントリーポイントです。

#### Q: フックの発火順序を知りたい
A: `lib/Compiler.js` の `compile()` メソッドと `run()` メソッドを読むと、フックの発火順序がわかります。主要な順序は：`beforeRun` → `run` → `beforeCompile` → `compile` → `thisCompilation` → `compilation` → `make` → `finishMake` → `afterCompile` → `shouldEmit` → `emit` → `afterEmit` → `done`

#### Q: 特定の依存関係（require/import）がどう処理されるか知りたい
A: `lib/dependencies/` ディレクトリで該当する Dependency クラスを探してください。CommonJS の `require` は `CommonJsRequireDependency.js` 等、ESM の `import` は `HarmonyImportDependency.js` 等で処理されます。対応する `*ParserPlugin.js` がパーサーフックを通じて依存関係を検出します。

#### Q: プラグインの `stage` とは何ですか？
A: 同一フックに複数のプラグインが登録される場合の実行順序を制御するための値です。`lib/Compilation.js` に `PROCESS_ASSETS_STAGE_*` として定義されています。数値が小さいほど先に実行されます。

### デバッグのヒント

- **`--stats verbose`** オプションでビルド統計の詳細を出力できます
- `lib/debug/` ディレクトリにデバッグ用プラグインがあります
- `tooling/print-cache-file.js` でキャッシュファイルの内容を確認できます
- `tooling/decode-debug-hash.js` でデバッグハッシュをデコードできます
- テストの実行には `yarn test:unit`（単体テスト）、`yarn test:basic`（基本テスト）、`yarn test:integration`（統合テスト）が使えます

---

## 付録

### A. 用語集

| 用語 | 説明 |
|-----|------|
| Compiler | ビルドプロセス全体を管理する最上位オブジェクト |
| Compilation | 1回のビルドを表現するオブジェクト。モジュールグラフの構築から出力まで |
| Module | バンドル対象の個々のファイルを表現する抽象概念 |
| NormalModule | 通常のJavaScript/アセットファイルを表すモジュール |
| Chunk | 出力ファイルの単位。1つ以上のモジュールを含む |
| ChunkGroup | 関連するチャンクのグループ |
| Entrypoint | エントリーポイントとなるチャンクグループ |
| Dependency | モジュール間の依存関係を表現するオブジェクト |
| Loader | モジュールのソースコードを変換する関数 |
| Plugin | apply(compiler) メソッドを持つオブジェクト。フックに処理を登録する |
| Hook (tapable) | イベント駆動のプラグインシステムの基盤 |
| tap / tapAsync | フックに同期/非同期ハンドラを登録するメソッド |
| ModuleGraph | モジュール間の依存関係グラフ |
| ChunkGraph | チャンクとモジュールの対応関係グラフ |
| RuntimeModule | バンドル出力に埋め込まれるランタイムコードを生成するモジュール |
| Asset | 最終的に出力されるファイル（バンドルJS, CSS等） |
| Seal | コンパイレーションを「封印」し、最適化とコード生成を開始するプロセス |
| Tree Shaking | 使用されていないエクスポートを除去する最適化 |
| Code Splitting | コードを複数チャンクに分割して遅延ロードを可能にする機能 |
| HMR (Hot Module Replacement) | 実行中のアプリケーションのモジュールを動的に入れ替える機能 |
| Module Federation | 複数のwebpackビルド間でモジュールを共有する機能 |
| Schema Validation | JSON Schemaによるwebpack設定のバリデーション |

### B. ファイル一覧

| ファイル/ディレクトリ | 説明 | 主な内容 |
|---------------------|------|---------|
| `package.json` | パッケージ定義 | 依存関係、スクリプト、メタデータ |
| `lib/index.js` | メインエントリーポイント | 全公開APIの遅延ロードエクスポート |
| `lib/webpack.js` | webpack関数 | Compiler生成、設定正規化 |
| `lib/Compiler.js` | Compilerクラス | ビルドライフサイクル管理（約42KB） |
| `lib/Compilation.js` | Compilationクラス | モジュールグラフ構築・最適化（約180KB） |
| `lib/NormalModule.js` | 通常モジュール | ローダー実行、パース、コード生成 |
| `lib/NormalModuleFactory.js` | モジュールファクトリ | モジュール生成、ルールマッチング |
| `lib/Chunk.js` | チャンククラス | 出力単位の管理（約24KB） |
| `lib/ChunkGraph.js` | チャンクグラフ | チャンク-モジュール関係（約58KB） |
| `lib/Dependency.js` | 依存関係基底 | 依存関係の共通インターフェース |
| `lib/RuntimeGlobals.js` | ランタイムグローバル | ランタイム変数の定数定義 |
| `types.d.ts` | TypeScript型定義 | 公開APIの型定義（約500KB） |
| `schemas/WebpackOptions.json` | 設定スキーマ | webpack設定のJSON Schema（約205KB） |
| `jest.config.js` | テスト設定 | Jestの設定 |

### C. 参考資料

- [webpack 公式ドキュメント](https://webpack.js.org/)
- [webpack GitHub リポジトリ](https://github.com/webpack/webpack)
- [tapable ライブラリ](https://github.com/webpack/tapable) — フック/プラグインシステム
- [enhanced-resolve](https://github.com/webpack/enhanced-resolve) — モジュール解決
- [webpack-sources](https://github.com/webpack/webpack-sources) — ソースコード生成
- [loader-runner](https://github.com/webpack/loader-runner) — ローダー実行
- [Node.js CommonJS Modules](https://nodejs.org/api/modules.html) — モジュールシステム
- [JSON Schema](https://json-schema.org/) — 設定バリデーション
