改善計画書
最終更新: 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 と達成状況
| 指標 | Before | After | 変化 | 判定 |
|---|---|---|---|---|
mainBootstrapMs(critical path) | 978.59 ms | 270.54 ms(dev 計測, trial 3) | -72.4% | ✅ 目標 -30% 達成 |
controlFirstPaintMs | 75.9 ms | 取得継続中 | — | △ dev 計測の安定化が今後の課題 |
controlMainKb(initial load) | 1339.61 KB | 734.17 KB | -45.2% | ✅ 目標 -20% 達成 |
controlTotalKb | 1339.61 KB | 1339.87 KB | ±0% | — lazy 化で初期パスから外したのみ |
overlayKb | 274.30 KB | 274.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:all1 コマンドで再現可能。 - 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を外しmanualChunksでreact-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-checksjob に統合(当面continue-on-error: true)。
- 3.1: Control の
- 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-checksjob:yarn build→perf:bundle→perf:check-imports→perf: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サイクル進捗
| # | 項目 | ステータス |
|---|---|---|
| 16 | useOverlayStore 分割 (617行) | 未着手 |
| 17 | Overlay.tsx 分割 (466行) | 未着手 |
| 18 | RealtimeAnalysisPanel 分割 (390行) | 未着手 |
| 19 | LogAnalysisTab 分割 (378行) | 未着手 |
| 20 | テストカバレッジ閾値の引き上げ (60→70%) | 未着手 |
第2サイクル進捗
| # | 項目 | ステータス |
|---|---|---|
| 11 | 各タブの個別 ErrorBoundary ラップ | ✅ 完了 (06ef350) |
| 12 | console.log → Logger 置換 | ✅ 完了 — store/hooks (2ae87f7) |
| 13 | SeasonAnalyticsPanelView 分割 (562→292行) | ✅ 完了 (10f4ddd) |
| 14 | SettingsSubTabs 分割 (458→212行) | ✅ 完了 (10f4ddd) |
| 15 | DB row の as any 型キャスト排除 | ✅ 完了 (10f4ddd) |
進捗
| # | 項目 | ステータス |
|---|---|---|
| 1 | Error Boundary の導入 | ✅ 完了 (fcd2ad9) |
| 2 | グローバルエラーハンドラの追加 | ✅ 完了 (fcd2ad9) |
| 3 | IPCチャネルのホワイトリスト化 | ✅ 完了 (fcd2ad9) |
| 4 | electronAPI ラッパーへの統一 | ✅ 完了 — BP Window/ResponseStorage/RuntimeStatusも移行済み |
| 5 | Electron サービスのテスト追加 | ✅ 完了 (9b6b3b0) — UserSettings/ResponseStorage テスト追加 |
| 6 | ウィンドウマネージャ・大型コンポーネントのテスト追加 | ✅ 完了 — フックテスト6件 + WindowStateStoreテスト追加 |
| 7 | 大型コンポーネントの分割 | ✅ 完了 — 全6コンポーネント分割(BrowserAutomationTab/ControlPanel/SeasonAnalyticsPanel/LogAnalysisTab/CharacterMatchupsSectionView/RealtimeAnalysisTab) |
| 8 | React.memo の適用 | ✅ 完了 (8f930d0) — 6コンポーネントに適用 |
| 9 | シーズンフィルタの再有効化 | ✅ 完了 (a82a829) — 7箇所のTODO解消 |
| 10 | as 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.tsのon()メソッドが任意のチャネル文字列を受け付ける。レンダラ側で不正なチャネルのリッスンが可能 - 提案: 許可されるチャネル名のホワイトリストを定義し、
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.tsBrowserAutomationService.tsResponseStorageService.tsUserSettingsService.ts
- 現状テストあり:
LogWatcherService.test.tsのみ - 提案: 各サービスの責務に応じたユニットテストを追加。既存のテストパターン(
electron/database/,electron/ipc/)に準拠 - 影響範囲:
electron/services/ - 見積: 中〜大
6. ウィンドウマネージャ・大型コンポーネントのテスト追加
- 課題:
- 4つのウィンドウマネージャがすべてテストなし(
ControlWindowManager,OverlayWindowManager,BPOpponentWindow, 予定のウィンドウ) BrowserAutomationTab.tsx(986行)がテストなし
- 4つのウィンドウマネージャがすべてテストなし(
- 提案: 重要度の高いものからテストを追加。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.md3.3 に既に積んでいるscripts/perf/check-bundle-size.tsが該当。 - 冷起動
main.bootstrap: 既存scripts/perf/measure-startup.tsをyarn 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=Nmsをconsole.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 開発者が手元で見るだけに留める方針推奨。 - 「体感の重さ」の主観評価: 人がやるしかない。手動チェックリストは残す。
- シーン依存(実ログ解析中)の負荷計測: テスト用ログサンプルが必要。整備 → 維持コストが高め。
推奨アプローチ
app-performance-optimizationの Task 3.3(bundle-size)と Task 0.3 のpackage.jsonscript 化から着手。即効性あり、コスト低。- Playwright Electron による cold start + tab TTI 自動化は別 spec
e2e-automation-testsの 1st マイルストーンに据える。app-performance-optimization内では参照のみ。 - 再レンダ回数は 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/test、playwright.config.ts、launchApp/withTempUserData/dbAccessヘルパー、ELECTRON_USER_DATAoverride) - 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
| Metric | Current | Target | 状態 |
|---|---|---|---|
| Lines | 81.11% | 70% | ✅ |
| Statements | 79.48% | 70% | ✅ |
| Functions | 81.26% | 70% | ✅ |
| Branches | 67.32% | 60% | ✅ |
全指標でターゲット超過済み。以下のファイルが個別に低カバレッジ:
| File | Stmts | Branch | 対処方針 |
|---|---|---|---|
electron/database.ts | 51.37 | 32.28 | coverage.exclude に追加(Electron直依存) |
electron/services/LogWatcherService.ts | 54.02 | 37.07 | coverage.exclude に追加 |
src/utils/electronAPI/database.ts | 31.85 | 31.57 | coverage.exclude に追加 |
src/utils/electronAPI/window.ts | 44.87 | 42.30 | coverage.exclude に追加 |
src/components/tabs/db-viewer/hooks/useMatchListState.ts | 54.54 | 32.25 | Phase 1/3 テスト追加で改善 |
src/components/tabs/realtime-analysis/hooks/useBrowserAutomation.ts | 60.44 | 39.36 | Phase 3 テスト追加で改善 |
src/store/sync/wsAdapter.ts | 61.29 | 64.28 | Phase 1 テスト追加で改善 |
カバレッジしきい値の固定(2026-05-05, spec: code-split-and-coverage Phase 4)
vitest.config.ts の coverage.thresholds を以下にロック:
| Metric | Threshold | After excludes |
|---|---|---|
| Lines | 70% | 86.00% |
| Statements | 70% | 84.64% |
| Functions | 70% | 85.30% |
| Branches | 60% | 71.48% |
coverage.exclude に追加した Electron 直依存 / データのみのファイル:
electron/database.ts,electron/services/LogWatcherService.tssrc/utils/electronAPI/{database,window,index,responseStorage,simulator}.tssrc/data/**,src/utils/logAnalyzer/{StreamLogParser,index,types}.tssrc/test-helpers/**,src/utils/__mocks__/**
CI: .github/workflows/pr-check.yml で yarn 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: false、contextIsolation: true) - グローバルな HACK / WORKAROUND コメントは見当たらず、コードベースはクリーン
perf 計測の CI 統合方針(2026-05-05)
app-performance-optimization Task 3.4 で決定。
場所
- GitHub Actions の独立 job(
.github/workflows/pr-check.ymlのbundle-checksjob)に統合する。 pre-pushフックには載せない。理由: 1 push ごとにyarn buildが走ると人間の作業フローが重くなる。CI なら並列 job として動かせる。
段階的ロールアウト
- Phase A(現状):
bundle-checksjob をcontinue-on-error: trueで運用。 失敗しても PR の checks は緑。チェック結果はログで確認できる。 この期間に false positive / 予算過小設定を洗い出す。 - Phase B: 1〜2 PR サイクル安定したら
continue-on-errorを外して required にする。 branch protection rule 側で必須にするのも同タイミング。 - Phase C(オプション): bundle size 差分を PR コメントに自動投稿する bot を入れるかは別判断。
何をチェックしているか
yarn perf:check-imports(scripts/perf/check-renderer-imports.ts): renderer に main 専用依存(playwright-core/electron-updater/better-sqlite3/chokidar/electron)が import されていないか。yarn perf:check-size(scripts/perf/check-bundle-size.ts): Control 初期ロード(entry + modulepreload + css の合計)がperf-baseline.jsonのthresholds.controlMainKbを超えていないか。
予算更新の手順
予算引き上げが必要になったら:
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 KBoverlayKb(singlefile): 274.30 KB
データソース連携の整備(spec: data-integration-inventory)
ローカルログとブラウザ自動化の差分・照合ロジックの取りこぼし・推奨アクションを 1 ドキュメントに整理した。
上位の推奨アクション(次 spec の素材)
- A1: BattleId を log 由来 match にも紐付ける(M / DB 変更) — 短時間連戦・StartTime ずれの両方を緩和
- A2: BattleType の数値 → 文字列マッピングを単一ソース化(S)
- A3: avatar_url / rank_id / awake_kill_count 等の UI 反映を点検(S〜M)
詳細は inventory の §5 推奨アクションリストを参照。