# 機能設計書 10-createApp()

## 概要

本ドキュメントは、Vue 3における`createApp()` APIの機能設計を記述する。`createApp()`はVueアプリケーションインスタンスを生成するエントリーポイントであり、コンポーネントの登録、プラグインの適用、DOMへのマウントを管理する中核APIである。

### 本機能の処理概要

`createApp()`は、ルートコンポーネントとオプションのPropsを受け取り、Appインスタンスを生成する。Appインスタンスは`mount()`, `unmount()`, `use()`, `component()`, `directive()`, `provide()`, `runWithContext()`などのメソッドを提供し、アプリケーション全体のライフサイクルと設定を管理する。runtime-domパッケージでは、さらにDOMコンテナの正規化やテンプレートの自動検出を追加している。

**業務上の目的・背景**：Vue 3アプリケーションの最も基本的なエントリーポイントであり、全てのVueアプリケーションはcreateApp()から始まる。アプリケーションのグローバル設定、プラグインシステム、コンポーネント/ディレクティブのグローバル登録、依存性注入のルートを提供する。

**機能の利用シーン**：アプリケーション起動時のエントリーポイント、テスト環境でのアプリケーション生成、マイクロフロントエンドでの複数アプリ管理、カスタム要素のアプリ生成など。画面機能マッピングではOptions Panel（コンパイルオプション）でのVueアプリケーションインスタンス生成に使用されている。

**主要な処理内容**：
1. AppContextの生成（設定、mixins、コンポーネント、ディレクティブ、provides）
2. Appオブジェクトの構築（uid, rootComponent, rootProps等）
3. plugin管理（use()）: install関数の呼び出しとWeakSetによる重複防止
4. グローバルコンポーネント/ディレクティブ登録（component(), directive()）
5. mount(): VNode生成 -> render/hydrate -> パブリックインスタンス返却
6. unmount(): render(null) -> プラグインクリーンアップ -> devtools通知
7. provide(): コンテキストレベルの依存性注入
8. runWithContext(): アプリコンテキストでの関数実行

**関連システム・外部連携**：`@vue/runtime-core`パッケージのapiCreateApp.tsで基本実装、`@vue/runtime-dom`パッケージのindex.tsでDOMレンダラーとの統合。renderer.ts（レンダリング）、vnode.ts（VNode生成）、component.ts（コンポーネントインスタンス）と連携。

**権限による制御**：特になし。ただし、マウント済みのアプリへの再マウントは警告される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 5 | Options Panel（コンパイルオプション） | 主画面 | オプションパネルのVueアプリケーションインスタンス生成（#headerにマウント） |

## 機能種別

アプリケーション管理 / ライフサイクル管理API

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| rootComponent | Component | Yes | ルートコンポーネント定義（オブジェクトまたは関数） | - |
| rootProps | Data \| null | No | ルートコンポーネントに渡すProps | オブジェクトであること（開発モードで警告） |

### 入力データソース

APIの引数として直接渡される。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| App | App\<HostElement\> | mount/unmount/use/component/directive/provide等のメソッドを持つアプリインスタンス |

### 出力先

呼び出し元に返却。mount()によりDOMコンテナにレンダリングされる。

## 処理フロー

### 処理シーケンス

```
1. createApp(rootComponent, rootProps?)が呼び出される（runtime-dom）
   └─ ensureRenderer()でレンダラーを取得/生成
2. ensureRenderer().createApp(rootComponent, rootProps)を呼び出す
   └─ createAppAPI(render, hydrate)で生成されたファクトリ関数
3. createAppContext()でAppContextを生成
   └─ config, mixins, components, directives, provides, キャッシュ群
4. Appオブジェクトを構築
   ├─ _uid: uid++
   ├─ _component: rootComponent
   ├─ _props: rootProps
   └─ version, config, use, mixin, component, directive, mount, unmount, provide, runWithContext
5. mount(containerOrSelector)が呼ばれた場合:
   ├─ normalizeContainer()でDOMコンテナを取得
   ├─ テンプレート未定義の場合はcontainer.innerHTMLをテンプレートとして使用
   ├─ container.textContent = ''でクリア
   ├─ createVNode(rootComponent, rootProps)でVNode生成
   ├─ render(vnode, rootContainer, namespace)でレンダリング
   └─ getComponentPublicInstance()を返却
6. unmount()が呼ばれた場合:
   ├─ pluginCleanupFnsを実行
   ├─ render(null, app._container)でアンマウント
   └─ devtoolsUnmountApp(app)
```

### フローチャート

```mermaid
flowchart TD
    A[createApp rootComponent, rootProps] --> B[ensureRenderer]
    B --> C[createAppAPI render, hydrate]
    C --> D[createAppContext]
    D --> E[App object 構築]
    E --> F[App 返却]
    F --> G[app.mount container]
    G --> H[normalizeContainer]
    H --> I{container存在?}
    I -->|No| J[return undefined]
    I -->|Yes| K{template/render存在?}
    K -->|No| L[container.innerHTML をtemplate]
    K -->|Yes| M[続行]
    L --> M
    M --> N[container.textContent = 空]
    N --> O[createVNode rootComponent, rootProps]
    O --> P{isHydrate?}
    P -->|Yes| Q[hydrate vnode, container]
    P -->|No| R[render vnode, container, namespace]
    Q --> S[isMounted = true]
    R --> S
    S --> T[ComponentPublicInstance返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 重複マウント防止 | isMountedフラグで二重マウントを防止。警告を出力 | mount()が2回目以降に呼ばれた場合 |
| BR-02 | プラグイン重複防止 | WeakSetでプラグインの重複インストールを防止 | use()で同一プラグインが2回目以降に渡された場合 |
| BR-03 | コンテナ既存アプリ検出 | __vue_app__プロパティで既存アプリの存在を検出して警告 | 既にマウント済みのコンテナへのマウント時 |
| BR-04 | テンプレート自動検出 | render/template未定義の場合、container.innerHTMLをテンプレートとして使用 | runtime-domのmount()内 |
| BR-05 | コンテナクリア | マウント前にcontainer.textContentを空にする | Element nodeTypeの場合 |
| BR-06 | config変更不可 | app.config全体の置換は禁止（個別プロパティの変更は可能） | config setterアクセス時 |
| BR-07 | Mixin制限 | Options APIビルドでのみmixinが利用可能 | __FEATURE_OPTIONS_API__が有効な場合 |

### 計算ロジック

- uid: グローバルカウンター（0から自動インクリメント）
- コンテナ正規化: 文字列の場合document.querySelector()、Element/ShadowRootの場合そのまま使用

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 開発者警告 | rootPropsがオブジェクトでない | `root props passed to app.mount() must be an object.` |
| - | 開発者警告 | 二重マウント | `App has already been mounted.` |
| - | 開発者警告 | 既存アプリがマウント済みのコンテナ | `There is already an app instance mounted on the host container.` |
| - | 開発者警告 | 重複プラグイン | `Plugin has already been applied to target app.` |
| - | 開発者警告 | 重複コンポーネント登録 | `Component "{name}" has already been registered in target app.` |
| - | 開発者警告 | 重複ディレクティブ登録 | `Directive "{name}" has already been registered in target app.` |
| - | 開発者警告 | 未マウントアプリのunmount | `Cannot unmount an app that is not mounted.` |
| - | 開発者警告 | app.configの直接置換 | `app.config cannot be replaced. Modify individual options instead.` |
| ErrorCodes.APP_UNMOUNT_CLEANUP | ランタイムエラー | unmount時のプラグインクリーンアップ失敗 | callWithAsyncErrorHandling |

### リトライ仕様

該当なし

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

該当なし

## パフォーマンス要件

- レンダラーの遅延生成（ensureRenderer）によりreactivityのみ使用する場合はレンダラーコードがツリーシェイキングされる
- WeakMapベースのキャッシュ（optionsCache, propsCache, emitsCache）でコンポーネントオプションの再解析を防止

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

- container.innerHTMLをテンプレートとして使用する場合、XSSリスクがある。サーバーレンダリングされた信頼できるコンテンツのみ使用すべき
- app.config.globalPropertiesへの意図しない上書きに注意

## 備考

- `createSSRApp()`はhydration対応版で、`ensureHydrationRenderer()`を使用する
- `onUnmount(cleanupFn)`でアプリアンマウント時のクリーンアップを登録可能
- `runWithContext(fn)`はapp.provide()で提供された値をinject()で取得するためのコンテキスト設定
- DevTools連携（devtoolsInitApp, devtoolsUnmountApp）は__DEV__または__FEATURE_PROD_DEVTOOLS__で有効
- __COMPAT__モードでVue 2互換プロパティが追加される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | apiCreateApp.ts | `packages/runtime-core/src/apiCreateApp.ts` | Appインターフェース（33-119行目）。全メソッドシグネチャ |
| 1-2 | apiCreateApp.ts | `packages/runtime-core/src/apiCreateApp.ts` | AppConfig（123-169行目）。errorHandler, warnHandler, compilerOptions等 |
| 1-3 | apiCreateApp.ts | `packages/runtime-core/src/apiCreateApp.ts` | AppContext（171-206行目）。app, config, mixins, components, directives, provides |
| 1-4 | apiCreateApp.ts | `packages/runtime-core/src/apiCreateApp.ts` | Plugin型定義（208-222行目）。ObjectPlugin, FunctionPlugin |

**読解のコツ**: createApp()は2層構造。runtime-coreのcreateAppAPI()がコアロジックを提供し、runtime-domのcreateApp()がDOM固有の処理を追加する。runtime-domのindex.tsから読み始め、runtime-coreのapiCreateApp.tsに進むのが効率的。

#### Step 2: エントリーポイントを理解する（runtime-dom層）

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | index.ts | `packages/runtime-dom/src/index.ts` | createApp()（98-139行目）。ensureRenderer、mount上書き、normalizeContainer |

**主要処理フロー**:
- **98-99行目**: ensureRenderer().createApp()でコアApp生成
- **101-104行目**: 開発モードでnativeTag/compilerOptionsチェック注入
- **106-107行目**: 元のmountを保持し、DOM固有のmountで上書き
- **108行目**: normalizeContainer()でコンテナ正規化
- **112-131行目**: テンプレート自動検出、コンテナクリア
- **137行目**: 元のmountを呼び出す

#### Step 3: コアcreateApp実装を理解する（runtime-core層）

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | apiCreateApp.ts | `packages/runtime-core/src/apiCreateApp.ts` | createAppAPI()（253-487行目）。ファクトリ関数パターン |
| 3-2 | apiCreateApp.ts | `packages/runtime-core/src/apiCreateApp.ts` | createAppContext()（224-244行目）。コンテキスト初期化 |

**主要処理フロー**:
- **257-258行目**: createApp(rootComponent, rootProps)のシグネチャ
- **267行目**: createAppContext()でコンテキスト生成
- **273-479行目**: Appオブジェクトの構築。各メソッドの実装

#### Step 4: 各メソッドの実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | apiCreateApp.ts | `packages/runtime-core/src/apiCreateApp.ts` | use()（295-311行目）。プラグインインストール |
| 4-2 | apiCreateApp.ts | `packages/runtime-core/src/apiCreateApp.ts` | mount()（358-418行目）。VNode生成とレンダリング |
| 4-3 | apiCreateApp.ts | `packages/runtime-core/src/apiCreateApp.ts` | unmount()（431-447行目）。レンダリングツリー破棄 |
| 4-4 | apiCreateApp.ts | `packages/runtime-core/src/apiCreateApp.ts` | provide()（449-468行目）。コンテキストへの値登録 |

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

```
createApp(rootComponent, rootProps)  [runtime-dom/index.ts]
    |
    +-- ensureRenderer()
    |       +-- createRenderer(rendererOptions)
    |               +-- createAppAPI(render, hydrate)  // ファクトリ返却
    |
    +-- createAppAPI(render, hydrate)(rootComponent, rootProps)  [runtime-core/apiCreateApp.ts]
    |       +-- createAppContext()     // context生成
    |       +-- App object 構築
    |
    +-- app.mount(containerOrSelector)  [runtime-dom mount上書き]
    |       +-- normalizeContainer(containerOrSelector)
    |       +-- テンプレート自動検出
    |       +-- container.textContent = ''
    |       +-- mount(container, false, namespace)  [runtime-core mount]
    |               +-- createVNode(rootComponent, rootProps)
    |               +-- vnode.appContext = context
    |               +-- render(vnode, rootContainer, namespace)
    |               +-- getComponentPublicInstance(vnode.component)
    |
    +-- app.use(plugin, ...options)
    |       +-- installedPlugins.has(plugin)  // 重複チェック
    |       +-- plugin.install(app, ...options) or plugin(app, ...options)
    |
    +-- app.unmount()
            +-- pluginCleanupFns実行
            +-- render(null, app._container)
            +-- devtoolsUnmountApp(app)
```

### データフロー図

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

rootComponent    ───>  createApp()                         ───>  App instance
rootProps                  |
                    ensureRenderer()
                           |
                    createAppAPI(render, hydrate)
                           |
                    createAppContext()
                           |
                    App object 構築
                           |
                    [app.mount(container)]
                           |
                    normalizeContainer()
                           |
                    createVNode(rootComponent, rootProps)
                           |
                    render(vnode, container, namespace)
                           |
                    ComponentPublicInstance返却
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| apiCreateApp.ts | `packages/runtime-core/src/apiCreateApp.ts` | ソース | createAppAPI()、App/AppConfig/AppContext型定義、Plugin型 |
| index.ts | `packages/runtime-dom/src/index.ts` | ソース | runtime-dom版createApp()。DOM固有のmount処理 |
| renderer.ts | `packages/runtime-core/src/renderer.ts` | ソース | createRenderer()。render関数の実装 |
| vnode.ts | `packages/runtime-core/src/vnode.ts` | ソース | createVNode()。VNode生成 |
| component.ts | `packages/runtime-core/src/component.ts` | ソース | ComponentInternalInstance。コンポーネントインスタンス |
| nodeOps.ts | `packages/runtime-dom/src/nodeOps.ts` | ソース | DOM操作関数群 |
| patchProp.ts | `packages/runtime-dom/src/patchProp.ts` | ソース | DOMプロパティパッチング |
| errorHandling.ts | `packages/runtime-core/src/errorHandling.ts` | ソース | callWithAsyncErrorHandling |
| devtools.ts | `packages/runtime-core/src/devtools.ts` | ソース | DevTools連携 |
