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

Wrong styles applied during SSR hydration #351

Open
javiertury opened this issue Aug 25, 2021 · 9 comments
Open

Wrong styles applied during SSR hydration #351

javiertury opened this issue Aug 25, 2021 · 9 comments

Comments

@javiertury
Copy link

javiertury commented Aug 25, 2021

Styled components is applying wrong styles during SSR hydration. The problem is that styles in production builds are swapped across components. For instance, the class sc-16rshtk is applied to a ToolbarContainer but contains the styles of a FooterLink. I'm using gatsby with gatsby-theme-material-ui and gatsby-plugin-styled-components.

This didn't happen for client side rendering, only for SSR. Since it only affected components styled with styled-components, I tried to collect more information by assigning a displayName to each component, but it did nothing, classnames remained the same.

Then I found #261 and saw this comment. It says that styled-components should not be re-exported to make displayName work.

import styled from '../lib/styled-components'; //  Does not work :(
import styled from 'styled-components'; //  Works

After applying that change, I made a new production build and then discovered that SSR hydration was now working correctly. I suspect that babel-plugin-styled-components does not work if the package is re-exported.

This issue was very hard to debug.

If you were re-exporting the module to add theme type definitions, please use module augmentation instead.

// src/types/styled-components.ts
import type { Theme } from '@material-ui/core';

declare module 'styled-components' {
  export interface DefaultTheme extends Theme {
  }
}
@mnajdova
Copy link

You probably should use topLevelImportsPath to import styled() from different location. Based on the tests this is supported, see https://github.com/styled-components/babel-plugin-styled-components/blob/main/test/fixtures/add-identifier-with-top-level-import-paths-and-named-import/.babelrc and https://github.com/styled-components/babel-plugin-styled-components/blob/main/test/fixtures/add-identifier-with-top-level-import-paths/.babelrc

Should be confirmed by some of the maintainers.

@iDVB
Copy link

iDVB commented Dec 23, 2021

@javiertury This is the first time I've seen issues that speak very closely to the super annoying issues we are also having.
However, we still can't find a fix in any of the comments.

Env:
@ourcompany/react-ui-components
@ourcompany/projectx

We too are noticing that our projects (@ourcompany/projectx) that consume our ui lib (@ourcompany/react-ui-components) are experiencing this same issue with the wrong styles being applied.

The way we import

We're not using typescript, and never have imported this way in either our repos. import styled from '../lib/styled-components'; Not sure why anyone would do that, so I think I'm missing something important? We've always imported as import styled from 'styled-components'; in both our @ourcompany/react-ui-components and @ourcompany/projectx.

Version of babel-plugin-styled-components

We've had to lock babel-plugin-styled-components to v1.10.3 in order to get it working right. Even tried updated everything to latest v2.0.2 and still broken.

Please Help!

It sounds like many people have solved this issue and have wrapped there head around the cause, but the solution doesn't seem to apply to us?

@javiertury
Copy link
Author

@iDVB if the symptoms are similar to mine then it's probably because this babel plugin is not transforming your source files.

We've always imported as import styled from 'styled-components';

Even if you are importing the package correclty, there can be other reasons why your source files are not being transformed.

From the description of your issue, I suspect that the problem lies in your babel configuration with respect to packages @ourcompany/react-ui-components and @ourcompany/projectx. Usually babel is configured to transform only the source code of the current package and to ignore node_modules. Additionally, bundlers like webpack, vite or rollup could also be preventing node_modules from being transformed by babel.

Please check that both babel and your bundler are configured to transform your node_modules, or at least node_modules/@ourcompany/react-ui-components and node_modules/@ourcompany/projectx.

https://babeljs.io/docs/en/options#exclude
https://babeljs.io/docs/en/options#ignore

@iDVB
Copy link

iDVB commented Dec 23, 2021

@javiertury Thanks! Ya I bet it's something like that. But can you clarify one thing that has been nagging us.

As styled-component ui lib authors, are we supposed to apply the babel-styled-components plugin when packaging/publishing the lib AND in the consuming repo?

Currently, when publishing the ui lib we ARE using that plugin, however when we are bundling the consuming project (gatsby) we are ONLY targeting things NOT in node_modules. So this lib would not be processed this second time.

Also, keep in mind everything works fine AS-IS so long as we keep to babel-styled-components@v 1.10.5

@javiertury
Copy link
Author

javiertury commented Dec 23, 2021

Beyond the scope of my setup, I can only provide ideas for configuration changes but not much more.

Even though in many cases it's recommended to do transpilation at the library level, I have a gut feeling this plugin is different because there are reports of bugs when duplicated packages for styled-components or the babel plugin are used. I would say try to apply this babel plugin only on your main project(gatsby) and take the plugin out of your libraries (but just this plugin, you can keep the rest of your babel config). Try also to bundle those libraries as ES6 modules (that's the preferred format for rollup and webpack 5).

Finally, take a look at other issues that may be related with other aspects of your setup, for instance this bug with duplicated imports because of symlinked node_modules.

@iDVB
Copy link

iDVB commented Dec 27, 2021

@javiertury makes sense. But the larger question I'm thinking.... is why did this work fine before with previous versions?

@agriffis
Copy link
Contributor

@javiertury I'm a little confused about the conclusion of this issue. Are you reporting a bug or just confusion? Did @mnajdova's comment help?

@javiertury
Copy link
Author

Are you reporting a bug or just confusion?

Now just confusion. Although at first I didn't know about topLevelImportsPath and I thought it was a bug.

Also I would like to draw attention to how painful it was to find out that re-exporting the package was breaking SSR. Perhaps the debugging experience could be improved somehow or the documentation for the plugin could include a reference to topLevelImportsPath.

Did @mnajdova's comment help?

I replicated the original problem in my project, used @mnajdova topLevelImportsPath to solve it and it worked.

@michaeljscript
Copy link

I had the same issue when using nx dev with NextJS and what worked for me was to

  1. Make sure you have .babelrc file in your project with the following
{
 "plugins": [["styled-components", { "ssr": true }]],
 "presets": ["next/babel"]
}
  1. Correctly configured _document.tsx file
import Document, { Html, Head, Main, NextScript } from 'next/document';
import { ServerStyleSheet } from 'styled-components';

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

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

      const initialProps = await Document.getInitialProps(ctx);
      return {
        ...initialProps,
        styles: (
          <>
            {initialProps.styles}
            {sheet.getStyleElement()}
          </>
        ),
      };
    } finally {
      sheet.seal();
    }
  }
  render() {
    return (
      <Html>
        <Head>{this.props.styles}</Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

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

No branches or pull requests

5 participants