Skip to content

Prerender the dashboard into index.html - #17

Merged
NimmLor merged 2 commits into
mainfrom
prerender-dashboard
Nov 1, 2026
Merged

NimmLor merged 2 commits into
mainfrom
prerender-dashboard

Conversation

@NimmLor

@NimmLor NimmLor commented Nov 1, 2026

Copy link
Copy Markdown
Owner

index.html shipped an empty <div id="app">, so the page stayed blank until the 675 KB script had loaded and run, and only then laid out the placeholder dashboard from #16. Now the build prerenders that placeholder into index.html and the script hydrates it, so the layout is there on first paint.

How

  • Prerender (web/build.ts, web/src/prerender.tsx): after the page bundle, build.ts bundles prerender.tsx for Bun, calls renderToString(<App />), and writes the result into dist/index.html's #app. Bundling, not importing, gives the icons the same hashed names as the page's bundle.
  • Same render on both sides: the placeholder's runs lead up to a now that #app carries as data-now, the build time. frontend.tsx hydrates with that value, and falls back to createRoot when it's missing, as under dev.ts. Everything that time decides is veiled while pending. LastRun switches to the visitor's clock right after hydration, so real data never reads as of the build.
  • Stored choices (web/src/stored.ts): useStored now uses useSyncExternalStore. Its server snapshot is the fallback, so hydration renders arm64 / 256 MB, then switches to what the visitor stored. It still keeps picks in memory when storage refuses them.
  • No fake figures in search results: the placeholder wrapper gets data-nosnippet, since its made-up numbers are now in the HTML.

Verified

I served dist/ with a delayed /api/runs/history (production's history) in headless Chrome:

  • No console errors or hydration warnings, with and without stored arch/memory/compareWeb.
  • The prerendered <h1> is the same node after hydration.
  • Stored x86_64 / 512 MB apply once the page has hydrated.
  • As a negative control, a tampered data-now raises React's hydration error.

Limits

  • index.html grows from 4 KB to 337 KB (27 KB gzipped).
  • A visitor with a stored arch or size briefly sees the default one under the veil before it switches.

Created with Claude Opus 5.5 in Claude Code.

🤖 Generated with Claude Code

NimmLor and others added 2 commits November 1, 2026 22:20
build.ts renders the placeholder layout with react-dom/server and the
page hydrates it, so the dashboard is there before the 675 KB script
runs. The placeholder is laid out as of the build time, which
index.html carries as data-now, and useStored hydrates from its
fallback before reading storage, so hydration matches.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@NimmLor
NimmLor merged commit c7a88e9 into main Nov 1, 2026
3 checks passed
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.

1 participant