Reputation: 546
I have an issue whereby my client rendered components class names (custom class names created with makeStyles) are of the format jss1234
, however when rendering on the server they are of the format makeStyles-name-1234
. Causing issues when I then hydrate.
I have followed the server side set up here: https://material-ui.com/guides/server-rendering/#handling-the-request pretty much to the letter.
My client entry point looks something like:
const Main = () => {
useEffect(() => {
// clean up any server side generated styles
const jssStyles = document.querySelector('#jss-server-side');
if (jssStyles) {
jssStyles.parentNode.removeChild(jssStyles);
}
}, []);
return (
<ThemeProvider theme={ theme }>
<BrowserRouter>
<App />
</BrowserRouter>
</ThemeProvider>
);
};
ReactDOM.hydrate(<Main />, root);
This is only an issue in production and I have ensured that both my server and client side code have process.env.NODE_ENV === 'production'
.
I don't mind which format my classnames are, as long as they are consistent. I have tried using the StylesProvider and creating a new generateClassName function to force one way or the other, but it just doesn't seem to work. Client is always jss
and server is always makeStyles
prefixed.
Is there any other method of configuring this that I am missing?
thanks, in advance, I will update the question with any more information as I find it.
Update
On closer inspection it looks as though I cannot override the generateClassName function, I pass one in and a function is generated, but its not that one that gets called.
I have the following:
const generateClassName = createGenerateClassName({ disableGlobal: true });
const css = new ServerStyleSheets({ generateClassName });
const markup = ReactDOMServer.renderToString(
css.collect(
<StylesProvider generateClassName={ generateClassName }>
<ThemeProvider theme={ theme }>
...
and in my client:
const generateClassName = createGenerateClassName({ disableGlobal: true });
return (
<StylesProvider generateClassName={ generateClassName }>
<ThemeProvider theme={ theme }>
...
But the disableGlobal never takes effect, it looks as though it never actually uses this function. I must be missing some configuration, however I find the documentation about this stuff a little fragmented and it seems to suggest I wouldn't need to use StylesProvider on the server with the new API.
thanks in advance.
Upvotes: 1
Views: 1621
Reputation: 41
I had the some problem. I follow the exact tutorial in https://material-ui.com/guides/server-rendering/#handling-the-request. The development build works fine, but when running the production build on node, the server side rendering used development class names, causing a class mismatch on hydration.
I solved this by including the NODE_ENV enviroment variable on node bootstrap on production server.
NODE_ENV=production node server.js
Upvotes: 1
Reputation: 546
So as it turns out this was indeed an issue with NODE_ENV.
In my case I was compiling my client code with webpack, but not the external node modules (using webpack nodeExternals). The command to do this was something like:
NODE_ENV=production webpack ... && node server.js
changing these to seperate npm tasks or something like:
NODE_ENV=production webpack ... && NODE_ENV=production node server.js
This solved the issue and I have been able to remove the StylesProvider from my code, as it is not needed with the new MUI v4 API.
Thanks and keep up the good work.
Upvotes: 0