- Ya
- 2 Septemba 2026, 09:08 UTC
- Mwandishi
- kamo
- Ahadi ya
- d473a2c
internal.kamocrm.com was serving a 1.34 MB document containing 123 `css-xxxx` class names — `MuiBox-root css-e26q24` among them — and not one rule for any of them. A browser paints that exactly as given, and what it gives is the reported flash: the nav's "Loading…" as an unstyled `<h6>` jammed in the top-left corner, and the eight `MuiSvgIcon` `<svg>` elements beside it at 300x150 apiece, that being the size a replaced element takes when nothing sizes it and MUI icons carry no width or height attribute. Then hydration ran, emotion inserted every rule client-side, and the page snapped into place. The shell has been in the HTML since `perf(ssr): server-render the authenticated app`, and that is worth keeping — it is the difference between a document with 16 KB of real DOM in it and one with almost none. What it also did was make the application depend on something nothing here asserts: that the class names emotion writes into that markup arrive with their rules. Emotion decides that per render, from its own reading of the environment, and there is no way to see from inside the app whether it got it right. Nothing throws, nothing logs, no test that renders a component notices, and the page is correct a few hundred milliseconds later. A rebuild has since produced an image that does emit them, which is the other half of the problem: the behaviour is not ours to depend on. So it is stated instead of assumed. EmotionRegistry renders the tree through a cache in compat mode, collects what that cache inserts, and emits it through `useServerInsertedHTML`, which asks nothing about the environment. Measured against the real app: one `<style>` in `<head>`, 48.5 KB, defining all 58 of the classes the served markup uses, in place of 71 tags scattered down the body — ahead of the markup rather than interleaved with it. Key `css`, which is emotion's default, so no class name anywhere changes; it is also the key the browser-side `createCache` looks for when it adopts a server-rendered `style[data-emotion]` element, which is what stops the client inserting all 58 a second time. Not prepended: order decides nothing here in either direction, since `app/globals.css` and the white-label theme CSS contain no `.Mui` selector at all and `tailwind.config.js` sets `important: true`. `@emotion/cache` was already in the tree as a dependency of `@emotion/react`; this declares it, at the version already resolved, so the lockfile entry does not move and `npm ci` installs exactly what it installed before. Guarded, because the failure is invisible to everything else in the repository. check-emotion-ssr fails if the registry is deleted or if a provider is hoisted above it — which would quietly take that subtree's styles back out of the document — and both failures were confirmed to be caught before the guard was wired into `npm test`. Verified: the emitted stylesheet covers every class in the served markup, with **************** among them; all 13 other guards pass; tsc reports nothing new; vitest is at the same 30 pre-existing failures as origin/main is on this machine (@kamo/* packages behind the lockfile locally).