Skip to content

feat: reduce first-load JS below 200kB on all pages (#893)#896

Merged
sw-factory-automations merged 1 commit intomainfrom
feat/893-reduce-first-load-js
May 4, 2026
Merged

feat: reduce first-load JS below 200kB on all pages (#893)#896
sw-factory-automations merged 1 commit intomainfrom
feat/893-reduce-first-load-js

Conversation

@sw-factory-automations
Copy link
Copy Markdown
Collaborator

Closes #893

What

All 11 application pages now load under the 200kB gzipped first-load JS budget. Previously 7 pages exceeded it, with the worst at 287kB.

How

Three techniques applied in order of impact:

1. Lazy Supabase client in auth forms (~64kB saved per auth page)

Auth forms (sign-in, sign-up, forgot-password, reset-password) and OAuthButtons imported createClient directly from @/lib/supabase/client, which statically bundled the full Supabase SDK (~64kB gzipped including storage, realtime, WebSocket, postgrest). Switched to the existing getClient from @/lib/supabase/lazy-client — the SDK loads on first user interaction instead of at page load.

2. Dynamic import of OAuthButtons (~40kB saved on sign-in/sign-up)

OAuthButtons imports Tooltip from @base-ui/react which pulls in @floating-ui/react-dom. Dynamically importing OAuthButtons via next/dynamic defers these primitives.

3. Client wrappers for workspace pages (37–82kB saved per page)

Server component pages can't use next/dynamic for code splitting. Added thin client wrapper components that dynamically import the heavy page-level components:

  • WorkspaceHomeClient → lazy-loads WorkspaceHome (Select + @floating-ui)
  • MembersPageClient → lazy-loads MembersPage (Select + AlertDialog + Dialog + Tooltip)
  • DangerZoneSettings → lazy-loads DeleteAccountSection (AlertDialog)
  • DeleteWorkspaceSection extracted from WorkspaceSettingsForm and lazy-loaded (AlertDialog)

Results

Page Before After
/sign-up 287 kB 187 kB
/sign-in 287 kB 187 kB
/[ws]/settings/members 265 kB 183 kB
/reset-password 247 kB 188 kB
/forgot-password 247 kB 188 kB
/[ws] 242 kB 181 kB
/[ws]/settings 224 kB 197 kB
/[ws]/[pageId] 186 kB 186 kB
/invite/[token] 179 kB 179 kB
/ 164 kB 164 kB

Testing

  • pnpm lint
  • pnpm typecheck
  • pnpm test — 127 files, 1736 tests passed ✅
  • pnpm test:e2e — 297 passed, 9 failed (all pre-existing failures in unrelated areas: database-csv-export, database-inline, favorites, not-found, trash, version-history, workspace-limit) ✅
  • Auth, workspace-settings, and members E2E tests all pass ✅

- Switch auth forms (sign-in, sign-up, forgot-password, reset-password)
  from direct createClient to lazy getClient, deferring the
  ~64kB gzipped Supabase SDK to first user interaction
- Dynamically import OAuthButtons in sign-in/sign-up forms to keep
  @floating-ui and @base-ui/react tooltip primitives out of initial load
- Extract DeleteWorkspaceSection from WorkspaceSettingsForm and
  lazy-load it, deferring AlertDialog primitives
- Add DangerZoneSettings wrapper to lazy-load DeleteAccountSection
- Add WorkspaceHomeClient and MembersPageClient wrappers to defer
  Select, AlertDialog, Dialog, and Tooltip primitives via next/dynamic

Before → After (gzipped first-load JS):
  /sign-up:                     287kB → 187kB
  /sign-in:                     287kB → 187kB
  /[ws]/settings/members:       265kB → 183kB
  /[ws]:                        242kB → 181kB
  /[ws]/settings:               224kB → 197kB
  /reset-password:              247kB → 188kB
  /forgot-password:             247kB → 188kB

Co-authored-by: Ona <no-reply@ona.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented May 4, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
memo Ready Ready Preview, Comment May 4, 2026 3:21pm

Request Review

@sw-factory-automations sw-factory-automations merged commit 33a6a47 into main May 4, 2026
6 checks passed
@sw-factory-automations sw-factory-automations deleted the feat/893-reduce-first-load-js branch May 4, 2026 15:33
@sw-factory-automations
Copy link
Copy Markdown
Collaborator Author

✅ UI verification passed — design spec compliance confirmed.

Static analysis: All 10 changed UI files reviewed against .agents/design.md. Changes are purely structural (code-splitting wrappers, lazy imports, component extraction). No visual output changes — all Tailwind classes, color tokens, typography, spacing, button variants, and component usage are preserved identically from the original code.

Storybook visual regression: No regressions related to this PR. Two pre-existing issues detected (8 missing baselines for ViewConfigDropdown stories from a different feature, and 1 time-dependent date picker diff showing April→May calendar change).

Live site screenshots (7 routes, desktop dark + mobile):

  • /sign-in — ✅ OAuth buttons render correctly via dynamic import
  • /sign-up — ✅ OAuth buttons render correctly via dynamic import
  • /forgot-password — ✅ Lazy Supabase client, no visual change
  • /{workspace} — ✅ WorkspaceHomeClient wrapper renders identically
  • /{workspace}/settings — ✅ DangerZoneSettings + extracted DeleteWorkspaceSection render correctly
  • /{workspace}/settings/members — ✅ MembersPageClient wrapper renders identically

All pages use correct dark mode tokens, sharp corners, Tailwind spacing scale, proper typography, and responsive mobile layouts.

@sw-factory-automations
Copy link
Copy Markdown
Collaborator Author

✅ Post-merge verification passed.

E2E suite (302 passed, 6 failed — all pre-existing):

  • database-csv-export — pre-existing
  • database-inline — pre-existing
  • favorites — pre-existing
  • trash — pre-existing
  • workspace-limit — pre-existing
  • visual-regression — expected diff (live site vs local baselines)

No new failures introduced by this PR.

Ad-hoc smoke tests — all passed:

  • ✅ Landing page (200, has title)
  • /sign-in (email input present)
  • /api/health (healthy)
  • ✅ Authenticated login flow (redirect to workspace)
  • ✅ Workspace home page (rendered)
  • ✅ Editor page navigation (auth maintained)
  • Skipped: /dashboard (not yet built)

Interaction smoke tests (feature-specific) — all passed:

  • /sign-in — form renders, email/password inputs work, submit button present (lazy Supabase client loads on interaction)
  • /sign-up — form renders, inputs functional
  • /forgot-password — form renders, email input functional
  • /{ws} — workspace home renders via WorkspaceHomeClient dynamic import
  • /{ws}/settings — settings page renders with form elements (lazy DeleteWorkspaceSection)
  • /{ws}/settings/members — members page renders via MembersPageClient dynamic import
  • /{ws}/settings/account — account settings page renders (lazy DeleteAccountSection)
  • No console errors on any tested route

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 pages exceed 200kB first-load JS budget

1 participant