SSR + CSS Class Names Duplicated? August 17, 2019
Posted by kevinbe71 in Development, React, TypeScript, Uncategorized, Web Development.Tags: css modules, React, ssr, storybook, theming, TypeScript
add a comment
Over the last couple of weeks I’ve been messing around with a new React-based project: trying to get Storybook + Theming + React + SSR + TypeScript all playing nicely together.
I first started with NextJS and tried to get Styled Components working with it and Storybook. After running into too many problems I abandoned NextJS. The final straw being Styled Components type definitions that weren’t working well and I had to revert back to a pretty old version of the type defs which wasn’t acceptable.
Next I started looking for some kind of starter project (I decided that it was better if I had full control and not leave too much to behind-the-scenes “magic”). I found a good one and started tweaking it to my needs. I thought everything was working nicely- Storybook worked with theming and I started moving the “test” components into the main app (with SSR). This is where the title of the blog post comes into play…
Although the component styling had worked flawlessly in Storybook I started to see issues when it was running through SSR: the app would initially render well and then, within a split second, it would mess up the styling. When I inspected the DOM I saw that a class name that was meant to be applied to only one element was being applied to both the parent and child div.
I started to blame CSS Modules because I hadn’t used them enough to know what could/could not be done with them. However, it wasn’t CSS Modules that were the problem, because I could tell that it was rendering correctly and then being “corrupted” somehow. At first I didn’t recognize it as that and suspected that it was just either the SSR version of the app or the client-side version that was rendering incorrectly. I disabled SSR and it worked perfectly: so it must be the SSR configuration, right? Wrong.
Ultimately it turned out to be a mismatch in the index.tsx on the “client” side and the serverRenderer.tsx. I had inadvertently added an extra “level” to my router config! I added a MainLayout component to one of these files but not the other. So, in essence the server was rendering one hierarchy (missing MainLayout) while the client was rendering a different one. React tries to reconcile the differences and it seems that it doesn’t know how to clean up the CSS class names properly so that results in duplication of class names on the wrong nodes! It seems that the virtual DOM doesn’t always get it right.