Skip to content

Commit cc93caf

Browse files
authored
perf: fix startup and route loading (#49)
1 parent 9689594 commit cc93caf

49 files changed

Lines changed: 756 additions & 407 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ Browser or Capacitor shell
9191

9292
Important boundaries:
9393

94-
- [`src/main.tsx`](src/main.tsx) starts the client, observability, native runtime, service worker, and offline preloading.
94+
- [`src/main.tsx`](src/main.tsx) starts the client, deferred telemetry, native runtime, and service worker.
9595
- [`src/App.tsx`](src/App.tsx) defines public and authenticated routes.
9696
- [`src/lib/supabase/client.ts`](src/lib/supabase/client.ts) creates the environment-specific Supabase client.
9797
- [`src/lib/stores/`](src/lib/stores/) owns persisted client state and server hydration.

‎docs/architecture.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Browser or Capacitor
1515

1616
## Client startup and routing
1717

18-
[`src/main.tsx`](../src/main.tsx) mounts the application and starts native runtime handling, observability, native URL handling, service-worker registration, and offline route preloading. Vercel browser telemetry is disabled inside the native shell.
18+
[`src/bootstrap.ts`](../src/bootstrap.ts) imports the application entry immediately, then schedules Jam after window load and idle time. [`src/main.tsx`](../src/main.tsx) mounts the application before starting native runtime handling, observability, native URL handling, and service-worker registration. Vercel browser telemetry is disabled inside the native shell and loaded behind a separate Suspense boundary.
1919

2020
[`src/App.tsx`](../src/App.tsx) owns routes and top-level providers. Pages are lazy loaded. Public routes cover marketing, legal pages, login, sources, and shared content. `/app/*` routes pass through `RequireAuth` and include the main tools, history, library, timer, sparring, flowchart, settings, and administration.
2121

@@ -89,13 +89,13 @@ Historical provider pricing evidence is retained under [`docs/pricing-snapshots/
8989

9090
## Observability
9191

92-
Client startup initializes Sentry and PostHog when configured. Product events and exceptions use [`src/lib/observability.ts`](../src/lib/observability.ts). Vercel Analytics and Speed Insights run only in the web build.
92+
Client startup loads Sentry and PostHog asynchronously when configured. Product events and exceptions use the privacy-filtering facade in [`src/lib/observability.ts`](../src/lib/observability.ts), so SDK loading or failure cannot block rendering. Vercel Analytics and Speed Insights run only in the web build and load outside the application render boundary.
9393

9494
CI and staging must not upload authenticated browser captures. Logging must not expose tokens, provider keys, user content, or protected staging values.
9595

9696
## PWA and offline behavior
9797

98-
The service worker and manifest provide installable web assets and an offline app shell. Client startup registers the service worker and preloads route chunks. Offline support does not make authenticated Supabase or AI operations available without a network.
98+
The service worker and manifest provide installable web assets and an offline app shell. It precaches only the navigation shell and static identity assets; route chunks enter the runtime cache when a user visits them. Updates wait for the normal service-worker lifecycle instead of reloading an active page. Offline support does not make unvisited routes, authenticated Supabase, or AI operations available without a network.
9999

100100
## iOS shell
101101

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Startup and navigation performance evidence
2+
3+
Measured from production Vite builds at `origin/main` commit `99c2b53` and this branch. Each cold run used a new Chromium context with the HTTP cache disabled. "First real app paint" is the first animation frame containing the route's real React marker, not the branded HTML boot shell. Idle totals were sampled two seconds later so the old route stampede is included.
4+
5+
## Results
6+
7+
- Desktop `/` first real app paint: **769 ms before, 464 ms after** (`-39.7%`).
8+
- Mobile `/` first real app paint: **1,042 ms before, 393 ms after** (`-62.3%`).
9+
- Desktop `/` after-idle requests: **103 before, 34 after** (`-67.0%`).
10+
- Desktop `/` transferred bytes: **1,113,865 before, 711,360 after** (`-36.1%`).
11+
- Desktop `/` decoded bytes: **3,665,094 before, 2,035,497 after** (`-44.5%`).
12+
- Critical landing-route JavaScript gzip: **803,351 bytes before, 403,438 after** (`-49.8%`). The before graph includes the incorrectly preloaded PDF vendor and forced chart/ReactFlow vendor chunks.
13+
- Throttled desktop `/` first real app paint, 150 ms RTT and 1.6 Mbps down: **8,381 ms before, 4,904 ms after** (`-41.5%`).
14+
- Jam stalled indefinitely, desktop `/`: **3,582 ms before, 373 ms after** (`-89.6%`).
15+
- Jam stalled indefinitely, mobile `/`: **3,530 ms before, 485 ms after** (`-86.3%`).
16+
- Warm Generate to Attack navigation: **421 ms before, 157 ms after** on desktop (`-62.7%`); **1,314 ms before, 1,067 ms after** on the Pixel 5 profile (`-18.8%`). The shell remained visible for the full after run.
17+
18+
The SEO-directory sentence was observed on the first painted frames of every before run. It was observed on none of the after runs. After-idle request totals also fell from 104 to 32 on `/login`, from 105 to 57 on `/app/generate`, and from 105 to 55 on `/app/attack`.
19+
20+
The emitted manifest check walks the static graphs for `/`, `/login`, `/app`, `/app/generate`, and `/app/attack`. None contains PDF, DOCX, chart, ReactFlow, export, or Admin modules. Those modules remain available through dynamic imports when the matching feature is used.
21+
22+
## Filmstrips
23+
24+
Before, desktop:
25+
26+
![Before desktop filmstrip](before-desktop-filmstrip.png)
27+
28+
After, desktop:
29+
30+
![After desktop filmstrip](after-desktop-filmstrip.png)
31+
32+
Before, mobile:
33+
34+
![Before mobile filmstrip](before-mobile-filmstrip.png)
35+
36+
After, mobile:
37+
38+
![After mobile filmstrip](after-mobile-filmstrip.png)
39+
40+
## Videos
41+
42+
- [Before desktop](before-desktop.webm)
43+
- [After desktop](after-desktop.webm)
44+
- [Before mobile](before-mobile.webm)
45+
- [After mobile](after-mobile.webm)
46+
47+
The full Performance Timing and resource waterfalls were captured as JSON, and screenshot-enabled Playwright traces were retained locally for both throttled cold loads. The committed filmstrips and videos avoid trace archives that contain source snapshots.
130 KB
Loading
Binary file not shown.
160 KB
Loading
Binary file not shown.
149 KB
Loading
Binary file not shown.
334 KB
Loading

0 commit comments

Comments
 (0)