# 機能設計書 81-RequireJS互換

## 概要

本ドキュメントは、webpackにおけるRequireJS互換機能（RequireJsStuffPlugin）の設計を記述する。RequireJS固有のAPI呼び出しや式をwebpackのランタイムに適合する形に変換し、RequireJSベースの既存コードをwebpackで処理可能にするための互換レイヤーを提供する。

### 本機能の処理概要

RequireJsStuffPluginは、RequireJSのAPI（`require.config`、`requirejs.config`、`require.version`、`requirejs.onError`）をwebpackのコンパイル時に定数値やランタイムグローバルに置換するプラグインである。

**業務上の目的・背景**：RequireJSはAMD（Asynchronous Module Definition）仕様に基づくモジュールローダーであり、多くのレガシープロジェクトで使用されている。webpackへの移行を容易にするため、RequireJS固有のAPIをwebpackの仕組みに対応させる互換レイヤーが必要である。これにより、既存のRequireJSベースのコードを大幅に書き換えることなくwebpackでバンドルできる。

**機能の利用シーン**：RequireJSベースの既存プロジェクトをwebpackに移行する際に使用される。具体的には、`require.config()`による設定呼び出しや`require.version`参照がソースコード内に存在する場合、これらを無害な定数やwebpackランタイムのグローバル関数に置換する。

**主要な処理内容**：
1. JavaScriptパーサのフックに登録し、RequireJS固有のAPI呼び出し・式参照を検出する
2. `require.config()`および`requirejs.config()`呼び出しを`undefined`に置換する
3. `require.version`式を`"0.0.0"`文字列リテラルに置換する
4. `requirejs.onError`式をwebpackの`__webpack_require__.oe`（uncaughtErrorHandler）に置換する
5. 上記の置換はConstDependencyとして依存グラフに追加され、コード生成時に反映される

**関連システム・外部連携**：特になし。webpack内部のパーサフックシステムおよびConstDependencyを利用する。

**権限による制御**：パーサオプション`requireJs`が`true`に設定されている場合のみ有効化される。デフォルトでは無効。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 本機能に関連する画面はなし |

## 機能種別

コード変換処理（コンパイル時の静的コード置換）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| parserOptions.requireJs | boolean | No | RequireJS互換機能の有効/無効フラグ | undefined または falsy の場合は機能が無効化される |

### 入力データソース

- webpack設定ファイルの`module.parser.javascript.requireJs`オプション
- JavaScriptソースコード（パーサによる解析対象）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| ConstDependency | Dependency | ソースコード上のRequireJS API参照を置換する定数依存オブジェクト |

### 出力先

コンパイル結果のモジュール依存リスト（presentationalDependency）に追加され、コード生成時にソースコード上の該当箇所が置換される。

## 処理フロー

### 処理シーケンス

```
1. プラグイン適用（apply）
   └─ compiler.hooks.compilationフックに登録
2. コンパイル開始時にハンドラ登録
   └─ ConstDependencyテンプレートを登録
   └─ normalModuleFactory.hooks.parserにハンドラを登録（AUTO/DYNAMIC両モジュールタイプ）
3. パーサオプション確認
   └─ parserOptions.requireJsがfalsy → 処理をスキップ
4. パーサフック登録
   ├─ parser.hooks.call "require.config" → undefinedに置換
   ├─ parser.hooks.call "requirejs.config" → undefinedに置換
   ├─ parser.hooks.expression "require.version" → "0.0.0"に置換
   └─ parser.hooks.expression "requirejs.onError" → __webpack_require__.oeに置換
5. ソースコード解析時にフック発火
   └─ ConstDependencyが作成されモジュールに追加
```

### フローチャート

```mermaid
flowchart TD
    A[プラグイン適用] --> B[compilation フック登録]
    B --> C[ConstDependency テンプレート登録]
    B --> D[parser フック登録]
    D --> E{parserOptions.requireJs?}
    E -->|false/undefined| F[処理スキップ]
    E -->|true| G[require.config → undefined]
    E -->|true| H[requirejs.config → undefined]
    E -->|true| I[require.version → 0.0.0]
    E -->|true| J[requirejs.onError → oe]
    G --> K[ConstDependency 追加]
    H --> K
    I --> K
    J --> K
    K --> L[コード生成時に置換反映]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-81-1 | RequireJS有効化条件 | parserOptions.requireJsがtruthyの場合のみフック登録を行う | パーサ初期化時 |
| BR-81-2 | config呼び出し無効化 | require.config()およびrequirejs.config()はundefinedに置換される | RequireJS有効時 |
| BR-81-3 | バージョン固定値 | require.versionは常に"0.0.0"を返す | RequireJS有効時 |
| BR-81-4 | エラーハンドラ転送 | requirejs.onErrorはwebpackのuncaughtErrorHandlerに転送される | RequireJS有効時 |
| BR-81-5 | 対象モジュールタイプ | AUTO（自動検出）とDYNAMIC（動的）のJavaScriptモジュールタイプのみに適用される | パーサフック登録時 |

### 計算ロジック

特になし。

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

本機能にデータベース操作は含まれない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | - | 本機能固有のエラーは発生しない | - |

### リトライ仕様

リトライ処理は不要。

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

トランザクション処理は不要。

## パフォーマンス要件

パーサフックの登録・発火は軽量な定数置換であり、パフォーマンスへの影響は極めて小さい。

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

特になし。RequireJSのconfig呼び出しをundefinedに置換するため、外部設定のインジェクションリスクを軽減する効果がある。

## 備考

- RequireJS互換はレガシー機能であり、新規プロジェクトでは使用が推奨されない
- AMD構文のサポート（define、require([...])等）は別機能（依存性解析 No.6）で提供される
- `requirejs.onError`の置換先である`RuntimeGlobals.uncaughtErrorHandler`は`__webpack_require__.oe`に対応する

---

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

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

### 推奨読解順序

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

ConstDependencyは、ソースコード上の特定の式をコンパイル時に定数値で置換するための依存オブジェクトである。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ConstDependency.js | `lib/dependencies/ConstDependency.js` | expression、range、runtimeRequirementsの3プロパティが置換処理の核 |
| 1-2 | RuntimeGlobals.js | `lib/RuntimeGlobals.js` | uncaughtErrorHandlerが`__webpack_require__.oe`に対応することを確認 |

**読解のコツ**: ConstDependencyはNullDependencyを継承し、モジュール間の依存関係は持たないが、コード生成時にソースコードの文字列置換を行う「表示用依存（presentational dependency）」として機能する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | RequireJsStuffPlugin.js | `lib/RequireJsStuffPlugin.js` | プラグイン全体が84行と非常にコンパクト。applyメソッドが唯一のエントリーポイント |

**主要処理フロー**:
1. **30-83行目**: applyメソッド全体 - compiler.hooks.compilationフックにtapし、パーサフックを登録
2. **34-37行目**: ConstDependencyテンプレートの登録
3. **43-49行目**: パーサオプションの確認。requireJsがfalsy（undefinedを含む）の場合は早期リターン
4. **51-53行目**: `require.config`呼び出しをundefinedに置換
5. **54-56行目**: `requirejs.config`呼び出しをundefinedに置換
6. **58-63行目**: `require.version`式を"0.0.0"に置換
7. **64-73行目**: `requirejs.onError`式をRuntimeGlobals.uncaughtErrorHandlerに置換（ランタイム依存あり）
8. **75-80行目**: AUTO/DYNAMICの両モジュールタイプのパーサにhandlerを登録

#### Step 3: ヘルパー関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | JavascriptParserHelpers.js | `lib/javascript/JavascriptParserHelpers.js` | toConstantDependency関数（118-129行目）がConstDependencyの作成と追加を担う |

**主要処理フロー**:
- **118-129行目**: toConstantDependency関数。パーサ、置換値、ランタイム要件を受け取り、式が検出されたときにConstDependencyを作成してモジュールに追加するクロージャを返す

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

```
RequireJsStuffPlugin.apply(compiler)
    |
    +-- compiler.hooks.compilation.tap()
        |
        +-- compilation.dependencyTemplates.set(ConstDependency)
        |
        +-- normalModuleFactory.hooks.parser.tap(JAVASCRIPT_MODULE_TYPE_AUTO, handler)
        |
        +-- normalModuleFactory.hooks.parser.tap(JAVASCRIPT_MODULE_TYPE_DYNAMIC, handler)
            |
            +-- handler(parser, parserOptions)
                |
                +-- parser.hooks.call.for("require.config").tap()
                |   +-- toConstantDependency(parser, "undefined")
                |       +-- new ConstDependency("undefined", range)
                |           +-- module.addPresentationalDependency(dep)
                |
                +-- parser.hooks.call.for("requirejs.config").tap()
                |   +-- toConstantDependency(parser, "undefined")
                |
                +-- parser.hooks.expression.for("require.version").tap()
                |   +-- toConstantDependency(parser, '"0.0.0"')
                |
                +-- parser.hooks.expression.for("requirejs.onError").tap()
                    +-- toConstantDependency(parser, "__webpack_require__.oe", [...])
```

### データフロー図

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

JavaScriptソースコード
  require.config({...})  --> RequireJsStuffPlugin          --> undefined
  requirejs.config({..}) --> RequireJsStuffPlugin          --> undefined
  require.version        --> RequireJsStuffPlugin          --> "0.0.0"
  requirejs.onError      --> RequireJsStuffPlugin          --> __webpack_require__.oe

parserOptions.requireJs  --> 有効/無効判定                  --> フック登録の可否
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| RequireJsStuffPlugin.js | `lib/RequireJsStuffPlugin.js` | ソース | メインプラグイン。RequireJS API の検出と置換ロジック |
| ConstDependency.js | `lib/dependencies/ConstDependency.js` | ソース | 定数置換を表現する依存クラス |
| JavascriptParserHelpers.js | `lib/javascript/JavascriptParserHelpers.js` | ソース | toConstantDependencyヘルパー関数 |
| RuntimeGlobals.js | `lib/RuntimeGlobals.js` | ソース | uncaughtErrorHandler等のランタイムグローバル定義 |
| ModuleTypeConstants.js | `lib/ModuleTypeConstants.js` | ソース | JAVASCRIPT_MODULE_TYPE_AUTO/DYNAMIC定数 |
