Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hydration errors in development for Next.js app with MUI Material v5 after updating emotion dependencies #3222

Open
ddembo opened this issue Jul 24, 2024 · 17 comments

Comments

@ddembo
Copy link

ddembo commented Jul 24, 2024

Current behavior:

We are getting hydration errors in development on pages that render components which are styled MUI components, after updating the following dependencies:

  • @emotion/cache from 11.11.0 to 11.13.0
  • @emotion/react from 11.11.4 to 11.13.0
  • @emotion/styled from 11.11.5 to 11.13.0
Warning: Prop `className` did not match. Server: "MuiTableCell-root MuiTableCell-body MuiTableCell-sizeSmall e18whkzw0 mui-az1ynu-MuiTableCell-root-TableCellLinkContainer" Client: "MuiTableCell-root MuiTableCell-body MuiTableCell-sizeSmall e18whkzw0 mui-1odz46y-MuiTableCell-root-TableCellLinkContainer"

Notably, we did not update MUI or any related dependencies at the same time.

It only affects components created using the styled helper, e.g.:

import styled from "@emotion/styled";
import TableRow from "@mui/material/TableRow";

const StyledTableRow = styled(TableRow)({
  "&:last-child > th, &:last-child > td": {
    borderBottom: 0,
  },
});

export default StyledTableRow;

It seems to be a problem with one of those packages' underlying dependencies, because the issue disappears when we use the old package-lock.json, but not if we nuke and recreate it.

I've been trying to identify the root cause but I'm finding it difficult, I'm not very familiar with the internals of emotion. I think it could be a problem with the serialiser, because the client <style> tags being inserted look to me like the data-emotion attributes are missing the serialized classnames that typically seem to follow the cache prefix mui, e.g.:

image

It could also be a problem with the hash package, since the hashed part of the className is different.

The issue is not present in production builds of the app.

To reproduce:

CSB: TODO later if I have some more time

  1. Make a styled MUI component as described above, put it on a Next.js page.
  2. Visit that route in a browser, open devtools.

Expected behavior:

Classnames should match on both client & server, no hydration errors.

Environment information:

"react": "^18.3.1",
"@emotion/react": "^11.13.0",

"@emotion/cache": "^11.13.0",
"@emotion/server": "^11.11.0",
"@emotion/styled": "^11.13.0",

"@mui/material": "^5.16.4",
"@mui/material-nextjs": "^5.16.4",
@OliverwengFiltered
Copy link

same here, we need it to be fixed.

@Andarist
Copy link
Member

I need a runnable repro case to investigate this.

@OliverwengFiltered
Copy link

I can get that over to you tomorrow.

@Andarist
Copy link
Member

I'd appreciate that, thanks!

@OliverwengFiltered
Copy link

interestingly, when I shrink the project to bare minimum, the issue is gone, I will need to do more research.

@jakeleventhal
Copy link

FWIW, I am getting this problem with:

"@emotion/cache": "11.11.0",
"@emotion/react": "11.11.4",
"@emotion/styled": "11.11.5",

@mridgway
Copy link

mridgway commented Jul 29, 2024

I think this is introduced as an issue with this change. The server now defaults to using emotion-serialize.cjs.js while webpack will automatically use development.cjs.js version. The non-development version excludes sourceMaps explicitly from the serialization algorithm while the development version does not.

It doesn't seem reasonable to assume that users will know to add --conditions to the node process to fix this development issue, especially when it is still an experimental flag.

Setting an override in my package.json fixed this for me:

    "overrides": {
        "@emotion/serialize": "1.2.0"
    }

@jakeleventhal
Copy link

jakeleventhal commented Jul 30, 2024

@mridgway I can confirm I have this issue even with 1.2.0

▶ cat pnpm-lock.yaml | grep @emotion/serialize
      '@emotion/serialize':
  '@emotion/[email protected]':
      '@emotion/serialize': 1.2.0
      '@emotion/serialize': 1.2.0
  '@emotion/[email protected]':
      '@emotion/serialize': 1.2.0
      '@emotion/serialize': 1.2.0

pnpm-lock.yaml.zip

@Andarist
Copy link
Member

It doesn't seem reasonable to assume that users will know to add --conditions to the node process to fix this development issue, especially when it is still an experimental flag.

This is news to me. I totally considered this a stable feature. It's mentioned multiple times in other parts of the docs and is never guarded with the experimental warning at those places. On top of that, node.js doesn't emit any experimental features warnings when you use custom conditions so it's not apparent at all that it's experimental.

That said, I don't know how we are supposed to deal with this. The environment needs to be in a cohesive state. What kind of setup are you using? Is your server created manually?

@OliverwengFiltered
Copy link

I think this is introduced as an issue with this change. The server now defaults to using emotion-serialize.cjs.js while webpack will automatically use development.cjs.js version. The non-development version excludes sourceMaps explicitly from the serialization algorithm while the development version does not.

It doesn't seem reasonable to assume that users will know to add --conditions to the node process to fix this development issue, especially when it is still an experimental flag.

Setting an override in my package.json fixed this for me:

    "overrides": {
        "@emotion/serialize": "1.2.0"
    }

I can confirm that the override works for me, after override it back to 1.2.0, and redo npm install, the warning is gone.

@jakeleventhal
Copy link

I think this is a red herring. My current version of code uses @emotion/[email protected] in my pnpm-lock.yaml file.
The only emotion packages I use/specify in my package.json files are:

"@emotion/cache": "11.11.0",
"@emotion/react": "11.11.4",
"@emotion/styled": "11.11.5",

@PeanutButte7
Copy link

I think this is introduced as an issue with this change. The server now defaults to using emotion-serialize.cjs.js while webpack will automatically use development.cjs.js version. The non-development version excludes sourceMaps explicitly from the serialization algorithm while the development version does not.

It doesn't seem reasonable to assume that users will know to add --conditions to the node process to fix this development issue, especially when it is still an experimental flag.

Setting an override in my package.json fixed this for me:

    "overrides": {
        "@emotion/serialize": "1.2.0"
    }

Using MUI Material v5 with Nextjs Pages router and got this exact problem after updating emotion dependencies.

While I don't have "@emotion/serialize" directly in my package.json overriding "@emotion/serialize" as mentioned, running install and restarting the server fixed it for me

@Andarist
Copy link
Member

Once I get the repro case of the problem, I could investigate this

@ddembo
Copy link
Author

ddembo commented Jul 31, 2024

@Andarist I've made a minimal reproduction of the issue here. The error is slightly different (complains about table tag instead of classname) but it looks like the same problem with malformed style tags in the DOM.

Thank you for looking into this, please let me know if you need any more details.

@mridgway
Copy link

mridgway commented Jul 31, 2024

The serialization issue is also reproducible in the basic next.js create-next-app example:

npx create-next-app --example with-emotion repro
cd repro
npm run dev

Screenshot 2024-07-30 at 8 15 04 PM

After adding to the package.json:

  "overrides": {
    "@emotion/serialize": "1.2.0"
  },

Screenshot 2024-07-30 at 8 20 56 PM

@gchallen
Copy link

gchallen commented Aug 1, 2024

As an additional data point, I've been seeing these errors since MUI 5.16.0 and have been pinned on 5.15.21 until I had time to put together a reproduction. I got the emotion changes today and am using @emotion/serialize: 1.3.0. So it's possible that there are several overlapping issues here causing the same failures, as suggested by @jakeleventhal.

@furai
Copy link

furai commented Aug 19, 2024

Is there a way to actually fix it without overriding dependencies and downgrading packages?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants