next.js: CSS Modules sometimes don't load when using next/dynamic import

Run next info (available from version 12.0.8 and up)

Operating System:
  Platform: darwin
  Arch: x64
  Version: Darwin Kernel Version 20.3.0: Thu Jan 21 00:06:51 PST 2021; root:xnu-7195.81.3~1/RELEASE_ARM64_T8101
Binaries:
  Node: 14.17.0
  npm: 6.14.13
  Yarn: 1.22.10
  pnpm: N/A
Relevant packages:
  next: 12.0.8
  react: 17.0.2
  react-dom: 17.0.2

What version of Next.js are you using?

12.0.8

What version of Node.js are you using?

14.17

What browser are you using?

Chrome

What operating system are you using?

macOS

How are you deploying your application?

Vercel

Describe the Bug

When loading a component using next/dynamic, CSS modules are sometimes not loaded correctly. This seems like it may be similar to https://github.com/vercel/next.js/issues/18252, which is described as fixed (although there is no linked PR showing the fix).

This bug only occurs when running next build + next start. Works as expected in development (next dev). Additionally, there seem to very specific scenarios where it occurs, which I’ve tried to outline as clearly and concisely as possible int he repro steps.

Expected Behavior

CSS modules should be loaded into the document so that your styles are applied.

To Reproduce

Repro Repo and Deployment

I’ve created a demo using create-next-app --typescript 12.0.8: https://github.com/jzxhuang/dynamic-import-css-module-next-bug

It’s hosted at: https://dynamic-import-css-module-next-bug.vercel.app/

Isolated Reproduction Steps

  1. Go directly to https://dynamic-import-css-module-next-bug.vercel.app/broken/one, notice the button has a red background.
  2. Click the link to /foo. The button will now have a clear background, even though it is the exact same component with no changes whatsoever.

This can be reproduced with both SCSS and CSS modules. Repeating the above steps with https://dynamic-import-css-module-next-bug.vercel.app/broken/two will break the blue button. This is reproduced only in the “production” build, if you follow the same steps with next dev, the buttons on /foo should always be the correct color.

Cases where it works, but why?

The above steps are an isolated reproduction of this bug which we found in production. Now, here’s where it starts getting super weird, we decided to do some more experimentation. I’m not sure if the following scenarios will be helpful or just throw you into a wild goose chase, but here we go:

  1. Go to https://dynamic-import-css-module-next-bug.vercel.app
  2. Click the link to /broken/one, DO NOT REFRESH
  3. Click the link to /foo.
  4. It’s expected that the button is now red…

We also created a few other examples, under the routes /working/*. The only difference here is that we either load 2, 3, or 0 of the buttons. For some reason, these seems to work fine, but if you load only one button, as shown in broken/one and broken/two, the styling will be broken.

If you don’t lazy load, everything is fine

Back to something that makes sense. The example /working/three shows that the blue button will always be the correct color. It is not dynamically imported in /foo, and thus does not have the same bug that the dynamically imported buttons do.

What’s going on in the DOM?

On /broken/one, we see the button has the class comp-one_button__MtA0_ which is in the stylesheet 0ff09bacf4af1553.css. image

When we click into /foo, the button still has the same class, but the stylesheet is not being applied. image

I’m not sure what the root cause of this might be, but there’s somehow a stylesheet missing when dynamically importing, and it seems to be related to using a component on the previous component inside the dynamically imported component.

About this issue

  • Original URL
  • State: open
  • Created 2 years ago
  • Reactions: 49
  • Comments: 21

Commits related to this issue

Most upvoted comments

Having similar issues with missing css files!

Having the same issue with Next.js 13, when navigating to any other page from the Home page, the CSS doesn’t work.

Also seeing this on NextJS 12.2.2. Can confirm that the issue goes away if not using dynamic imports.

bump, same issue on nextjs 12.1.5

Hey, wondering if there are any insights or leads on this one! It’s affecting us in production and we don’t have any known workarounds — next/dynamic is required for to avoid a problematic library import that is not SSR-compatible. Thanks!

A possible workaround for this problem is to move all async chunks into one group.

next.config.mjs:

export default {
  webpack(config, context) {
    const { isServer, dev } = context
    if(!isServer && !dev) {
       config.optimization.splitChunks.cacheGroups.asyncChunks = {
         enforce: true,
         type: "css/mini-extract",
         chunks: 'async',
       }
    }
   return config
  }
}

Same issue in 13.4.4

Same issue here 😦 v.13.4.3

In my Case, im building a Site with Data coming from a CMS. So i wanted to load the needed Components to the currently active Sites with Next/dynamic.

I tried all kind of stuff, but in the End solved the Issue with a switch. Guess we have to wait for a future release to get things fixed with dynamic. For now i would only recommend to use it with small components that dont load extra CSS.

Heres an Example how i did it, like this the Components will be returned the normal way and CSS Modules will be loaded:

          `{components.map((component: any, k: any) => {
              if (componentsProps[k].componentregion === regionNum) {

                switch (component) {
                  case "Example_component1":
                    return (
                      <Example_component1
                        componenttype={componentsProps[k].componenttype}
                        componentid={componentsProps[k].componentid}
                        key={k}
                      />
                    )
                  break;
                  case "Example_component2":
                    return (
                      <Example_component2
                        componenttype={componentsProps[k].componenttype}
                        componentid={componentsProps[k].componentid}
                        key={k}
                      />
                    )
                  break;
                  case "Example_component3":
                    return (
                      <Example_component3
                        componenttype={componentsProps[k].componenttype}
                        componentid={componentsProps[k].componentid}
                        key={k}
                      />
                    )
                  break;
                  case "Example_component4":
                    return (
                      <Example_component4
                        componenttype={componentsProps[k].componenttype}
                        componentid={componentsProps[k].componentid}
                        key={k}
                      />
                    )
                  break;
                }
              }
            })}`