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

Verify CSS import ordering #16630

Closed
Timer opened this issue Aug 27, 2020 · 122 comments
Closed

Verify CSS import ordering #16630

Timer opened this issue Aug 27, 2020 · 122 comments
Assignees
Labels
linear: next Confirmed issue that is tracked by the Next.js team. locked Webpack Related to Webpack with Next.js.

Comments

@Timer
Copy link
Member

Timer commented Aug 27, 2020

A user on twitter reported that Next.js may not order CSS imports from JS correctly. We need to investigate and fix this!

https://twitter.com/samselikoff/status/1299032241100787712

NEXT-1350

@Timer Timer added this to the iteration 8 milestone Aug 27, 2020
@santiagoRebella
Copy link

this is still happening to me

@santiagoRebella
Copy link

santiagoRebella commented Sep 7, 2020

@Timer I tried with latest versions including the v9.5.4-canary.5 the issue still there, I am importing global.scss from _app.js and then I have different scss module files. with yarn dev the order is correct, but when doing yarn build && yarn start the order gets changed, so for example, the global bootstrap classes override module classes as is loaded after
Screen Shot 2020-09-07 at 12 06 56 PM
Screen Shot 2020-09-07 at 12 07 10 PM
Screen Shot 2020-09-07 at 12 08 46 PM

@santiagoRebella
Copy link

could be related to #16723

@Aichnerc
Copy link

Hey! I'm having trouble with that too. See my repo for my code and Stackoverflow for my problem.

@sunoj
Copy link

sunoj commented Oct 8, 2020

same here

@kenaku
Copy link

kenaku commented Oct 13, 2020

Nextjs is one of the greatest things in JS landscape, thanks for great work!
Also this bug is killing me, we have a pretty big app with millions of users and update from 9.0.3 to 9.5.5 broke our app in so many places, I cant even imagine how to hotfix this...
Please, fix this 🙏

@usamamashkoor
Copy link

Did anyone find any solution for this?

@sunoj
Copy link

sunoj commented Oct 17, 2020

i create a new css file:style.css and manual import css like the code below, replace the css import in _app.tsx before.

`@import './node_modules/@hackplan/uui/lib/index.css';
@import './node_modules/react-weui/build/packages/react-weui.css';
@import './node_modules/react-image-gallery/styles/css/image-gallery.css';

@import './static/css/app.css';

.style {
color: aliceblue;
}`

then add import '../style.css' in _app.tsx

@usamamashkoor
Copy link

Thanks, @sunoj but it did not work out for us.

@ghost
Copy link

ghost commented Nov 3, 2020

same here

next@10
react@17

@uthd-dev
Copy link

I believe I have this issue as well

@klaemo
Copy link

klaemo commented Dec 9, 2020

Is there anything we can do to help resolve this issue?

@iksent
Copy link

iksent commented Dec 15, 2020

I can confirm this bug exists at 10.0.3 also!
Reproduction is here: #19055
Just can't use Next.js due to such annoying bug: I am using CSS Modules so can't order styles manually and only one possible fix is to add "!important", but for some projects this is a really inconvenient, for some - just impossible.

My own example:

2020-12-15_12-18-29

@newtoniumx3

This comment has been minimized.

@klaemo
Copy link

klaemo commented Jan 12, 2021

I've seen some improvement when going from 10.0.3 -> 10.0.5, but there remain cases where this bug occurs.

@phbetbeze
Copy link

I still have the same issue with 10.0.5. Order is still broken

@Gilbert09
Copy link

Also a problem for me on 10.0.5. Temp fixed the issue with throwing in !important everywhere the ordering was broken

@omarabid
Copy link

Same issue version 10.0.5. How to disable code-splitting?

@edgardz
Copy link

edgardz commented Feb 1, 2021

For me, the problem was I had a global wrapper component imported on _app.js. It contained a navbar and a footer component and rendered the children in the middle. It seems there is not a CSS order problem, but a CSS class duplication problem, because while inspecting the build output I was able to see some classes from the global chunk being redeclared in the page chunk, and since the page chunk is added to the HTML after the global one, it caused some styles to be overwritten. My solution, for now, is to avoid importing any component inside _app.js, instead, I added my wrapper to every page. Not so DRY, but it is working now...

@alexandre-marchina
Copy link

alexandre-marchina commented Feb 1, 2021

@edgardz your case seems to be the same we're discussing here #20203. In our particular scenario, we're experiencing both: the duplication occurs by using components with style inside _app.js (and thus there's a style chunk created for the "_app.js"), and the chunk responsible for the "_app.js" style is ordered after the page chunk, causing the rewrite in different classes (global ones), like the comment from @santiagoRebella #16630 (comment)

@edgardz
Copy link

edgardz commented Feb 1, 2021

@edgardz your case seems to be the same we're discussing here #20203. In our particular scenario, we're experiencing both: the duplication occurs by using components with style inside _app.js (and thus there's a style chunk created for the "_app.js"), and the chunk responsible for the "_app.js" style is ordered after the page chunk, causing the rewrite in different classes (global ones), like the comment from @santiagoRebella #16630 (comment)

Yup. I just checked and my solution is making the component to be re-rendered at each navigation as described in the other issue. So now I changed it a bit, instead of adding the Layout to the render function, I just import it at each page. It is a workaround... Hope they fix this soon.

@spaghettiguru
Copy link

We are experiencing the same problem. Did anybody manage to solve this?

@theivanfranco

This comment has been minimized.

@olalonde
Copy link

olalonde commented Sep 14, 2023

Reproduced this bug here: https://github.com/olalonde/next-vanilla-extract-template/tree/styles-order-broke (vanilla-extract)

And here: https://github.com/olalonde/next-app-template/tree/css-order-wrong (css modules)

The first line of the root layout imports a CSS file but it is not the first content of the generated css bundle. This is an issue even in dev mode npm run dev.

@olalonde
Copy link

olalonde commented Sep 14, 2023

How have people been working around this issue since 3 years? It's kind of a deal breaker no?

edit:

If anyone else happens to use vanilla-extract I made this little wrapper around style() that adds !important all over the place, lol.

// Workaround for the fact that Next.js bundles CSS files in an unpredicatble order
// See
// - https://github.com/vercel/next.js/issues/51030
// - https://github.com/vercel/next.js/issues/16630
// - https://github.com/vercel/next.js/issues/16630#issuecomment-1718974809

import { StyleRule, ComplexStyleRule, style as vanillaStyle } from '@vanilla-extract/css';

type ClassNames = string | Array<ClassNames>;

function isStyleRule(rule: ComplexStyleRule): rule is StyleRule {
  return !Array.isArray(rule);
}

function makeStyleRuleImportant(rule: StyleRule): StyleRule {
  const importantStyle: StyleRule = Object.fromEntries(
    Object.entries(rule).map(([selector, value]) => {
      if (Array.isArray(value)) {
        return [selector, `${value.join(' ')} !important`];
      }
      if (typeof value === 'object') {
        return [selector, makeStyleRuleImportant(value)];
      }
      return [selector, `${value} !important`];
    })
  );
  return importantStyle;
}

function makeImportant(rule: ComplexStyleRule): ComplexStyleRule {
  if (!isStyleRule(rule)) {
    // rule is Array<StyleRule | ClassNames>
    if (rule.length === 0) return rule;
    return rule.map((rule2: StyleRule | ClassNames) => {
      // ClassNames
      if (typeof rule2 === 'string') {
        return rule2;
      }
      // ClassNames
      if (Array.isArray(rule2)) {
        return rule2;
      }
      // StyleRule
      return makeStyleRuleImportant(rule2);
    });
  }
  // rule is StyleRule
  return makeStyleRuleImportant(rule);
}

export function style(rule: StyleRule) {
  return vanillaStyle(makeImportant(rule));
}

@connerdassen
Copy link

connerdassen commented Sep 20, 2023

I have the same issue but with inconsistent results, the order keeps changing.
When I first run npm dev and load my page, bootstrap is incorrectly overriding my globals.css.
Then when I reload the page, the order suddenly changes to the correct order, which (during my limited testing) seems to stay, until I edit files.

When I start editing my page or globals.css, it'll randomly start switching between which styles override which and back.
It's not triggered on every edit either, it just randomly switches up the order, sometimes it stays on one order for a while but eventually it switches again.

@connerdassen
Copy link

I have the same issue but with inconsistent results, the order keeps changing. When I first run npm dev and load my page, bootstrap is incorrectly overriding my globals.css. Then when I reload the page, the order suddenly changes to the correct order, which (during my limited testing) seems to stay, until I edit files.

When I start editing my page or globals.css, it'll randomly start switching between which styles override which and back. It's not triggered on every edit either, it just randomly switches up the order, sometimes it stays on one order for a while but eventually it switches again.

What seems to fix this for now is adding sass, replacing globals.css with globals.scss, adding
@import "../node_modules/bootstrap/scss/bootstrap.scss";
to the top of globals.scss and importing it to the root layout once.

@monolithed
Copy link

monolithed commented Sep 20, 2023

The more I learn about this framework, the more I realize that it's abandoned. First, I encountered a bug with style duplication, and now this issue. I don't even know how to work around it. No one has suggested a fix for three years.

@monolithed
Copy link

When I start editing my page or globals.css, it'll randomly start switching between which styles override which and back.
It's not triggered on every edit either, it just randomly switches up the order, sometimes it stays on one order for a while but eventually it switches again.

@connerdassen, I conducted a small investigation on this issue. If you have reusable components, their styles will always be duplicated. Additionally, if these components are iterated within a loop, in dev mode, the styles get lost when the routing changes.
I also attempted to replace webpack with turbopack, but due to its recent errors, I couldn't even build the project.

If anyone knows how to bundle styles into one file, please let me know.

@Kurt-von-Laven
Copy link

@monolithed, did you already see #16630 (comment)?

@Kurt-von-Laven
Copy link

This issue seems like a duplicate of #13092.

@3den

This comment has been minimized.

@mjvalade
Copy link

mjvalade commented Oct 4, 2023

This issue seems like a duplicate of #13092.

True but both are very long threads about the same thing and seems like Vercel/Next is not interested in a solution? I just created a Next app and ran into this same issue but all I can find are issue threads with no fixes.
I am also on "next": "^13.5.4"

@Kurt-von-Laven
Copy link

I wouldn't assume that they have no interest in fixing this bug. They are actively fixing open issues, but there are many, many open issues. I mainly noted the duplicate to help save them some time. The comment I linked to above has a suggested workaround for now.

@Rajankr542
Copy link

Rajankr542 commented Oct 9, 2023

As @JorianWoltjer explained the problem extending it or adding my version!

When @import is used in any CSS/SCSS file you import at root level directly(layout), the production build will put it at the start. This means that even if you put this import '/path/to/style.css' below your any other CSS/SCSS, the production build will swap them around and put the styles commponent at top which usses internal import.

To solve this, in layout.tsx, you want your css/scss to go at the very bottom or the order, then you have to create a new tsx/jsx file and add import statement there and then, import this tsx to layout.

For me my custom style comes to very top and bootstrap overwrites the things.
Screenshot 2023-10-09 at 1 18 39 PM

to solve this,

  1. I have created a styles.tsx file
Screenshot 2023-10-09 at 1 21 33 PM
  1. imported that TSX file into root layout at a specific place where I want.
Screenshot 2023-10-09 at 1 22 40 PM

This solves the problem for me!
Not the ideal solution yes, but it's a work around!

@paulcoyle
Copy link

paulcoyle commented Oct 9, 2023

While not ideal, @Rajankr542's solution works. Though I'm sure anyone who needs to have specific ordering of their globals will be in for some headaches.

Update: unfortunately I think I got lucky with a few builds after trying this method out. It is not deterministic so, effectively, it is not any better. Seems like !important is the only reliable way for now.

@mobob
Copy link

mobob commented Oct 11, 2023

I'm not sure this is 100% related - but i put together a small POC of how css gets reordered differently by NextJS during dev vs prod setups;

https://github.com/mobob/poc-next-css-import-ordering-issue

Essentially what happens is during dev (npm run dev), all the styles of the two buttons are consistent, tailwind is consumed first, and overwritten by Radix themes. But after bundling (npm run build && npm run start), the styles are reversed, for SOME of the buttons.

Happy to be educated otherwise, this could be a tailwind/radix/coding issue, but the fact that deployment config of NextJS is the only variable suggests this issue/Next might be related.

@jessethomson
Copy link

@mobob I have the exact same set up and seeing the exact same thing. And yes, this appears to be an issue with NextJS having different css ordering between dev and prod builds when importing css files.

In case this is helpful for anyone else:

I was able to workaround this issue by:

  1. Installing the postcss-import and adding it to my postcss.config.js
module.exports = {
  plugins: {
    'postcss-import': {},
    tailwindcss: {},
    autoprefixer: {},
  },
};

  1. Importing the @radix-ui/themes/styles.css file inside of my globals.css file, and then using css cascade layers
@layer tw_base, radix_ui, tw_components_utils;
@import "@radix-ui/themes/styles.css" layer(radix_ui);

@layer tw_base {
  @tailwind base;
}

@layer tw_components_utils {
  @tailwind components;
  @tailwind utilities;
}

Credit goes to this article: https://www.frontend.fyi/v/fixing-radix-themes-with-css-cascade-layers

@tr-nhan
Copy link

tr-nhan commented Oct 15, 2023

This bug has not been fixed yet, isn't it?

I am using Next 13 with app router together with CSS libraries such as Bootstrap and Normalize. The thing is, the order of imported CSS files & modules is not consistent. It will change after you hot reload and recompile everything. Thus, no matter I put my CSS file either in layout.tsx or import it as css modules in components, it still creates this bug once I hard compile in a multiple of times

@sanny-io
Copy link

@jessethomson this worked for me too (using Mantine)

What an absolute journey this has been lol. Thanks bro.

@Toshinaki
Copy link

@sanny-io
Could you please share your code?
using Mantine and having same issue.

@sanny-io
Copy link

@Toshinaki I don't know if this is the proper way to do it, but here it is. There's also a separate "layer" css file that Mantine has. Maybe that's also relevant? Not sure.

@layer tailwind_base, mantine, tailwind_components_utilities;
@import '@mantine/core/esm/index.css' layer(mantine);

@layer tailwind_base {
  @tailwind base;
}

@layer tailwind_components_utilities {
  @tailwind components;
  @tailwind utilities;
}

@leerob
Copy link
Member

leerob commented Nov 5, 2023

Closing for #13092, let's continue there please 🙏

@leerob leerob closed this as completed Nov 5, 2023
@LandonSchropp
Copy link

@leerob Not to be pushy, but is there a timeline for addressing the root cause of this issue? Working around it was a bit cumbersome, and I'd love to have this "just work". 🙂

@haydn
Copy link

haydn commented Nov 10, 2023

I haven't actually tested this, but this configuration seems likely to be the root cause:

// Next.js guarantees that CSS order "doesn't matter", due to imposed
// restrictions:
// 1. Global CSS can only be defined in a single entrypoint (_app)
// 2. CSS Modules generate scoped class names by default and cannot
// include Global CSS (:global() selector).
//
// While not a perfect guarantee (e.g. liberal use of `:global()`
// selector), this assumption is required to code-split CSS.
//
// If this warning were to trigger, it'd be unactionable by the user,
// but likely not valid -- so we disable it.
ignoreOrder: true,

The comment in that code pretty clearly states that the behaviour is required for the code splitting to work and makes the assumption that the CSS order won't matter most of the time. I think this issue (and #13092) have proven that assumption incorrect and it's actually important to guarantee the import order. Unfortunately, it also sounds like the fix isn't as simple as changing that config because that would break code splitting.

We haven't heard anything offical from the Next.js team, but I think it's a pretty safe to assume the solution is going to be to switch to Turbopack when it's released, but it'd be great to get conformation on that from the Next.js team so we can plan accordingly.

@Enkratia
Copy link

@haydn, "use client" in code somehow makes disaster with css modules ordering.

Copy link
Contributor

This closed issue has been automatically locked because it had no new activity for 2 weeks. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Nov 28, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
linear: next Confirmed issue that is tracked by the Next.js team. locked Webpack Related to Webpack with Next.js.
Projects
None yet
Development

No branches or pull requests