SSR or hydration breaks the page
The server has no window, document, MutationObserver, or real event loop. Browser-only initialization at module top level fails during SSR; placing it in first render can also cause hydration mismatch.
Symptoms
| Symptom | Likely cause |
|---|---|
window is not defined | Browser code runs during module import |
| Hydration mismatch | Server and client render different initial DOM |
| Actions unavailable on first paint | Plugin installs after mount |
| Double registration | Server render and client initialize twice |
| Crash after route change | Singleton reused across requests |
| Leaked listeners | Plugin teardown does not clean up |
Vue / Nuxt
- create
createPling()inside a plugin or afteronMounted; - do not share a module singleton across requests;
- use a
.clientplugin or an explicit client condition; - keep server and client initial markup identical before hydration;
- recreate page declarations on route change, or ensure scope cleanup is correct.
See Nuxt and SSR.
React / Next.js
- use the provider in a client component and check the
"use client"boundary; - never touch browser globals at module top level;
- avoid rendering different DOM on the first render based on
window; - create the runtime in an effect or after client mount;
- do not pass non-serializable instances or functions from server components.
See Next.js and SSR.
Diagnostic order
- Find the first
window/documentaccess in server logs. - Inspect hydration warnings and component boundaries in the browser.
- Disable Pling initialization and confirm base SSR works.
- Move runtime creation into a client lifecycle.
- Check duplicate plugin installation and singleton reuse across requests.
- Test a real production build, not only a dev server.
Security and consistency
An SSR page can return signed-out or placeholder markup first. Do not write protected data into server HTML and then let the client surface assume login. Revalidate identity per request; do not cache request sessions in a global module.
Acceptance
- Server rendering accesses no browser API.
- Hydration emits no structural mismatch warning.
- Actions appear at a documented point after first paint.
- Two concurrent requests do not share user state.
- Route changes and unmount clean up listeners and registrations.
- SSR and client behavior are tested in a production build.
Related
Nuxt and SSR, Next.js and SSR, Projection: Shadow DOM and iframes.

