Next.js: styled-components with Babel plugin results in className mismatch on Next.js 5

Created on 6 Feb 2018  Â·  19Comments  Â·  Source: vercel/next.js

  • [x] I have searched the issues of this repository and believe that this is not a duplicate.

Expected Behavior

styled-components should not result in the className mismatch warning from React.

Current Behavior

Warning: Prop `className` did not match. Server: "Header-johx6c-0 bHIeEO" Client: "Header___default-johx6c-0 gGUBlx"

I'm exporting the header component like so:

export default styled(Header)`
  text-align: center;
`;

Notice that styled-components uses the name Header on the server and Header__default on the client. This doesn't happen with Next.js 4, so I assume it has something to do with the way modules are built with the new Universal Webpack setup.

Steps to Reproduce (for bugs)

  1. Use styled-components with next v5.
  2. Use babel-plugin-styled-components with the default displayName setting.
  3. Render a component exported like: export default styled(Component)

(It doesn't matter what the Babel plugin's ssr setting is, nor if the server stylesheet is set up in _document.js. Same thing in every combination.)

Your Environment

| Tech | Version |
|---------|---------|
| next | v5.0.0 |
| node | v8.9.4 |
| OS | macOS |
| browser | Chrome |

Most helpful comment

I suppose this is a side effect of using ES module exports for the client and CJS for the server, correct?

I thought we used to have a fix for this in place but apparently we don’t. I’m not sure how safe it’d be to filter out component names that are exposed as “default” but that’d be a solution.

Please note that I would not recommend the “export default styled.div” pattern. I’d guess this is what causes this.

As the result you’d get when applying the above to arrow functions, similarly for our Babel plugin this would mean that your StyledComponent technically doesn’t have a name. So simply writing “const X = ...; export default X” might help here if I’m not mistaken. Even if for “Header” you’d name that variable “Header” or “Container”, for debugging in general this would be more explicit.

All 19 comments

bump.

It only happens in dev for me though.

Tim knows this and said its on their list of things todo very soon!

I got the same problem with a simple h1 component:

const Headline = styled.h1`...`; 

Warning: Prop `className` did not match. Server: "pages__Headline-te1id5-0 bqAPoZ" Client: "pages__Headline-te1id5-0 cIpCqj"

Also only for dev...

([email protected], [email protected])

Tim knows this and said its on their list of things todo very soon!

I haven't said anything like this at any point 🤔

Maybe @kitten knows what's going on.

I suppose this is a side effect of using ES module exports for the client and CJS for the server, correct?

I thought we used to have a fix for this in place but apparently we don’t. I’m not sure how safe it’d be to filter out component names that are exposed as “default” but that’d be a solution.

Please note that I would not recommend the “export default styled.div” pattern. I’d guess this is what causes this.

As the result you’d get when applying the above to arrow functions, similarly for our Babel plugin this would mean that your StyledComponent technically doesn’t have a name. So simply writing “const X = ...; export default X” might help here if I’m not mistaken. Even if for “Header” you’d name that variable “Header” or “Container”, for debugging in general this would be more explicit.

Finally got a fix for this issue. You need to specify for each environment how babel handles styled-components:

this is my .babelrc file, I have other stuff going on in here but look specifically at "Development". Adding the development under env should fix the error completely.

{
  "env": {
    "test": {
      "presets": [
        [
          "env",
          {
            "modules": "commonjs"
          }
        ],
        "next/babel"
      ]
    },
    "development": {
      "plugins": [
        [
          "styled-components",
          {
            "ssr": true,
            "displayName": true
          }
        ]
      ],
      "presets": "next/babel"
    },
    "production": {
      "presets": "next/babel"
    },
    "server": {
      "presets": [
        [
          "env",
          {
            "modules": "commonjs"
          }
        ],
        "next/babel"
      ]
    }
  },
  "plugins": [
    [
      "styled-components",
      {
        "ssr": true,
        "displayName": true
      }
    ],
    [
      "inline-react-svg"
    ],
    [
      "transform-flow-strip-types"
    ]
  ],
  "retainLines": true
}

@spencersmb alright, this indicates that the recommended next.js usage of the plugin is out of date. We've got a note on why this matters in our docs https://www.styled-components.com/docs/tooling#usage

Quote:

The plugin call order in your .babelrc file matters. If you're using the env property in your babel configuration, then putting this plugin into the plugins array won't suffice. Instead it needs to be put into each env's plugins array to maintain it being executed first. See this for more information.

With this issue linked there: https://github.com/styled-components/babel-plugin-styled-components/issues/78

The next.js example needs an update then, if I'm not mistaken? :smile:

@kitten makes sense. The example is actually fine since it doesn't use "env" maybe this should be documented in the example readme though 🤔

https://github.com/zeit/next.js/blob/canary/examples/with-styled-components/

https://github.com/zeit/next.js/blob/canary/examples/with-styled-components/.babelrc

Hmmm, I don't use different envs in my .baberc (actually it looks like the one Tim referenced) and I don't export the styled component. I just use it in the same file:

const Test = styled.div`
 color: red;
`;

export default () => (
    <>
        ...
            <Test>XXX</Test>
        ...
    </>
);

Strangely enough it happens only on my index page and not on every page load...

Hiya, I am also getting Warning: Prop className did not match. Server: "sc-ifAKCX jWHVsk" Client: "sc-bdVaJa ebJbtP"

I was npm link components into my nextJS project and this was causing the issue I think. When I bring the component into the project without linking it works, I still get the render flash though.

Also the issue seems to be on a full refresh - when I edit the page the element renders correctly, on full refresh I get the error above again

Hope this helps to dive a little deeper

Babelrc

{
  "plugins": [
    [ "styled-components", { "ssr": true, "displayName": true, "preprocess": false } ],
  ],
  "presets": ["next/babel"]
}

I use style inline method

    const Button = styled.button`
      border: none;
      border-radius: 5rem;
      color: white;
      cursor: pointer;
      display: inline-block;
      font-size: 1rem;
    `

I'm assuming this doesn't happen anymore with latest styled-components.

@timneutkens Actually it still happens. Is it just me or do you guys also still have this warning popping up?

I'm using [email protected] and [email protected].

Any update on this issue ? Seems annoying to everyone using in dev mode.

What about the Babel plugin version @sarneeh @revskill10? I just tried to make a quick repro with the latest version of next, styled-components, and babel-plugin-styled-components and it looks fixed to me. __default isn't appended to the computed name of the exported component anymore.

@exogen I'm using "babel-plugin-macros": "^2.4.2", , with antd and always got this warning.
The magic is Why client-side still generates their own IDs , because as i see, the only place to generate IDs is in _document.js, which only happens on server side though.

These are my versions:

next 7.0.2
babel-plugin-styled-components 1.1.5
styled-components 4.1.3

...and I'm still having this issue intermittently. Any suggestions?

I found this to work. Make sure you have babel-plugin-styled-components in your dependencies. The following can go in .babelrc or in package.json

```
"babel": {
"env": {
"development": {
"presets": ["next/babel"],
"plugins": [
["styled-components", {
"ssr": true,
"displayName": true
}]
]
},
"production": {
"presets": ["next/babel"],
"plugins": [
["styled-components", {
"ssr": true,
"displayName": true
}]
]
},
"test": {
"presets": [
["next/babel", {
"preset-env": {
"modules": "commonjs"
}
}]
],
"plugins": [
["styled-components", {
"ssr": true,
"displayName": true
}]
]
}
}
}

Issue also occurs with react-jss, where no babel plugin is required.
When the server starts everything works fine, then …randomly… if I refresh the page or hot-reloading does it, client rendered className (example: Comp-el-0-1-3) is higher of server rendered className (example: Comp-el-0-1-1). 🤷‍♂️
next: 8.0.3
react-jss: 8.6.1
@babel/core: 7.3.3

For me everything is fine in production but I get a warning for className mismatch in development. I quickly solved the issue by disabling stylesheets server-side rendering in development.

Here is my _document

class MyDocument extends Document {
  static async getInitialProps(ctx) {
    const sheet = new ServerStyleSheet();
    const originalRenderPage = ctx.renderPage;

    try {
      const initialProps = await Document.getInitialProps(ctx);

      // prevent stylesheets server-side rendering 
      // in case we are not in production
      if (!process.env.NODE_ENV !== 'production') {
        return initialProps;
      }

      ctx.renderPage = () =>
        originalRenderPage({
          enhanceApp: App => props => sheet.collectStyles(<App {...props} />),
        });

      return {
        ...initialProps,
        styles: (
          <React.Fragment>
            {initialProps.styles}
            {sheet.getStyleElement()}
          </React.Fragment>
        ),
      };
    } finally {
      sheet.seal();
    }
  }
}

Then you just to have to edit your babel config to disable the ssr option in development (note that if you're using a .babelrc file to manage babel's config you'll have to convert it to a .babelrc.js file)

const dev = process.env.NODE_ENV !== 'production';

module.exports = {
  presets: ['next/babel'],
  plugins: [
    ['styled-components', { ssr: !dev, displayName: dev }],
  ],
};

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Timer picture Timer  Â·  87Comments

timneutkens picture timneutkens  Â·  250Comments

matthewmueller picture matthewmueller  Â·  102Comments

Timer picture Timer  Â·  60Comments

robinvdvleuten picture robinvdvleuten  Â·  74Comments