Route-level code splitting for faster mobile first paint (#106) #113

Merged
steve merged 2 commits from feat/code-splitting into main 2026-07-22 06:18:23 +00:00
2 Commits
Author SHA1 Message Date
steveandClaude Opus 4.8 79df0df53f Address code-split review: chunk-load recovery + tidier lazy + gesture split
Build image / build-and-push (push) Successful in 10s
Gadfly on #106:

- (2 models) React.lazy memoizes a REJECTED import, so after a deploy (every
  main push) a still-open app references chunk hashes the server just
  replaced — the import 404s and RouteError's "Try again" can never recover.
  New lazyPage() helper reloads once on a chunk-load failure to fetch fresh
  hashes (session-flag guarded against a reload loop; cleared on success).
- (perf) @use-gesture is editor-only, but the single vendor chunk pulled it
  into the eager first paint. Exclude it from vendor so it rides with the
  lazy editor chunk (vendor 421→392 KB; the gesture code moved into the
  editor's own chunk). react/react-dom/tanstack still share one vendor chunk
  — splitting react-dom out is what broke React 19 at load.
- (nits) lazyPage also unwraps the named export, so the five route lazies are
  uniform one-liners; moved the lazy block below the import group.

Re-verified live: app mounts, /gardens/1 lazy-loads + renders the editor,
console clean. tsc + build green, no >500 KB warning.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01H3zbym8Doka2d7D48maSgZ
2026-07-22 02:17:55 -04:00
steveandClaude Opus 4.8 99798db8f6 Route-level code splitting for faster mobile first paint (#106)
Build image / build-and-push (push) Successful in 9s
Gadfly review (reusable) / review (pull_request) Successful in 6m18s
Adversarial Review (Gadfly) / review (pull_request) Successful in 6m18s
The whole app shipped in one 578 KB chunk, so a phone on cell data
downloaded and parsed everything — the canvas editor, gestures, geometry,
every page — before the login screen could paint.

- Lazy-load the heavy/deep routes via React.lazy: the editor (its
  GardenCanvas + use-gesture + geometry are the biggest surface), the
  public garden view, plants, settings, register. Login and the gardens
  list stay eager (entry points — no fallback flash on landing). AppShell
  wraps <Outlet> in a Suspense boundary.
- One `vendor` manualChunk for all node_modules so the rarely-changing
  libraries cache across app deploys while the tiny app chunk churns.
  Kept as a SINGLE chunk deliberately: splitting react-dom/scheduler into
  their own chunk reorders module init across chunk boundaries and breaks
  React 19 at load ("Cannot set 'Activity' of undefined") — verified that
  failure and backed it out.

Result: app entry chunk 578 KB → 39 KB; vendor 421 KB (cached); the editor
(43 KB) + canvas (17 KB) only download when you open a garden. No more
>500 KB chunk warning.

Verified live against the embedded binary: /gardens loads with only
index+vendor; opening a garden lazy-fetches the editor chunk and renders;
console clean; the embed serves the hashed split chunks + SPA fallback fine.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01H3zbym8Doka2d7D48maSgZ
2026-07-22 02:07:50 -04:00