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
This commit is contained in:
2026-07-22 02:07:50 -04:00
co-authored by Claude Opus 4.8
parent 11e8e1a544
commit 99798db8f6
3 changed files with 39 additions and 7 deletions
+5 -2
View File
@@ -1,4 +1,4 @@
import { useEffect, useState } from 'react'
import { Suspense, useEffect, useState } from 'react'
import { Link, Outlet, useMatchRoute, useNavigate, useRouterState } from '@tanstack/react-router'
import { Toaster } from '@/components/ui/toast'
import { useLogout, useMe } from '@/lib/auth'
@@ -93,7 +93,10 @@ export function AppShell() {
showBottomNav && 'pb-[calc(3.5rem+env(safe-area-inset-bottom))] md:pb-6',
)}
>
<Outlet />
{/* Boundary for the lazily-loaded routes (see router.tsx). */}
<Suspense fallback={<p className="p-6 text-sm text-muted">Loading</p>}>
<Outlet />
</Suspense>
</main>
{showBottomNav && <BottomNav sections={visibleSections} />}