fix(useWindowDimensions): guard window access for SSR / static prerender#1569
Conversation
getWindowDimensions() read window.innerWidth/innerHeight unguarded and is invoked eagerly via useState(getWindowDimensions()) on the initial render. Under server-side rendering or Next.js static-export prerender there is no window, so any component calling useWindowDimensions() (e.g. a navbar) threw ReferenceError: window is not defined during prerender. Return zeroed dimensions when window is undefined; the real values are read on the client during hydration and updated by the existing resize listener. Adds a node-environment regression test asserting renderToString does not throw and falls back to 0x0 when window is absent. Signed-off-by: miacycle <184569369+miacycle@users.noreply.github.com>
There was a problem hiding this comment.
Code Review
This pull request introduces SSR safety to the getWindowDimensions utility and adds a corresponding test suite to verify behavior in non-browser environments. A high-severity issue was identified regarding a hydration mismatch, as the initial client-side state will differ from the server-rendered output. The reviewer recommends initializing the state to zero and using an effect to capture actual dimensions after mounting to ensure hydration consistency and align the implementation with the provided documentation.
There was a problem hiding this comment.
Pull request overview
Fixes useWindowDimensions() so it can be safely used during SSR / Next.js static-export prerender without crashing the render pipeline, by guarding access to window and adding a regression test to prevent reintroducing the issue.
Changes:
- Guarded
getWindowDimensions()to return{ width: 0, height: 0 }whenwindowis unavailable (SSR/prerender). - Added a Jest
node-environment SSR regression test usingrenderToStringto assert no throw and verify the fallback behavior.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/custom/Helpers/Dimension/windowSize.tsx |
Adds an SSR-safe window guard in getWindowDimensions() and updates the doc comment. |
src/__testing__/useWindowDimensions.test.tsx |
Adds SSR regression coverage in a node Jest environment using react-dom/server. |
Addresses review feedback: initializing state via useState(getWindowDimensions()) read window during render, which (a) diverged from the server's 0x0 render and caused a hydration mismatch for SSR'd consumers, and (b) made the docstring's 'first effect-driven read' claim inaccurate (the effect only added a resize listener, never an initial read). Initialize state to 0x0 so the server render and first client (hydration) render are identical, then sync to the real dimensions in the mount effect and keep them current via the debounced resize listener. getWindowDimensions is now only called on the client; its window guard remains as a defensive net. Splits tests: SSR safety (node env, renderToString does not read window, falls back to 0x0) and client behavior (jsdom renderHook: reads real dimensions on mount, updates on debounced resize). Signed-off-by: miacycle <184569369+miacycle@users.noreply.github.com>
Description
getWindowDimensions()readswindow.innerWidth/innerHeightunguarded and is invoked eagerly viauseState(getWindowDimensions())on the initial render. Under server-side rendering or Next.js static-export prerender there is nowindow, so any component that callsuseWindowDimensions()(e.g. a navbar) throws:during prerender. This blocked
make ui-build(Next.jsoutput: "export") inmeshery-cloud, whereNavBarcallsuseWindowDimensions()and renders during static export.Fix
Return zeroed dimensions when
windowis undefined. The real values are read on the client during hydration (theuseStateinitializer runs again client-side) and kept current by the existingresizelistener. No behavior change in the browser.Tests
Adds a
node-environment regression test (src/__testing__/useWindowDimensions.test.tsx) assertingrenderToStringdoes not throw and falls back to0x0whenwindowis absent, plus a positive case withwindowpresent.npx jest src/__testing__/useWindowDimensions.test.tsx— 2 passednpm run build— success (CJS/ESM/DTS)Downstream
meshery-cloudconsumes published sistent (^0.21.13) and has an interim consumer-side mitigation (wrappingNavBarinNoSsr). This PR is the root-cause fix; once released it can replace the need for SSR guards at every call site.