Electron Main Process
electron/main.ts を中心とした Electron メインプロセスの起動シーケンスと、electron/main/ 配下の helper の構成。
全体構成
electron/
├── main.ts # 271 行に圧縮されたエントリ(旧 370 行)
├── main/ # main.ts から抽出した helper
│ ├── dbInit.ts # DB 初期化失敗時のダイアログ + リトライ
│ ├── bpOpponentVisibility.ts # BP 対戦相手ウィンドウの表示判定
│ └── perfRelay.ts # 起動計測 + perf marker IPC
├── core/ # ライフサイクル骨格
│ ├── AppLifecycle.ts # 単一インスタンスロック / グローバル例外 / app events
│ ├── PathResolver.ts # userData パス解決
│ ├── ProcessManager.ts
│ └── StartupSequencer.ts # critical-path / deferred-boot の 2 段階起動
├── windows/ # BrowserWindow ラッパ
│ ├── ControlWindowManager.ts
│ ├── OverlayWindowManager.ts
│ ├── BPOpponentWindow.ts
│ └── WindowStateStore.ts
├── ipc/ # IPC ハンドラ群
│ ├── IPCRegistry.ts # core / features を分けた段階登録
│ └── *Handlers.ts # 機能別ハンドラ
├── services/ # アプリサービス
│ ├── AutoUpdateService.ts
│ ├── LogWatcherService.ts
│ ├── BrowserAutomationService.ts
│ ├── browserAutomation/ # browser detection / response listener
│ ├── ResponseStorageService.ts
│ └── UserSettingsService.ts
├── preload/ # preload.ts の実装本体
│ ├── api/ # window.electronAPI に expose する API 群
│ ├── eventChannels.ts
│ └── types.ts
├── database.ts # 薄い facade
├── database/ # 6 repository(Database Design 参照)
└── logger.ts起動シーケンス
StartupSequencer が critical path と deferred boot に分けて初期化を進める。first paint までの時間を最短化するため、UI を先に出して DB / Service / feature IPC は後で実行する。
Critical Path の責務
| Step | 役割 | なぜ critical | 補足 |
|---|---|---|---|
loadMinimalUserSettings | bpWindowOnlyInBP 等、ウィンドウ表示判断に必要な設定だけ読む | ウィンドウ生成前に値が必要 | 失敗時はデフォルト値で続行 |
createWindows | control + overlay の BrowserWindow を生成 | 画面を出すコア処理 | overlay は OBS が読む URL |
registerCoreIpc | core IPC(ウィンドウ操作 / 設定 / アップデート等)を登録 | renderer の最初の IPC が成立する必要がある | bpOpponentWindow は null で OK(後で updateWindows で反映) |
Deferred Boot の責務
| Step | 役割 | 失敗時の振る舞い |
|---|---|---|
initDatabase | initDatabaseWithFailureDialog() で SQLite を開く | ダイアログ → 削除 / DB なし続行 / 終了 |
initServices | BPOpponentWindow 生成 / IPCRegistry に reflect | DB 不可でも UI は使えるよう続行 |
registerFeatureIpc | DB / 統計 / log watcher / browser automation 系 IPC を登録 | ユーザーが終了を選んだ場合は no-op |
startStartupImportPreview | renderer 駆動なので no-op (将来の拡張点) | — |
startLogWatcher | UserSettings の opt-in を見て auto-start(現状 false) | — |
DB 初期化失敗の対処(dbInit.ts)
initDatabaseWithFailureDialog() は initDatabase() を呼び、失敗時はダイアログでユーザに選ばせる。
- ダイアログのボタンラベル:
🗑️ DBファイルを削除して再試行/▶️ DBなしで続行/❌ アプリを終了 - 終了選択時は呼び出し側の
electron/main.tsでapp.quit()を行い、deferred boot の残りステップを skip - 単体テスト:
electron/main/__tests__/dbInit.test.ts(8 ケース)
BP 対戦相手ウィンドウ表示制御(bpOpponentVisibility.ts)
makeBPOpponentVisibility(getCtx) は closure factory。getCtx で「現在の window / onlyInBP 設定 / 試合フェーズ」を毎回読み直す。
const { applyVisibility } = makeBPOpponentVisibility(
() => ({ window: bpOpponentWindow, onlyInBP: bpWindowOnlyInBP, currentPhase })
);bpWindowOnlyInBP=false→ 常に表示bpWindowOnlyInBP=true→currentPhase === 'BP'のときだけ表示- 試合フェーズの切り替えで
applyVisibility()を呼ぶ責務は IPC ハンドラ側
起動計測 (perfRelay.ts)
| 関数 | 役割 |
|---|---|
reportBinAndModuleLoad() | PERF_RUN_ELECTRON_T0_MS 環境変数(spawn 時刻)と現在時刻の差分を [perf] electron.binAndModuleLoad=Xms として stdout に書く |
registerPerfMarkerRelay() | ELECTRON_PERF_MEASURE か ELECTRON_PERF_DEV_MEASURE が '1' のときだけ、renderer からの perf-marker IPC を stdout にリレー |
利用側スクリプト: scripts/perf/measure-startup.ts / measure-dev-startup.ts
IPC レジストリ(段階登録)
IPCRegistry は 2 段階登録 を行う。registerCore() は critical path で実行し、registerFeatures() は DB 初期化後の deferred boot で実行する。updateWindows / updateDatabaseAvailability で後から参照を差し替える。
単一インスタンスロック
AppLifecycle.setupSingleInstanceLock(onSecondInstance):
- 二重起動時、後発プロセスは即
process.exit(0) - 既存プロセスでは
onSecondInstancecallback で control window をフォーカスする
グローバル例外ハンドラ
AppLifecycle.setupGlobalErrorHandlers():
process.on('uncaughtException')/unhandledRejectionをキャッチして Logger 出力- 開発時は dev tools で詳細確認できるよう error の stack を残す
関連ドキュメント
- スキーマと repository: Database Design
- ストア / 同期: Sync and State
- ログ解析エンジン: Log Parser Architecture
Last verified: 2026-05-06 / against commit e351b23a