fix(frontend): render client-side (ssr=false) to close pre-hydration interaction races
EventSnap is a client-only SPA: auth is a localStorage JWT and every page fetches its data in onMount, so SSR only ever produced a logged-out skeleton — including interactive controls that exist in the DOM before hydration attaches their handlers. Interacting in that window silently no-ops: a caption typed on /upload never reaches the reactive state (so cancel() navigates away instead of confirming), and a click on /account's custom role=radio / leave button does nothing. This surfaced as a ~1-4% mobile e2e flake and is a real (if brief) bug for users on slow connections too. Disable SSR app-wide (csr stays on). The server now ships a ~2.5 KB shell with no page controls, so the pre-hydration window is structurally impossible. No SEO is lost (private, QR-gated app). app.html paints a themed boot spinner to cover the JS-load gap (script-free; inline <style> is CSP-safe via style-src 'unsafe-inline'); the root layout's onMount removes it once the app paints. Also fixes the one regression ssr=false exposed: /recover's back chevron used `cameFromApp = from !== null`, which assumes SSR semantics (cold load => from is null). In CSR mode the initial navigation reports a non-null `from`, sending history.back() to about:blank. Key on `type !== 'enter'` instead — SvelteKit's initial-load marker in both SSR and CSR modes. Verified: desktop 210 passed, mobile 22 passed, back-chevron 10/10, frontend gates green (svelte-check 0 errors, eslint, prettier, vitest 46). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -30,6 +30,9 @@
|
||||
});
|
||||
|
||||
onMount(async () => {
|
||||
// With `ssr = false` the server ships an empty shell; `app.html` paints a boot
|
||||
// spinner to cover the JS-load gap. The app has now mounted and painted, so drop it.
|
||||
document.getElementById('app-boot')?.remove();
|
||||
initAuth();
|
||||
// Hooks up the appliedTheme → <html class="dark"> sync. Must run early so the
|
||||
// first paint after hydration matches the saved preference.
|
||||
|
||||
Reference in New Issue
Block a user