Skip to content

改善計画書

最終更新: 2026-05-05 (App Performance Optimization spec まとめ追加)

App Performance Optimization (spec: app-performance-optimization)

Electron 起動と Control パネルのタブ切替を中心に、起動・稼働時の負荷を体系的に下げた。詳細は .spec-workflow/specs/app-performance-optimization/ と各 Implementation Logs/。基準値は perf-baseline.json

主要 KPI と達成状況

指標BeforeAfter変化判定
mainBootstrapMs(critical path)978.59 ms270.54 ms(dev 計測, trial 3)-72.4%✅ 目標 -30% 達成
controlFirstPaintMs75.9 ms取得継続中△ dev 計測の安定化が今後の課題
controlMainKb(initial load)1339.61 KB734.17 KB-45.2%✅ 目標 -20% 達成
controlTotalKb1339.61 KB1339.87 KB±0%— lazy 化で初期パスから外したのみ
overlayKb274.30 KB274.30 KB±0%— singlefile 維持
renderer に main 専用依存の混入監視なしCI で機械検出✅ Phase 3.2

Phase ごとの成果

  • Phase 0(計測基盤): scripts/perf/measure-startup.ts / measure-bundle.ts を整備し、perf-baseline.json を真実の単一 source 化。yarn perf:all 1 コマンドで再現可能。
  • Phase 1(critical path 短縮): electron/core/StartupSequencer.ts を導入し main bootstrap を「critical(ウィンドウ生成 + core IPC)」と「deferred(DB / 機能 IPC / startup-import / chokidar)」に 2 分。main.bootstrap を 978 → 270 ms に短縮。
  • Phase 2.1〜2.2(タブ lazy mount): LazyTabPanel + tabLoaders.ts で全タブを動的 import + keep-alive。タブ切替時の DOM ツリーが状態保持される。
  • Phase 3(バンドル分割):
    • 3.1: Control の viteSingleFile を外し manualChunksreact-vendor / mui / charts / vendor に分割。initial load -45%。
    • 3.2: check-renderer-imports.ts で main 専用依存の renderer 流入を検出。
    • 3.3: check-bundle-size.ts で initial load 予算を perf-baseline.json に固定。
    • 3.4: GitHub Actions の bundle-checks job に統合(当面 continue-on-error: true)。
  • Phase 5.1(dev:electron 体感改善): スプラッシュ + optimizeDeps 事前列挙 + parallel build/vite で「白画面待ち」を解消。

未達 / 持ち越し

  • 2.3 React.memo / selector 最適化(計測ベース): Profiler 計測の安定化が必要なため、別 issue に切り出し。
  • 2.4 仮想スクロール導入要否の判断: 計測待ちで延期。
  • 2.5 タブ TTI ベースライン再計測: 5.2 と同様 dev 計測の安定化と一緒に再着手。
  • 5.2 dev:electron 完全自動 3-run 計測: ユーザの実 Vite session と並走しない構成(独自 userData / 別ポート + DevTools off)に固める作業を follow-up issue として登録予定。

CI 統合(perf 計測)

  • bundle-checks job: yarn buildperf:bundleperf:check-importsperf:check-size
  • 当面 continue-on-error: true(Phase A)。1〜2 PR サイクル安定確認後に required 化(Phase B)。
  • pre-push には載せない(毎 push に build を強いるとローカル流れが重い)。
  • 予算引き上げが必要なときは npx tsx scripts/perf/check-bundle-size.ts --update --margin 5 で書き換え、PR 説明に理由を書く。

第3サイクル進捗

#項目ステータス
16useOverlayStore 分割 (617行)未着手
17Overlay.tsx 分割 (466行)未着手
18RealtimeAnalysisPanel 分割 (390行)未着手
19LogAnalysisTab 分割 (378行)未着手
20テストカバレッジ閾値の引き上げ (60→70%)未着手

第2サイクル進捗

#項目ステータス
11各タブの個別 ErrorBoundary ラップ✅ 完了 (06ef350)
12console.log → Logger 置換✅ 完了 — store/hooks (2ae87f7)
13SeasonAnalyticsPanelView 分割 (562→292行)✅ 完了 (10f4ddd)
14SettingsSubTabs 分割 (458→212行)✅ 完了 (10f4ddd)
15DB row の as any 型キャスト排除✅ 完了 (10f4ddd)

進捗

#項目ステータス
1Error Boundary の導入✅ 完了 (fcd2ad9)
2グローバルエラーハンドラの追加✅ 完了 (fcd2ad9)
3IPCチャネルのホワイトリスト化✅ 完了 (fcd2ad9)
4electronAPI ラッパーへの統一✅ 完了 — BP Window/ResponseStorage/RuntimeStatusも移行済み
5Electron サービスのテスト追加✅ 完了 (9b6b3b0) — UserSettings/ResponseStorage テスト追加
6ウィンドウマネージャ・大型コンポーネントのテスト追加✅ 完了 — フックテスト6件 + WindowStateStoreテスト追加
7大型コンポーネントの分割✅ 完了 — 全6コンポーネント分割(BrowserAutomationTab/ControlPanel/SeasonAnalyticsPanel/LogAnalysisTab/CharacterMatchupsSectionView/RealtimeAnalysisTab)
8React.memo の適用✅ 完了 (8f930d0) — 6コンポーネントに適用
9シーズンフィルタの再有効化✅ 完了 (a82a829) — 7箇所のTODO解消
10as any キャストの排除✅ 完了 (c1bd1ef)

概要

コードベース全体(React + Vite + Electron)の調査に基づく改善項目を優先度別に整理。 各項目は独立して着手可能。


HIGH優先度

1. Error Boundary の導入

  • 課題: React Error Boundary が一つも存在せず、任意のコンポーネントでレンダーエラーが発生すると UI 全体がクラッシュする
  • 提案: 共通 ErrorBoundary コンポーネントを作成し、主要画面(ControlPanel、Overlay、RealtimeAnalysisTab 等)をラップ
  • 影響範囲: src/components/ 全体
  • 見積: 小〜中

2. グローバルエラーハンドラの追加

  • 課題: Electron メインプロセスに uncaughtException / unhandledRejection ハンドラがなく、未捕捉の例外がサイレントに失敗またはクラッシュを引き起こす
  • 提案: electron/core/AppLifecycle.ts にプロセスレベルのエラーハンドラを追加し、ログ出力+ユーザー通知を行う
  • 影響範囲: electron/core/AppLifecycle.ts, electron/main.ts
  • 見積: 小

3. IPC チャネルのホワイトリスト化

  • 課題: preload.tson() メソッドが任意のチャネル文字列を受け付ける。レンダラ側で不正なチャネルのリッスンが可能
  • 提案: 許可されるチャネル名のホワイトリストを定義し、on() 内で検証
  • 影響範囲: electron/preload.ts
  • 見積: 小

4. electronAPI ラッパーへの統一

  • 課題: 20箇所以上で window.electronAPI を直接参照しており、一部は as any キャストを使用。型安全性とエラーハンドリングがバイパスされている
  • 主な該当箇所:
    • BrowserAutomationTab.tsx (5箇所)
    • useMatchListState.ts (8箇所)
    • useMatchDetail.ts (2箇所)
    • LogSimulator.tsx (1箇所)
    • SeasonAnalyticsPanel.tsx (1箇所)
    • LayoutResetButtons.tsx (6箇所, as any 付き)
    • RealtimeAnalysisTab.tsx (2箇所)
  • 提案: src/utils/electronAPI/ の型付きラッパーに全て移行し、直接アクセスを排除
  • 影響範囲: src/components/, src/hooks/
  • 見積: 中

MEDIUM優先度

5. Electron サービスのテスト追加

  • 課題: 5つのElectronサービスのうち4つがテストなし
    • AutoUpdateService.ts
    • BrowserAutomationService.ts
    • ResponseStorageService.ts
    • UserSettingsService.ts
  • 現状テストあり: LogWatcherService.test.ts のみ
  • 提案: 各サービスの責務に応じたユニットテストを追加。既存のテストパターン(electron/database/, electron/ipc/)に準拠
  • 影響範囲: electron/services/
  • 見積: 中〜大

6. ウィンドウマネージャ・大型コンポーネントのテスト追加

  • 課題:
    • 4つのウィンドウマネージャがすべてテストなし(ControlWindowManager, OverlayWindowManager, BPOpponentWindow, 予定のウィンドウ)
    • BrowserAutomationTab.tsx(986行)がテストなし
  • 提案: 重要度の高いものからテストを追加。BrowserAutomationTab はコンポーネント分割(#7)と併用が効果的
  • 影響範囲: electron/windows/, src/components/tabs/browser-automation/
  • 見積: 大

7. 大型コンポーネントの分割

  • 課題: 以下のコンポーネントが過大で、状態管理・API呼び出し・描画が混在
    • BrowserAutomationTab.tsx — 986行
    • ControlPanel.tsx — 819行
    • SeasonAnalyticsPanel.tsx — 715行
    • LogAnalysisTab.tsx — 658行
    • CharacterMatchupsSectionView.tsx — 545行
    • RealtimeAnalysisTab.tsx — 522行
  • 提案: 責務ごとに子コンポーネント・カスタムフックへ分割。Container/View パターン(既存の bp-opponent/ で採用済み)に統一
  • 影響範囲: src/components/tabs/
  • 見積: 大(コンポーネントごとに中)

8. React.memo の適用

  • 課題: React.memo を使用しているコンポーネントがわずか2件(PlayerCard, CharacterIcon)。親コンポーネントの状態変化で不要な再レンダリングが発生
  • 提案: 再レンダリングが頻繁なコンポーネント(リストアイテム、チャート、アイコン等)に React.memo を適用。React DevTools Profiler でボトルネックを特定してから対応
  • 影響範囲: src/components/, src/screens/
  • 見積: 小〜中

LOW優先度

9. シーズンフィルタの再有効化

  • 課題: シーズンフィルタ機能が一時無効化され、7つの TODO コメントが散在
    • MatchListToolbar.tsx (3箇所)
    • useMatchListState.ts (2箇所)
    • PlayerDashboardTab.tsx (2箇所)
    • useMatchesData.ts (2箇所)
  • 提案: シーズン判定ロジック(src/constants/seasons.ts)を安定化させ、各箇所の TODO を解消してフィルタを再有効化
  • 前提: シーズンデータの供給方法が確定していること
  • 影響範囲: src/constants/seasons.ts, src/components/tabs/db-viewer/, src/components/tabs/player-dashboard/
  • 見積: 中

10. as any キャストの排除

  • 課題: 以下の箇所で as any を使用
    • src/components/tabs/common/hooks/useProfileManager.ts:62 — プロファイルリストのキャスト
    • src/hooks/useMatchConverter.ts:54,58 — プロパティアクセスのキャスト
    • src/components/tabs/settings/containers/LayoutResetButtons.tsx (6箇所) — #4 で対応
  • 提案: 適切な型ガード・インターフェース定義に置換
  • 影響範囲: 個別ファイル
  • 見積: 小

パフォーマンス計測の自動化アイディア

spec: app-performance-optimization の Task 0.5 / 1.6 / 2.5 など、現状は人手依存の計測項目を yarn perf:all 一発で回せる状態にしたい。下記アイディアの整理メモ。実装は app-performance-optimization の本体タスクとは別に、e2e-automation-tests spec(未着手)と連携して進める想定。

自動化しやすい(数時間〜半日)

  • バンドルサイズ計測: dist/control/manifest.json を読むスクリプト。tasks.md 3.3 に既に積んでいる scripts/perf/check-bundle-size.ts が該当。
  • 冷起動 main.bootstrap: 既存 scripts/perf/measure-startup.tsyarn perf:startup として package.json に登録、yarn build:electron-ts を pre-script に置く。
  • yarn perf:all 一括計測: 上記 2 つ + 結果を perf-baseline.json に上書きする集約スクリプトを書く。レポート 1 回で全部更新できる。

中くらい(1〜2 日)

  • タブ切替 TTI: playwright-core(既に依存にある)で Electron を直接駆動。タブクリック → performance.now() で次フレームの DOM marker までの差分を測る。
  • renderer first paint: renderer 起動直後に src/utils/perf.ts から [perf] control.firstPaint=Nmsconsole.log 出力 → --enable-logging で main の stdout に乗る → measure-startup.ts が拾う。既存の [perf] <label>=<ms> 仕組みをそのまま流用できる。
  • DB 初期化失敗フォールバック: Playwright で userData の DB ファイルを退避 → app 起動 → ダイアログ visible の assert。manual checklist の 1 項目を E2E に昇格できる。
  • chokidar 起動有無: デバッグ用 IPC dev-internal-status を追加(dev のみ expose)→ Playwright で fetch → 期待値と比較。dev only にしてセキュリティ影響を回避。

難しい / 自動化しないほうが良い

  • React Profiler の再レンダ回数の正確な比較: Profiler API は dev only でビルド差で値が変わる。Playwright + <Profiler onRender> のサンプリングで「相対値」までは取れるが、CI で安定的な閾値判定は難しい。dev 開発者が手元で見るだけに留める方針推奨。
  • 「体感の重さ」の主観評価: 人がやるしかない。手動チェックリストは残す。
  • シーン依存(実ログ解析中)の負荷計測: テスト用ログサンプルが必要。整備 → 維持コストが高め。

推奨アプローチ

  1. app-performance-optimization の Task 3.3(bundle-size)と Task 0.3 の package.json script 化から着手。即効性あり、コスト低。
  2. Playwright Electron による cold start + tab TTI 自動化は別 spec e2e-automation-tests の 1st マイルストーンに据える。app-performance-optimization 内では参照のみ。
  3. 再レンダ回数は CI 判定にせず、dev 用の Profiler ラッパーで開発者が見られるだけにする。退化検知は TTI / バンドルサイズで十分なケースが多い。

この方針で進めれば、app-performance-optimization の Task 0.5 / 1.6 / 2.5 を yarn perf:all 1 コマンドで再現可能にできる。

E2E 自動化(e2e-automation-tests)の到達点

spec e2e-automation-tests の Phase 0–3 が完了し、主要フローの手動回帰依存が解消 された。

  • Phase 0: Playwright + Electron 基盤(@playwright/testplaywright.config.tslaunchApp / withTempUserData / dbAccess ヘルパー、ELECTRON_USER_DATA override)
  • Phase 1: 5 シナリオ(startup smoke / log-import / db-viewer / profile-switch / overlay-sync)
  • Phase 2: yarn scripts(test:e2e[:smoke|:headed])と GitHub Actions(PR smoke / nightly full)
  • Phase 3: tests/e2e/README.md、vitest exclude、本ドキュメントへの反映

これにより、リリース前作業は「CI 緑(unit + lint + tsc + e2e:smoke)+ 重点スポット確認」に縮約可能。



カバレッジベースライン(2026-05-05, spec: code-split-and-coverage)

計測コマンド: yarn test:unit --coverage
詳細: coverage-baseline.json

MetricCurrentTarget状態
Lines81.11%70%
Statements79.48%70%
Functions81.26%70%
Branches67.32%60%

全指標でターゲット超過済み。以下のファイルが個別に低カバレッジ:

FileStmtsBranch対処方針
electron/database.ts51.3732.28coverage.exclude に追加(Electron直依存)
electron/services/LogWatcherService.ts54.0237.07coverage.exclude に追加
src/utils/electronAPI/database.ts31.8531.57coverage.exclude に追加
src/utils/electronAPI/window.ts44.8742.30coverage.exclude に追加
src/components/tabs/db-viewer/hooks/useMatchListState.ts54.5432.25Phase 1/3 テスト追加で改善
src/components/tabs/realtime-analysis/hooks/useBrowserAutomation.ts60.4439.36Phase 3 テスト追加で改善
src/store/sync/wsAdapter.ts61.2964.28Phase 1 テスト追加で改善

カバレッジしきい値の固定(2026-05-05, spec: code-split-and-coverage Phase 4)

vitest.config.tscoverage.thresholds を以下にロック:

MetricThresholdAfter excludes
Lines70%86.00%
Statements70%84.64%
Functions70%85.30%
Branches60%71.48%

coverage.exclude に追加した Electron 直依存 / データのみのファイル:

  • electron/database.ts, electron/services/LogWatcherService.ts
  • src/utils/electronAPI/{database,window,index,responseStorage,simulator}.ts
  • src/data/**, src/utils/logAnalyzer/{StreamLogParser,index,types}.ts
  • src/test-helpers/**, src/utils/__mocks__/**

CI: .github/workflows/pr-check.ymlyarn test:ci 実行 + coverage/ artifact を 14 日保持。

メモ

  • 現在のテストカバレッジ閾値: lines/funcs/stmts 70% / branches 60%(vitest.config.ts、2026-05-05 引き上げ)
  • IPC ハンドラのエラーハンドリングは良好(electron/ipc/ 配下は一貫して try/catch を使用)
  • Electron セキュリティ設定は概ね良好(contextBridge 使用、nodeIntegration: falsecontextIsolation: true
  • グローバルな HACK / WORKAROUND コメントは見当たらず、コードベースはクリーン

perf 計測の CI 統合方針(2026-05-05)

app-performance-optimization Task 3.4 で決定。

場所

  • GitHub Actions の独立 job.github/workflows/pr-check.ymlbundle-checks job)に統合する。
  • pre-push フックには載せない。理由: 1 push ごとに yarn build が走ると人間の作業フローが重くなる。CI なら並列 job として動かせる。

段階的ロールアウト

  1. Phase A(現状): bundle-checks job を continue-on-error: true で運用。 失敗しても PR の checks は緑。チェック結果はログで確認できる。 この期間に false positive / 予算過小設定を洗い出す。
  2. Phase B: 1〜2 PR サイクル安定したら continue-on-error を外して required にする。 branch protection rule 側で必須にするのも同タイミング。
  3. Phase C(オプション): bundle size 差分を PR コメントに自動投稿する bot を入れるかは別判断。

何をチェックしているか

  • yarn perf:check-importsscripts/perf/check-renderer-imports.ts): renderer に main 専用依存(playwright-core / electron-updater / better-sqlite3 / chokidar / electron)が import されていないか。
  • yarn perf:check-sizescripts/perf/check-bundle-size.ts): Control 初期ロード(entry + modulepreload + css の合計)が perf-baseline.jsonthresholds.controlMainKb を超えていないか。

予算更新の手順

予算引き上げが必要になったら:

bash
yarn build
npx tsx scripts/perf/check-bundle-size.ts --update --margin 5
git add perf-baseline.json
# PR 説明に「なぜ予算を増やしたか」を必ず書く

背景データ(2026-05-05 時点)

  • controlMainKb: 734.17 KB(5% margin で threshold 770.88 KB)
  • controlTotalKb(lazy 含む全体): 1339.87 KB
  • overlayKb(singlefile): 274.30 KB

データソース連携の整備(spec: data-integration-inventory

ローカルログとブラウザ自動化の差分・照合ロジックの取りこぼし・推奨アクションを 1 ドキュメントに整理した。

上位の推奨アクション(次 spec の素材)

  1. A1: BattleId を log 由来 match にも紐付ける(M / DB 変更) — 短時間連戦・StartTime ずれの両方を緩和
  2. A2: BattleType の数値 → 文字列マッピングを単一ソース化(S)
  3. A3: avatar_url / rank_id / awake_kill_count 等の UI 反映を点検(S〜M)

詳細は inventory の §5 推奨アクションリストを参照。