material-ui icon indicating copy to clipboard operation
material-ui copied to clipboard

Next.js + Material UI v5 styled-component example is still showing className mismatch error

Open daveteu opened this issue 3 years ago • 50 comments

  • [ x] The issue is present in the latest release.
  • [ x] I have searched the issues of this repository and believe that this is not a duplicate.

Current Behavior 😯

I've followed the example for nextjs styled-components.

The example works out of the box.

However, once you create a styled-component, the className did not match from server side rendering error will occur.

https://github.com/mui-org/material-ui/tree/75f27074b89381d25a1fab85fc2098af58e89cb0/examples/nextjs-with-styled-components-typescript

Prop className did not match. Server: "sc-dlnjwi fBCjsW MuiBox-root" Client: "sc-gtsrHT kMdZqK MuiBox-root"

Expected Behavior 🤔

The example should work like it should.

Steps to Reproduce 🕹

I've forked the example ( from above ) with code sandbox.

What I did was to create a simple styled component on index.js (I'm not proficient with ts) and the error will show.

  1. Fork https://github.com/mui-org/material-ui/tree/75f27074b89381d25a1fab85fc2098af58e89cb0/examples/nextjs-with-styled-components-typescript
  2. Create a simple styled component
  3. Restart server (if you are using codesandbox).
  4. See console for error.

I've done the above in a sandbox - https://codesandbox.io/s/jolly-yonath-kjxj2?file=/pages/index.js

Context 🔦

I'm using NextJS but I'm not sure how to modify your example to work with Material-ui v5. I think this is the toughest part using NextJS + Material-UI and a solution is necessary.

Your Environment 🌎

`Material-UI` "@material-ui/core": "^5.0.0-beta.2", "@material-ui/icons": "^5.0.0-beta.1", "@material-ui/lab": "^5.0.0-alpha.41", "@material-ui/styled-engine-sc": "^5.0.0-beta.1", "@material-ui/styles": "^5.0.0-beta.2",
`NEXT.JS` "next-transpile-modules": "^8.0.0", "next": "^11.0.1",
`npx @material-ui/envinfo`
System:
    OS: macOS 11.4
  Binaries:
    Node: 16.5.0 - ~/.nvm/versions/node/v16.5.0/bin/node
    Yarn: Not Found
    npm: 7.19.1 - ~/.nvm/versions/node/v16.5.0/bin/npm
  Browsers:
    Chrome: 92.0.4515.107
    Edge: Not Found
    Firefox: Not Found
    Safari: 14.1.1

daveteu avatar Jul 29 '21 15:07 daveteu

Agree, I don't think that we can expect developers to use the current version of the example. Personally, I wouldn't as it not really working.

~https://github.com/mui-org/material-ui/pull/27088#issuecomment-885278495 is a working solution.~

As to why the current solution doesn't work? I don't know. It would be great to have a deep dive. So far, it seems that styled-components was not designed for SSR.

oliviertassinari avatar Jul 29 '21 19:07 oliviertassinari

Thanks @oliviertassinari

I've tried your linked solution. I've removed the webpack config for alias, and updated package.json with "@material-ui/styled-engine": "npm:@material-ui/styled-engine-sc@next"

It seems to have removed the className mismatch error.

However, for your information. I cannot remove the next-transpile-modules ( per your example ) in my projects.

Since MUI v5, I've been experiencing the following error if I don't use the next-transpile-modules. It says export is undefined.

I haven't tested enough to know whether I'm the only one needing the transpile, or whether it's really Mui related.

index.js?20a9:42 Uncaught     at /Users/myname/Work/React/myproject/node_modules/ (material-ui/core/colors/grey.js:17)
    at Object.compileFunction (node:vm:352:18)
    at wrapSafe (node:internal/modules/cjs/loader:1025:15)
    at Module._compile (node:internal/modules/cjs/loader:1059:27)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1124:10)
    at Module.load (node:internal/modules/cjs/loader:975:32)
    at Function.Module._load (node:internal/modules/cjs/loader:816:12)
    at Module.require (node:internal/modules/cjs/loader:999:19)
    at require (node:internal/modules/cjs/helpers:93:18)
    at Object.@material-ui/core/colors/grey (file:///Users/myname/Work/React/myproject/.next/server/pages/component.js:515:18)
    at __webpack_require__ (file:///Users/myname/Work/React/myproject/.next/server/webpack-runtime.js:33:42)

daveteu avatar Jul 30 '21 12:07 daveteu

@daveteu Do you have a reproduction?

oliviertassinari avatar Jul 30 '21 12:07 oliviertassinari

I am reopening as I needed to revert https://github.com/mui-org/material-ui/pull/27583 as it does not work with npm. We'll come back to this later.

For those using yarn https://github.com/mui-org/material-ui/pull/27583 should work and fix the class name mismatch error.

mnajdova avatar Aug 23 '21 13:08 mnajdova

I also faced this issue recently with Next Js version 11.1.2 for some components.

But I was able to overcome the issue using the dynamic imports used by Next Js with ssr:false

Material UI version

"@material-ui/core": "5.0.0-beta.4", "@material-ui/icons": "5.0.0-beta.4", "@material-ui/lab": "5.0.0-alpha.43", "@material-ui/styles": "5.0.0-beta.4",

Styled Component version

"styled-components": "^5.3.1"

npx @material-ui/envinfo

System: OS: macOS 11.5.2 Binaries: Node: 14.17.0 - /usr/local/bin/node Yarn: 1.22.11 - /usr/local/bin/yarn npm: 7.20.1 - /usr/local/bin/npm Browsers: Chrome: 92.0.4515.159 Edge: Not Found Firefox: 90.0.2 Safari: 14.1.2

ankurmaheshsingh avatar Aug 31 '21 19:08 ankurmaheshsingh

As i mentioned in closed issue above, in a builded app these errors does not exists, but i faced some components rendering issues, like Tabs.

In development environmnent the application crashes in every refresh, throwing this warning, the unique workarround that i found is using next/dynamic in every MUI component with SSR set to false, but, with this we loss the server side goods.

import dynamic from 'next/dynamic'

const Grid = dynamic(() => import('@mui/material/Grid'), { ssr: false })

truediogo avatar Sep 16 '21 11:09 truediogo

For me on npm: '7.21.0' just putting this in package.json worked in dev and prod without any errors:

"dependencies": {
    "@mui/material": "^5.0.0",
    "@mui/icons-material": "^5.0.0",
    "@mui/lab": "^5.0.0-alpha.47",
    "@mui/styled-engine-sc": "^5.0.0",
    "@mui/styles": "^5.0.0",
    ...,
    "next": "^11.1.2",
    ...
    "styled-components": "^5.3.1",
},
"alias": {
    "@mui/styled-engine": "@mui/styled-engine-sc"
},

(and also having usual collectStyles in the _document and like 3 providers in the _app)

I'm styling with import styled from "styled-components";.

MonstraG avatar Sep 17 '21 11:09 MonstraG

For me on npm: '7.21.0' just putting this in package.json worked in dev and prod without any errors:

"dependencies": {
    "@mui/material": "^5.0.0",
    "@mui/icons-material": "^5.0.0",
    "@mui/lab": "^5.0.0-alpha.47",
    "@mui/styled-engine-sc": "^5.0.0",
    "@mui/styles": "^5.0.0",
    ...,
    "next": "^11.1.2",
    ...
    "styled-components": "^5.3.1",
},
"alias": {
    "@mui/styled-engine": "@mui/styled-engine-sc"
},

(and also having usual collectStyles in the _document and like 3 providers in the _app)

I'm styling with import styled from "styled-components";.

Warning: Did not expect server HTML to contain a <style> in <div>.

In every page refresh

truediogo avatar Sep 17 '21 14:09 truediogo

Warning: Did not expect server HTML to contain a <style> in <div>.

In every page refresh

Putting "alias" in the package.lock surely wouldn't cause that.

MonstraG avatar Sep 17 '21 14:09 MonstraG

Warning: Did not expect server HTML to contain a <style> in <div>. In every page refresh

Putting "alias" in the package.lock surely wouldn't cause that.

Is already in package.json, there's also in next.config.js the configs from examples.

    webpack: config => {
      config.resolve.alias = {
        ...config.resolve.alias,
        '@mui/styled-engine': '@mui/styled-engine-sc'
      }
      return config
    }

Already deleted .next and node_modules, cleaned up the browsers data and didn't solve this issue.

truediogo avatar Sep 17 '21 19:09 truediogo

@mnajdova Is this still active or was it fixed in https://github.com/mui-org/material-ui/pull/27583?

eps1lon avatar Sep 18 '21 08:09 eps1lon

Guys, I have edit sandbox example, because it doesn't reproduce bug. To reproduce bug, styled component must use props

Here is a link to see the bug

https://codesandbox.io/s/charming-rain-oswex?file=/pages/index.js

the same thing to withStyle and makeStyle If u dont use props, it is ok, but once u have used props based styles, bug happens

nurbeknurjanov avatar Sep 21 '21 15:09 nurbeknurjanov

image

gajet5 avatar Sep 23 '21 13:09 gajet5

Hi guys, anyone figured out a fix?

https://github.com/mui-org/material-ui/tree/master/examples/nextjs-with-styled-components-typescript has some recents commit, still seeing the errors when developing

alexhhn avatar Sep 29 '21 19:09 alexhhn

@alexhhn see https://github.com/mui-org/material-ui/issues/27512#issuecomment-903781107 If you are using yarn - #27583 should work and fix the class name mismatch error. It, however, doesn't work with npm.

mnajdova avatar Oct 14 '21 06:10 mnajdova

dunno if this is some poor hack or what, but i found solution that works for me:

_app.tsx:

export default function MyApp(props: AppProps) {
  const { Component, pageProps } = props;
  const [loaded, setLoaded] = React.useState(false);

  React.useEffect(() => {
    setLoaded(true);
  }, []);

  return (
    <React.Fragment>
      <Head>
        <title>Next App</title>
        <link href="/favicon.ico" rel="icon" />
        <meta content="minimum-scale=1, initial-scale=1, width=device-width" name="viewport" />
      </Head>
      <ThemeProvider theme={theme}>
        <CssBaseline />
        {loaded && <Component {...pageProps} />}
      </ThemeProvider>
    </React.Fragment>
  );
}

Michal-gasiorowski avatar Oct 18 '21 11:10 Michal-gasiorowski

The problem with this approach is that the SSR part ends up being turned off @Michal-gasiorowski, I'm having the same problem using next + material-5 + makeStyles + npm, I saw several issues reporting this type of issue being caused by various reasons, this ended up leaving me confused about the real status of this issue?

tiagooliveira08 avatar Oct 18 '21 16:10 tiagooliveira08

Thats true @tiagooliveira08, i know its a temporary solution, not a proper fix, but i found that you can do this like below, and loose that ssr performance boost only in development- in production everything seems to work fine, and some quick tests i did shows, that ssr works fine in production without errors. But maybe, there is something im missing here, or other drawbacks?:

_app.tsx:

const isProd = process.env.NEXT_PUBLIC_ISPROD ? (process.env.NEXT_PUBLIC_ISPROD === "true" ? true : false) : true;

const MyApp: React.FC<AppProps> = (props) => {
  const { Component, pageProps } = props;
  const [loaded, setLoaded] = React.useState(false);

  React.useEffect(() => {
    setLoaded(true);
  }, []);

  return (
    <React.Fragment>
      <Head>
        <title>Next App</title>
        <link href="/favicon.ico" rel="icon" />
        <meta content="minimum-scale=1, initial-scale=1, width=device-width" name="viewport" />
      </Head>
      <ThemeProvider theme={theme}>
        <CssBaseline />
        {(isProd || loaded) && <Component {...pageProps} />}
      </ThemeProvider>
    </React.Fragment>
  );
};

export default MyApp;

envs:

NEXT_PUBLIC_ISPROD=false // dev

NEXT_PUBLIC_ISPROD=true // prod

ps. i dont like this soulution, but i havent found any better ;) All the fixes i found here and there, doesnt work with newest next.js + mui 5 + styled components

Michal-gasiorowski avatar Oct 19 '21 08:10 Michal-gasiorowski

@alexhhn see #27512 (comment) If you are using yarn - #27583 should work and fix the class name mismatch error. It, however, doesn't work with npm.

For me, using yarn, this doesn't fix the issue right now.

Here is repro (though there isn't much to look at): https://codesandbox.io/s/classmismatch-mui-2021-10-19-x27lr?file=/pages/index.tsx Because it uses yarn 2, you'll need to open up second terminal and write yarn dev (and probably yarn install) Sometimes codesandbox doesn't trigger the message immideately, local build is more "reliable"

MonstraG avatar Oct 19 '21 09:10 MonstraG

@MonstraG we haven't tested with yarn 2 yet. Could you confirm that it works with 1?

mnajdova avatar Oct 20 '21 07:10 mnajdova

Also having this problem, getting Prop 'className' did not match. Server: "sc-iktFfs ljFsjP sc-jJEKmz gpmJvp" Client: "sc-hHfuMS ixscoD sc-dmlqKv iyJBXp" when using "@mui/styled-engine": "npm:@mui/styled-engine-sc@latest" and all the changes listed in https://github.com/mui-org/material-ui/pull/27583. I'm using import { styled } from "@mui/material/styles"; to style the components if that makes any difference, and yarn v2.

JacobSoderblom avatar Oct 26 '21 15:10 JacobSoderblom

Hi again! I was able to get it working with yarn v2.

Followed the implementation in https://github.com/mui-org/material-ui/pull/27583 until I got the problem above, but I solved that problem by upgrading babel-plugin-styled-components to v1.13.3, and it seems to solve the problem overall. Cannot see any warnings any more!

JacobSoderblom avatar Oct 28 '21 08:10 JacobSoderblom

Thanks for the info @JacobSoderblom, I will test again now to see if the instructions in #27583 still apply. We use there latest as a version of the plugin so it should be always up to date.

mnajdova avatar Oct 28 '21 11:10 mnajdova

Yarn2, recent update fixed important issue on production (thanks, by the way :) ), but classMismatch didn't go away. setup:

		"@mui/material": "^5.0.6",
		"@mui/styled-engine-sc": "^5.0.4",
		and
		"resolutions": {
				"@mui/styled-engine": "npm:@mui/[email protected]"
		},
	   
	   import styled, { css } from "@mui/styled-engine";

switching to yarn1 does nothing.

MonstraG avatar Oct 28 '21 12:10 MonstraG

@mnajdova, I'm still unsure of how to tackle the issue but it is worth mentioning that the issue is the same, following both, styled-components and emotion examples.

Detailed steps to reproduce:

  • (Terminal) Clone any of the available examples of nextjs + mui + typescript, (emotion or styled-components)

  • (Terminal) Install dependencies:

        yarn
    
  • (Terminal) Add @mui/styles dependency to use makeStyles:

     yarn add @mui/styles
    
  • (/pages/index) Import makeStyles and define classes:

    • ps: using media queries here since breakpoints + typescript + useStyles was leading to another error;
    
       // pages/index.tsx
    
       import Box from '@mui/material/Box';
       import Container from '@mui/material/Container';
       import Typography from '@mui/material/Typography';
       import { makeStyles } from '@mui/styles';
       import * as React from 'react';
       import Copyright from '../src/Copyright';
       import Link from '../src/Link';
       import ProTip from '../src/ProTip';
    
       export default function Index() {
    
         const classes = makeStyles(() => ({
           container: {
             '@media (max-width: 600px)': {
               fontSize: 20'vw'
             },
             '@media (min-width: 601px)': {
               fontSize: '7rem'
             }
           }
         }))();
    
         return (
           <Container maxWidth="sm" className={classes.container}>
             <Box sx={{ my: 4 }}>
               <Typography variant="h4" component="h1" gutterBottom>
                 Next.js v5-beta with TypeScript example
               </Typography>
               <Link href="/about" color="secondary">
                 Go to the about page
               </Link>
               <ProTip />
               <Copyright />
             </Box>
           </Container>
         );
       }
    
    • (Terminal) Run project:
       yarn dev
    
    • (Browser) Access app on http://localhost:3000;
    • (Browser: DevTools) Set window to responsive and drag to force the media query responsive font size changes;
    • (Browser) :heavy_check_mark: Verify that it is all running as expected ;
    • (Browser) Click on 'Go to the about page' link;
    • (Browser) :heavy_check_mark: Verify that is all running as expected;
    • (Browser) Click to go back on the browser 'back' arrow;
    • (Browser) Refresh the page (F5);
    • (Browser) ❌ Verify that the style broke and the following error appear on the console:
      Warning: Prop `className` did not match. Server: "MuiContainer-root MuiContainer-maxWidthSm makeStyles-container-2 css-cuefkz-MuiContainer-root" Client: "MuiContainer-root MuiContainer-maxWidthSm makeStyles-container-1 css-cuefkz-MuiContainer-root"
          at div
          at eval (webpack-internal:///./node_modules/@emotion/react/dist/emotion-element-99289b21.browser.esm.js:55:66)
          at Container (webpack-internal:///./node_modules/@mui/material/Container/Container.js:93:83)
          at Index (webpack-internal:///./pages/index.tsx:32:19)
          at InnerThemeProvider (webpack-internal:///./node_modules/@mui/system/esm/ThemeProvider/ThemeProvider.js:21:70)
          at ThemeProvider (webpack-internal:///./node_modules/@mui/private-theming/ThemeProvider/ThemeProvider.js:47:5)
          at ThemeProvider (webpack-internal:///./node_modules/@mui/system/esm/ThemeProvider/ThemeProvider.js:41:5)
          at MyApp (webpack-internal:///./pages/_app.tsx:57:27)
          at StyleRegistry (webpack-internal:///./node_modules/styled-jsx/dist/stylesheet-registry.js:231:34)
          at ErrorBoundary (webpack-internal:///./node_modules/@next/react-dev-overlay/lib/internal/ErrorBoundary.js:26:47)
          at ReactDevOverlay (webpack-internal:///./node_modules/@next/react-dev-overlay/lib/internal/ReactDevOverlay.js:90:23)
          at Container (webpack-internal:///./node_modules/next/dist/client/index.js:305:9)
          at AppContainer (webpack-internal:///./node_modules/next/dist/client/index.js:745:26)
          at Root (webpack-internal:///./node_modules/next/dist/client/index.js:866:27)
      printWarning @ react-dom.development.js?ac89:67
      error @ react-dom.development.js?ac89:43
      warnForPropDifference @ react-dom.development.js?ac89:8824
      diffHydratedProperties @ react-dom.development.js?ac89:9645
      hydrateInstance @ react-dom.development.js?ac89:10400
      prepareToHydrateHostInstance @ react-dom.development.js?ac89:14616
      completeWork @ react-dom.development.js?ac89:19458
      completeUnitOfWork @ react-dom.development.js?ac89:22815
      performUnitOfWork @ react-dom.development.js?ac89:22787
      workLoopSync @ react-dom.development.js?ac89:22707
      renderRootSync @ react-dom.development.js?ac89:22670
      performSyncWorkOnRoot @ react-dom.development.js?ac89:22293
      scheduleUpdateOnFiber @ react-dom.development.js?ac89:21881
      updateContainer @ react-dom.development.js?ac89:25482
      eval @ react-dom.development.js?ac89:26021
      unbatchedUpdates @ react-dom.development.js?ac89:22431
      legacyRenderSubtreeIntoContainer @ react-dom.development.js?ac89:26020
      hydrate @ react-dom.development.js?ac89:26086
      renderReactElement @ index.js?46cb:488
      doRender @ index.js?46cb:709
      _callee$ @ index.js?46cb:384
      tryCatch @ runtime.js?2d8a:45
      invoke @ runtime.js?2d8a:274
      prototype.<computed> @ runtime.js?2d8a:97
      asyncGeneratorStep @ index.js?46cb:31
      _next @ index.js?46cb:49
      eval @ index.js?46cb:54
      eval @ index.js?46cb:46
      _render @ index.js?46cb:403
      render @ index.js?46cb:406
      eval @ next-dev.js?3515:76
      eval @ fouc.js?0087:12
      requestAnimationFrame (async)
      displayContent @ fouc.js?0087:7
      eval @ next-dev.js?3515:75
      Promise.then (async)
      eval @ next-dev.js?3515:38
      ./node_modules/next/dist/client/next-dev.js @ main.js?ts=1635690486095:578
      options.factory @ webpack.js?ts=1635690486095:633
      __webpack_require__ @ webpack.js?ts=1635690486095:37
      __webpack_exec__ @ main.js?ts=1635690486095:1247
      (anonymous) @ main.js?ts=1635690486095:1248
      webpackJsonpCallback @ webpack.js?ts=1635690486095:1179
      (anonymous) @ main.js?ts=1635690486095:9
      Show 2 more frames
    

My environment:

node: v16.13.0 yarn: v1.22.10

amaralc avatar Oct 31 '21 14:10 amaralc

After struggling for a day with a combination of issues (Next.js 12 + MUI v5 + TypeScript + makeStyles), I guess there is a permanent solution (at least for those using emotion as engine and are wiling to use styled api). I think it also works with styled components but can't be sure since I ran into another error (same mentioned by @mnajdova here);

So... to the possible solution:

While trying to fix the media query thing, I stumbled upon this CodeSandbox, that uses the styled API instead of makeStyles. I also noticed that it uses a <StyledEngineProvider> component with injectFirst property, but after testing it, the use of styled API was enough to prevent the issue.

I will send a PR, adding a styled component to the the emotion example in the next minutes (my first PR here, still unsure of how to proceed, but I'll give it a try), so that other people can also avoid wasting time on the makeStyles path.

amaralc avatar Oct 31 '21 15:10 amaralc

_document.tsx

`import { ServerStyleSheets } from '@mui/styles'


MyDocument.getInitialProps = async (ctx) => { const sheets = new ServerStyleSheets() ctx.renderPage = () => originalRenderPage({ // eslint-disable-next-line react/display-name enhanceApp: (App: any) => (props) => sheets.collect(<App emotionCache={cache} {...props} />), }) ..... return { ...initialProps, // Styles fragment is rendered after the app and page rendering finish. styles: [...React.Children.toArray(initialProps.styles), sheets.getStyleElement()], } }`

Alan-QK avatar Nov 12 '21 03:11 Alan-QK

@mnajdova Thanks for the answer, I tried to use Yarn but still got the same error after one refresh

alexhhn avatar Nov 28 '21 19:11 alexhhn

See https://github.com/mui-org/material-ui/issues/29742#issuecomment-982597676 I am starting to think that we should maybe rather recommend emotion for SSR projects. There are just so many issues using styled-components with external library.

Credits to @Janpot for the investigation around this.

mnajdova avatar Dec 02 '21 10:12 mnajdova

See #29742 (comment) I am starting to think that we should maybe rather recommend emotion for SSR projects. There are just so many issues using styled-components with external library.

Credits to @Janpot for the investigation around this.

I'm a styled-component user with NextJS. Can we conveniently convert to emotion just by updating the _document.js as specified in the example repo?

Our components are all using the const Styledcomponent = styled(MuiComponent)(({ theme }) => ``) pattern.

We are uncomfortable with moving our codes now because we do not understand why Mui offers the choice of "emotion" and "styled-components" and we used "styled-components" simply because we have used it before and we can easily reuse many of our component codes.

However, in your https://codesandbox.io/s/9r5ww?file=/demo.js example sandbox, it uses @emotion/styled and it looks the same as styled-components code style.

Also, in the documentation, there is also 'styled component API' https://mui.com/styles/basics/#styled-components-api which we are unsure whether it's related to using 'styled-components, or Mui simply created a API that allow us to create styles using styled-components code style.

overall it's a little confusing... will there be a lot of code migration if we switch to emotion now?

daveteu avatar Dec 06 '21 12:12 daveteu