perf: reduce browsing rerenders and startup cost (#1189)

* chore(profiling): collect serializable react-scan reports

* perf(routing): rerender only when directory winner changes

* perf(zustand): remove shallow warning hot path

* perf(state): narrow directory lifecycle updates

* perf(home): avoid redundant stats render work

* perf(posts): isolate live loading subscriptions

* perf(chrome): skip unchanged shell rerenders

* fix(profiling): drop unsupported render metric

* perf(feeds): skip unchanged loading state renders

* perf(home): stop resolved stats collector renders

* chore(agent run): record rerender verification

* perf(home): defer stats requests until metadata resolves

* perf(startup): load protocol modules on demand

* chore(agent run): record acquisition and startup profiles
This commit is contained in:
Tommaso Casaburi
2026-07-30 00:29:12 +07:00
committed by GitHub
parent 27cc4767c6
commit da03239bb2
33 changed files with 1274 additions and 380 deletions
+4 -2
View File
@@ -17,7 +17,9 @@ You receive from the parent agent:
## How It Works
The app has `react-scan` configured with `report: true` in dev mode (`src/lib/react-scan.ts`). It exposes `window.__getReactScanReport()` which returns per-component render counts and times: `{ ComponentName: { count, time } }`.
`src/lib/react-scan.ts` runs react-scan in dev mode and accumulates render data via its `onRender` option. It exposes `window.__getReactScanReport()`, which returns a plain, JSON-serializable object of per-component render counts and times: `{ ComponentName: { count, time } }`, plus `window.__resetReactScanReport()` to zero it between phases.
Do NOT call react-scan's own `getReport()` — in 0.5.3 it reads a Map that is never written to, and a `Map` stringifies to `"{}"` anyway.
The profiler's `addInitScript` also intercepts `__REACT_DEVTOOLS_GLOBAL_HOOK__` to count React commits independently (works even if react-scan is not loaded).
@@ -163,7 +165,7 @@ Routes profiled: /route1, /route2, ...
- Always use the `-s=SESSION` flag on every playwright-cli command
- Replace `SESSION` and `ROUTE` placeholders with actual values
- **Collect per-route data before navigating to the next route** — goto resets the document
- If `__getReactScanReport` returns null, note "react-scan report unavailable" and rely on commit counts
- If `__getReactScanReport` is undefined or returns `{}`, wait ~1s and retry once (it is a dynamic import); if still empty, note "react-scan report unavailable" and rely on commit counts
- If a route has no content or fails to load, note it in Info and move on
- **Always stop tracing and close the browser when done, even on errors** — wrap your workflow in a try/finally mindset: if any step fails, still run `tracing-stop` and `close`
- Board codes (`biz`, `pol`, `g`, etc.) map to community addresses via the app's directory
+8 -4
View File
@@ -16,10 +16,14 @@ Two-layer profiling: browser-level symptoms (Web Vitals, long tasks, scroll jank
### react-scan (already configured)
The app has `react-scan` set up in `src/lib/react-scan.ts` with `report: true`. In dev mode it:
`src/lib/react-scan.ts` runs react-scan in dev mode. It:
- Highlights rerendering components visually (toolbar + overlay)
- Tracks per-component render counts and times internally
- Exposes `window.__getReactScanReport()` for programmatic collection
- Accumulates per-component render counts and times via react-scan's `onRender` option
- Exposes `window.__getReactScanReport()` and `window.__resetReactScanReport()` for programmatic collection
`__getReactScanReport()` returns a plain object: `{ ComponentName: { count, time } }`.
**Do not use react-scan's own `getReport()`.** It reads `Store.legacyReportData`, which react-scan 0.5.3 never writes to, so it always returns an empty `Map`. The live `Store.reportData` is no better: it is only populated while the toolbar is visible *and* a component is manually focused in the inspector, neither of which holds under automation. The app's `onRender` collector exists precisely because of this. Also note a `Map` cannot be serialized — `JSON.stringify(new Map())` is `"{}"` regardless of contents — which is why the collector returns a plain object.
The profiler's `addInitScript` sets `window.__PROFILING__ = true` before the app loads, which tells react-scan to disable its toolbar and sounds during automated runs.
@@ -160,4 +164,4 @@ playwright-cli -s=prof-3 close 2>/dev/null
- **addInitScript persistence**: Instrumentation re-injects automatically in each new document.
- **Tracing**: Each subagent produces a `trace.zip` viewable in [Trace Viewer](https://trace.playwright.dev).
- **Board codes**: `biz`, `pol`, `g`, `a`, `v`, etc. map to community addresses via the directory.
- **Without react-scan**: If `__getReactScanReport` returns null, the profiler falls back to commit counts + render bursts (still useful, just no component names).
- **Empty react-scan report**: react-scan is a dynamic import, so `__getReactScanReport()` returns `{}` for the first moment after a `goto`. If it is empty, wait ~1s and re-read before falling back to commit counts + render bursts (still useful, just no component names).