Problem
Two related issues in prodMain (non-SSR branch) in packages/static/src/client/entry.tsx:
-
Inconsistent wrapping. It is the only one of the four mount paths (dev/prod × SSR on/off) that renders without GlobalErrorBoundary and React.StrictMode:
// SSR off: Root shell only, mount App client-side
const browserRoot = <BrowserRoot />;
-
Destructive mount. The App is mounted with createRoot(appMarker.parentElement).render(...). React clears all existing children of the container on the first render call. If a user's Root component renders static siblings around {children} — e.g. <body><Header/>{children}<Footer/></body> — those siblings are silently wiped when the client mounts. This works for the common "children are the sole content of <body>" shape, but the constraint is neither enforced nor documented.
Suggested fix
- Wrap the non-SSR prod mount in
GlobalErrorBoundary (and StrictMode) like the other paths.
- For the container issue: either emit a dedicated wrapper element around the marker at build time and mount into that (so only the marker's own wrapper is ever cleared), or document the constraint clearly in the Root component docs.
Found during a framework audit.
Problem
Two related issues in
prodMain(non-SSR branch) inpackages/static/src/client/entry.tsx:Inconsistent wrapping. It is the only one of the four mount paths (dev/prod × SSR on/off) that renders without
GlobalErrorBoundaryandReact.StrictMode:Destructive mount. The App is mounted with
createRoot(appMarker.parentElement).render(...). React clears all existing children of the container on the firstrendercall. If a user's Root component renders static siblings around{children}— e.g.<body><Header/>{children}<Footer/></body>— those siblings are silently wiped when the client mounts. This works for the common "children are the sole content of<body>" shape, but the constraint is neither enforced nor documented.Suggested fix
GlobalErrorBoundary(andStrictMode) like the other paths.Found during a framework audit.