Skip to content

perf(web): speed up SPA loading and preserve form state on revalidation - #7

Merged
ReaJason merged 3 commits into
masterfrom
perf/frontend-loading
Nov 7, 2026
Merged

ReaJason merged 3 commits into
masterfrom
perf/frontend-loading

Conversation

@ReaJason

@ReaJason ReaJason commented Nov 7, 2026

Copy link
Copy Markdown
Owner

Summary

Cuts first-load cost for the SPA and fixes a form-state bug triggered by loader revalidation.

Frontend performance

  • Self-host Inter (@fontsource-variable/inter) and remove the Google Fonts preconnects/stylesheet from the critical path
  • Remove motion (only used by the data-table action bar) and animate with CSS
  • Code-split the syntax-highlighting CodeViewer into a deferred chunk and extract CopyButton so the HTTP repeater no longer pulls the highlighter
  • Load Monaco lazily, only when an editable file is opened, registering just the editor features and languages the app uses
  • Replace the Recharts memory pies on the shell info page with small SVG donuts (shell-info route payload: 314.55 KiB → 19.74 KiB raw, 93.02 KiB → 5.11 KiB gzip)
  • Poll extension tasks with recursive timeouts so requests never overlap, and back off to 5 s while the tab is hidden
  • Keep file-editor buffers in a ref so typing only re-renders on dirty-state flips
  • Prefetch sidebar and dashboard links on intent
  • Client build output: 8.4 MiB → 8.1 MiB; modules 6162 → 5794

Form state fix

Loaders allocate fresh but equal objects on every revalidation. Effects keyed on object identity therefore reset react-hook-form and wipe in-progress edits after any fetcher action - for example clicking Test Connection on /shells/create.

The new useSeedSync hook compares serialized seed values, so only genuine record changes sync. It is applied to the shell, profile, project, plugin, role, and user forms, plus the extension plugin selection. Connection tests also skip revalidation entirely.

Server

  • /assets/** served with Cache-Control: public, max-age=31536000, immutable
  • SPA HTML keeps no-cache so deployments roll over immediately
  • gzip response compression for payloads of 2 KB or more
  • Integration test covering both cache-header behaviors

Test plan

  • bun run fmt && bun run fmt:check
  • bun run typecheck
  • bun run lint
  • bun run test:run - 30 files / 82 tests
  • bun run build
  • ./gradlew :noone-server:build
  • Manual: fill /shells/create, click Test Connection - input preserved
  • Manual: user, role, project, and profile edit pages render with seeded values

- Self-host Inter via @fontsource-variable and drop Google Fonts links
- Remove motion; use a CSS animation for the data-table action bar
- Split CodeViewer (syntax highlighting) into a lazy chunk and extract
  CopyButton so the HTTP repeater no longer pulls the highlighter
- Load Monaco only when an editable file is opened, using trimmed
  language/feature registration instead of the full editor package
- Replace Recharts memory pies with lightweight SVG donuts
- Poll extension tasks with recursive timeouts, avoiding overlapping
  requests and backing off while the tab is hidden
- Keep file buffers in a ref so typing does not re-render the manager
- Prefetch sidebar and dashboard links on intent
Loaders allocate fresh objects on every revalidation, so effects keyed on
object identity reset forms and wiped in-progress edits whenever a fetcher
action ran (for example "Test Connection" on the create-shell page).

Compare serialized seed values instead with the new useSeedSync hook, and
let the shell create/edit route skip revalidation for connection tests.
Apply the same fix to the profile, project, plugin, role, and user forms
and to the extension plugin selection.
- Serve /assets/** with public, immutable, one-year caching and keep the
  SPA HTML revalidating so new deployments roll over immediately
- Enable gzip response compression for payloads of 2 KB or more
- Cover both cache headers with an integration test
@vercel

vercel Bot commented Nov 7, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated
no-one Ready Ready Preview Nov 7, 2026 12:17am UTC

@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 53.02%. Comparing base (8d20920) to head (22ee300).
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@             Coverage Diff              @@
##             master       #7      +/-   ##
============================================
+ Coverage     52.95%   53.02%   +0.07%     
  Complexity      554      554              
============================================
  Files           109      109              
  Lines          3165     3170       +5     
  Branches        397      397              
============================================
+ Hits           1676     1681       +5     
  Misses         1241     1241              
  Partials        248      248              
Flag Coverage Δ
noone-server 53.02% <100.00%> (+0.07%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ReaJason
ReaJason merged commit 4e6b7a2 into master Nov 7, 2026
5 checks passed

This branch was successfully deployed

1 active deployment
Preview — 22ee3002 Deployed Nov 7, 2026 by vercel[bot]
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.

2 participants