# 機能設計書 39-リモートモジュール

## 概要

本ドキュメントは、webpackのModule Federationにおけるリモートエントリからのモジュール取得・フォールバック処理機能について記述する。RemoteModuleとFallbackModuleが、リモートコンテナからのモジュール取得と障害時のフォールバックを担当する。

### 本機能の処理概要

リモートモジュール機能は、Module Federationにおいてホストアプリケーションがリモートコンテナからモジュールを取得する際のモジュール表現とランタイム処理を提供する。RemoteModuleがリモートモジュールの抽象化を、FallbackModuleが複数リモートソースの順次試行によるフォールバックを実現する。

**業務上の目的・背景**：マイクロフロントエンドにおいて、リモートアプリケーションのコンポーネントをホストアプリケーションから利用する際、ネットワーク障害やリモートサーバーのダウンタイムに対する耐障害性が必要である。FallbackModuleにより複数のリモートソースを順次試行し、可用性を向上させる。

**機能の利用シーン**：
- ホストアプリケーションがリモートコンテナ（mfe-b/Component等）のモジュールをimportする場合
- リモートソースのフォールバック（プライマリ→セカンダリ→...）が必要な場合
- React.lazyと組み合わせたリモートコンポーネントの遅延読み込み

**主要な処理内容**：
1. RemoteModuleによるリモートモジュールの抽象化（request, externalRequests, internalRequest, shareScope）
2. RemoteModuleのコード生成（__webpack_require__による外部モジュール取得・共有スコープ初期化・モジュール取得）
3. FallbackModuleによる複数リモートソースの順次試行コード生成
4. FallbackItemDependencyによる個別フォールバック候補の依存管理
5. RemoteRuntimeModuleによるチャンクごとのリモートモジュール読み込みランタイム

**関連システム・外部連携**：外部コンテナ（remoteEntry.js）からのモジュール取得。共有スコープ（shareScope）を通じた依存パッケージの共有。

**権限による制御**：特になし。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 19 | App (Host) (module-federation) | 主機能 | mfe-b/Component, mfe-c/Componentのリモートモジュール取得 |
| 21 | MFE-C (Remote) (module-federation) | 補助機能 | LazyComponent(Component2)の遅延読み込み用動的インポート |

## 機能種別

モジュール定義 / コード生成

## 入力仕様

### 入力パラメータ

#### RemoteModule

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| request | string | Yes | リモートモジュールのリクエスト文字列 | - |
| externalRequests | string[] | Yes | コンテナへの外部リクエストのリスト | - |
| internalRequest | string | Yes | コンテナ内の公開モジュール名 | - |
| shareScope | string | Yes | 使用する共有スコープ名 | - |

#### FallbackModule

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| requests | string[] | Yes | フォールバック候補のリクエストリスト | 1つ以上必須 |

### 入力データソース

- ContainerReferencePluginのfactorizeフックから生成されるRemoteModule
- 複数のexternalが指定されている場合に生成されるFallbackModule

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| RemoteModule CodeGeneration | Source | 外部コンテナ取得→init→getの呼び出しチェーンコード |
| FallbackModule CodeGeneration | Source | 複数候補を順次試行するフォールバックコード |
| SourceTypes | Set | "javascript"（RemoteModule）, "javascript"（FallbackModule） |

### 出力先

バンドルファイル内のモジュールコードとして出力。

## 処理フロー

### 処理シーケンス

```
RemoteModule:
1. buildフェーズ
   └─ RemoteToExternalDependency（1つ目の外部参照）とFallbackDependency（複数候補時）を登録
2. codeGenerationフェーズ
   └─ __webpack_require__(externalModuleId)でコンテナ取得
   └─ container.init(shareScope)で共有スコープ初期化
   └─ container.get(internalRequest)でモジュール取得

FallbackModule:
1. buildフェーズ
   └─ 各候補に対してFallbackItemDependencyを登録
2. codeGenerationフェーズ
   └─ 各候補を順次試行するコードを生成
   └─ 最初に成功した候補のモジュールを返却

RemoteRuntimeModule:
1. generate()
   └─ chunkToRemotesMappingでチャンクIDとリモートモジュールIDの対応を生成
   └─ idToExternalAndNameMappingでリモートモジュールIDと外部モジュール・名前の対応を生成
   └─ ensureChunkHandlers.remotesでリモートモジュール読み込みのランタイムコードを生成
```

### フローチャート

```mermaid
flowchart TD
    A[リモートモジュール要求] --> B[RemoteModule.codeGeneration]
    B --> C[__webpack_require__(externalId)]
    C --> D[container取得]
    D --> E[container.init(shareScope)]
    E --> F[container.get(internalRequest)]
    F --> G[factory関数実行]
    G --> H[モジュールエクスポート取得]

    I[フォールバック要求] --> J[FallbackModule.codeGeneration]
    J --> K[候補1を試行]
    K --> L{成功?}
    L -->|Yes| M[候補1のモジュール返却]
    L -->|No| N[候補2を試行]
    N --> O{成功?}
    O -->|Yes| P[候補2のモジュール返却]
    O -->|No| Q[次の候補...]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | モジュールタイプ | RemoteModuleはWEBPACK_MODULE_TYPE_REMOTE、FallbackModuleはWEBPACK_MODULE_TYPE_FALLBACKとして登録 | モジュール生成時 |
| BR-02 | ソースタイプ | RemoteModuleはJAVASCRIPT_TYPESとREMOTE_AND_SHARE_INIT_TYPESを提供 | getSourceTypes時 |
| BR-03 | チャンク条件 | FallbackModuleはエントリモジュールが存在するチャンクのみに配置可能 | chunkCondition時 |
| BR-04 | ランタイム要件 | RemoteModuleはRuntimeGlobals.moduleを必要とする | RUNTIME_REQUIREMENTS |
| BR-05 | 識別子形式 | RemoteModuleは"remote (shareScope) externalRequests internalRequest"形式、FallbackModuleは"fallback requests"形式 | identifier() |
| BR-06 | libIdent形式 | RemoteModuleは"webpack/container/remote/{request}"、FallbackModuleは"webpack/container/fallback/{request}/and N more" | libIdent() |

### 計算ロジック

RemoteRuntimeModule.generate()のidToExternalAndNameMapping: 各リモートモジュールについて、moduleIdをキーとし、[shareScope, name, externalModuleId]のタプルを値とするマッピングを生成する。

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

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ランタイムエラー | リモートコンテナの取得失敗 | FallbackModuleにより次の候補を試行 |
| - | ランタイムエラー | container.init失敗 | Promiseチェーンのcatchで処理 |
| - | ランタイムエラー | container.get失敗 | Promiseチェーンのcatchで処理 |

### リトライ仕様

FallbackModuleにより複数リモートソースの順次試行がフォールバックとして機能する。

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

該当なし

## パフォーマンス要件

- リモートモジュールの読み込みは非同期で行われ、Promiseベースの処理
- 共有スコープの初期化は一度だけ実行（冪等性保証）

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

- リモートコンテナからのコード実行はセキュリティリスクを伴う
- 共有スコープを通じたモジュール注入の可能性に注意

## 備考

- RemoteModuleとFallbackModuleはmakeSerializableにより永続化対応
- needBuild()はbuildInfo未設定時のみtrueを返し、不要な再ビルドを回避

---

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

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

### 推奨読解順序

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

リモートモジュールとフォールバックモジュールの構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | RemoteModule.js | `lib/container/RemoteModule.js` | 46-67行目: コンストラクタのプロパティ（request, externalRequests, internalRequest, shareScope, _identifier） |
| 1-2 | FallbackModule.js | `lib/container/FallbackModule.js` | 42-52行目: コンストラクタのプロパティ（requests, _identifier） |
| 1-3 | RemoteToExternalDependency.js | `lib/container/RemoteToExternalDependency.js` | リモート→外部参照の依存クラス |
| 1-4 | FallbackDependency.js | `lib/container/FallbackDependency.js` | フォールバック依存クラス |

**読解のコツ**: RemoteModuleはModuleクラスを継承したカスタムモジュールである。buildフェーズで依存関係を追加し、codeGenerationフェーズでソースコードを生成するwebpackモジュールの標準パターンに従っている。

#### Step 2: RemoteModuleのライフサイクルを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | RemoteModule.js | `lib/container/RemoteModule.js` | 72-92行目: identifier(), readableIdentifier(), libIdent() |
| 2-2 | RemoteModule.js | `lib/container/RemoteModule.js` | 99-100行目: needBuild() - buildInfo未設定時のみリビルド |

**主要処理フロー**:
- **53-67行目**: コンストラクタでWEBPACK_MODULE_TYPE_REMOTE型モジュールを初期化
- **64-66行目**: _identifierを"remote (shareScope) externalRequests internalRequest"形式で構築
- **99-100行目**: needBuild()でbuildInfo未設定の場合のみtrue

#### Step 3: FallbackModuleのライフサイクルを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | FallbackModule.js | `lib/container/FallbackModule.js` | 42-86行目: コンストラクタ、identifier, chunkCondition |
| 3-2 | FallbackModule.js | `lib/container/FallbackModule.js` | 84-86行目: chunkCondition - エントリモジュールが存在するチャンクのみ |

**主要処理フロー**:
- **46-52行目**: WEBPACK_MODULE_TYPE_FALLBACKでモジュールを初期化
- **84-86行目**: chunkCondition()でchunkGraph.getNumberOfEntryModules(chunk) > 0を要求

#### Step 4: RemoteRuntimeModuleを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | RemoteRuntimeModule.js | `lib/container/RemoteRuntimeModule.js` | 19-80行目: ランタイムコード生成全体 |

**主要処理フロー**:
- **32-33行目**: chunkToRemotesMappingとidToExternalAndNameMappingの初期化
- **35-61行目**: 全参照チャンクのリモートモジュールをイテレートしマッピング構築
- **62-80行目**: ensureChunkHandlers.remotesのランタイムコード生成

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

```
ContainerReferencePlugin.factorize()
    |
    +-- RemoteModule(request, externalRequests, internalRequest, shareScope)
           |
           +-- build()
           |      +-- RemoteToExternalDependency (外部参照)
           |      +-- FallbackDependency (複数候補時)
           |             +-- FallbackModule(requests)
           |                    +-- FallbackItemDependency (各候補)
           |
           +-- codeGeneration()
                  +-- __webpack_require__(externalModuleId)
                  +-- container.init(shareScope)
                  +-- container.get(internalRequest)

RemoteRuntimeModule.generate()
    +-- chunkToRemotesMapping構築
    +-- idToExternalAndNameMapping構築
    +-- ensureChunkHandlers.remotesランタイムコード
```

### データフロー図

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

リモートリクエスト ────> RemoteModule                    ──> コード生成結果
  "mfe-b/Component"        |
                           +-> build(): 依存登録
                           +-> codeGeneration():
                                 __webpack_require__(extId)  ──> コンテナ取得
                                 container.init(shareScope)  ──> 共有スコープ初期化
                                 container.get(name)         ──> モジュール取得

フォールバック ────────> FallbackModule                  ──> 順次試行コード
  [候補1, 候補2, ...]       |
                           +-> build(): 各候補の依存登録
                           +-> codeGeneration(): 順次試行ロジック
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| RemoteModule.js | `lib/container/RemoteModule.js` | ソース | リモートモジュールの抽象化 |
| FallbackModule.js | `lib/container/FallbackModule.js` | ソース | フォールバックモジュール |
| RemoteRuntimeModule.js | `lib/container/RemoteRuntimeModule.js` | ソース | リモート読み込みランタイムコード生成 |
| RemoteToExternalDependency.js | `lib/container/RemoteToExternalDependency.js` | ソース | リモート→外部参照依存 |
| FallbackDependency.js | `lib/container/FallbackDependency.js` | ソース | フォールバック依存 |
| FallbackItemDependency.js | `lib/container/FallbackItemDependency.js` | ソース | フォールバック個別アイテム依存 |
| FallbackModuleFactory.js | `lib/container/FallbackModuleFactory.js` | ソース | フォールバックモジュールファクトリ |
| ContainerReferencePlugin.js | `lib/container/ContainerReferencePlugin.js` | ソース | リモートモジュール生成の統合ポイント |
