-
Notifications
You must be signed in to change notification settings - Fork 26.3k
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
[NEXT-1308] Css is imported multiple times and out of order in /app dir #51030
Comments
This PR #50406 seems like it should have fixed this issue, but I see the problem in my repro repositories |
CSS modules seem to be working ok. Removed vanilla-extract from this repro, and imported the same CSS from CSS module in the page and layout, and set it on the Edit: it works like that if both the page and layout are RSC. When I use |
This issue is still present in the latest canary (13.4.7-canary.1)
Here is a minimal repro with easy-to-reproduce test cases. https://codesandbox.io/p/sandbox/next-51030-hlj722?file=%2Fapp%2Fpage.tsx%3A1%2C1 |
The current order of imports wreaks havoc when CSS Cascade Layers are being used. The defined layer precedence that belongs in the root layout file gets read after the application of layers in child components. This causes the defined layer precedence to be ignored in favor of something random (https://css-tricks.com/css-cascade-layers/#aa-establishing-a-layer-order), and can make routes unusable. This issue surfaced for me when updating up from 13.4.4 to 13.4.5 or 13.4.6. |
One workaround I'm currently using is to make the children CSS more specific: |
For https://codesandbox.io/p/sandbox/next-51030-hlj722?file=%2Fapp%2Fpage.tsx%3A1%2C1, it becomes very tricky if your CSS code itself has conflicts and some behaviors are undefined. For example when a dynamic component has loaded, its CSS might cause side effects to other parts of the page, which is expected. For example, if you have a layout like this: import style1 from 'a.module.css'
import style2 from 'b.module.css'
<button className={style1.btn + ' ' + style2.btn}> The styles that imports later will override previous ones, so In general, we recommend you to use CSS |
@shuding, I appreciate you taking the time to look into this example.
I wouldn't call styles override a conflict. Overriding base component styles in a descendant component is a pretty common technique. Isn't that what "C" in CSS stands for?
The above example is a module-scoped CSS that doesn't have any global side-effects.
Yes, you are absolutely correct, and that's the desired behavior that we are unfortunately not able to achieve under the app router.
In theory, yes. But it's not the case in the above example, isn't it? |
@shuding if you'll please read my comment below,
|
Thanks! I'll go through all the reproductions and think about an improvement in the next couple of days! I understand that the confusion caused by the new architecture. In general scoped CSS itself doesn't have conflicts, but the order and duplication might cause the styles to conflict (override each other). I'll give you an example: layout: → layout.css If the module that contains the However when page is rendered, Previously in the pages directory, all styles will be packed into one CSS file. But here we need to generate one CSS per layout and page because they can be loaded separately. That said, we still have some ideas to improve it. Like changing the CSS modules hashing algorithm to make it base on the layer, or deduplicate styles that are already in its parent layer. Will keep you updated in this issue. |
If I understand the latter suggestion correctly, this seems to me like the right approach. If a build system produces hashed rule/class names based on the rule contents (e.g., To your point, if there's perfect purity, this won't be a problem, but it's also reasonably unrealistic that there wouldn't be things like rules applied to descendent selectors (and probably some non-negigible number of other scenarios) on class names that have a high likelihood of their precedence being trumped by the same properties in a rule duplicated in |
I'm also encountering the same behaviour. For my use case, I'm creating standard UI/layout components that I want to use across multiple pages and components – these components have The problem is, as mentioned above, changing between routes/different app runs can result in different CSS load orders in addition to a huge amount of duplicate CSS. For example: // components/layout/Section.tsx
import styles from '../../styles/layout/Section.module.css';
interface Props extends React.ComponentProps<'section'> {
fullWidth?: boolean;
}
export default function Section(props: Props) {
const { fullWidth, ...remainingProps } = props;
return (
<section
{...remainingProps}
className={[styles['section'], props.className].join(' ')}
data-fullwidth={fullWidth}
>
{props.children}
</section>
);
} Navigating from For now, as a partial fix, I have managed to use css Would be interested to know if there is a better way to go about this. I can provide more detailed examples/reproductions if necessary. |
Have a quick hack fix for the css layer order here #16630 (comment) |
This reverts commit af98261. Currently, importing 'normalize.css' is causing inconsistent styles (see: vercel/next.js#51030)
Is there already a solution for css that is loaded multiple times if you use the "use client" mode? |
I just ended up writing a simple Webpack plugin that removes duplicate rules by their class names (which isn't a good idea in pratice, but has worked well enough for my needs). I've only tested this with CSS generated with Vanilla Extract, and it doesn't support route groups, but someone may find it useful. |
Maybe not the best solution for now, but converting to the pages router fixed it for me. |
@katiasmet-93, your solution might be suitable for projects with a small codebase where there's no need for testing investments. But such thoughts really make one reconsider completely dropping Next. |
I have the same problem when using shared components in layouts and pages (next 13.4.19). It doesn't work correctly both when using CSS modules and when using tailwind. |
Same issue with mantine #16630 (comment) |
I updated to the latest and am still seeing this issue. Whenever the layout file uses a component that has |
To help with this issue, we're inserting our layer order onto every css file so the import order won't affect layer via next config and the BannerPlugin:
|
I also read up about using |
## What's the purpose of this pull request? This PR aims to: - [x] add the tsconfig needed to run Next 13. It also set `"strictNullChecks": false` to make the Section Override v2 API work as previously. - [x] Fix styles order problem by adding webpack config in next.config.js. See vercel/next.js#51030 (comment) - [x] adds the initial prefix folder, root layout and initial page layout ## How to test it? run locally and you should see the initial structure under: http://localhost:3000/fs-next-update ### Starters Deploy Preview <!--- Add a link to a deploy preview from `gatsby.store` AND `nextjs.store` with this branch being used. ---> <!--- Tip: You can get an installable version of this branch from the CodeSandbox generated when this PR is created. ---> ## References Next 13 file conventions https://nextjs.org/docs/app/api-reference/file-conventions/layout CSS order issues: [[NEXT-1308] Css is imported multiple times and out of order in /app dir · Issue #51030 · vercel/next.js](vercel/next.js#51030 (comment)) [Verify CSS import ordering · Issue #16630 · vercel/next.js](vercel/next.js#16630) [CSS "@import <file> layer()" isn't working · Issue #55763 · vercel/next.js](vercel/next.js#55763) [[NEXT-1308] Css is imported multiple times and out of order in /app dir · Issue #51030 · vercel/next.js](vercel/next.js#51030 (comment)) strictNullChecks vercel/next.js#39942 https://www.typescriptlang.org/tsconfig/#strictNullChecks
Does not seem to work great; when switching between pages, it's missing styles from the css bundle. Only once the page has been rendered at least once, it will be in the bundle |
Hi everyone! We landed some fixes with v15.0.0-canary.10. Taking a look at some |
Hi @samcx , |
@Netail Yeah can confirm we're still seeing issues—I've already let the team know and we're digging ( |
@samcx do you happen to know if it's possible to fallback on non-streaming CSS (the original way) for now? Where it would send a single CSS file per path |
@samcx Sadly not, feels like it makes it even worse if I look at the css order. So basically a server component uses a certain component styling, with some overwriting, these get added to the bundle. Then a client component renders which also uses the component styling, so this styling then gets added at the bottom (while it was already in the bundle), thus overwriting the overwrited component styling to the original styling. But was more looking for a fallback solution (till this get sorted) where it would bundle the full page css in 1 css file, like the old school days. It ofc creates a bigger payload, but at least fixes the issue for now Maybe I have some time tomorrow to help create some test cases in here, which can help you guys when fixing the issue? |
This PR aims to: - [x] add the tsconfig needed to run Next 13. It also set `"strictNullChecks": false` to make the Section Override v2 API work as previously. - [x] Fix styles order problem by adding webpack config in next.config.js. See vercel/next.js#51030 (comment) - [x] adds the initial prefix folder, root layout and initial page layout run locally and you should see the initial structure under: http://localhost:3000/fs-next-update <!--- Add a link to a deploy preview from `gatsby.store` AND `nextjs.store` with this branch being used. ---> <!--- Tip: You can get an installable version of this branch from the CodeSandbox generated when this PR is created. ---> Next 13 file conventions https://nextjs.org/docs/app/api-reference/file-conventions/layout CSS order issues: [[NEXT-1308] Css is imported multiple times and out of order in /app dir · Issue #51030 · vercel/next.js](vercel/next.js#51030 (comment)) [Verify CSS import ordering · Issue #16630 · vercel/next.js](vercel/next.js#16630) [CSS "@import <file> layer()" isn't working · Issue #55763 · vercel/next.js](vercel/next.js#55763) [[NEXT-1308] Css is imported multiple times and out of order in /app dir · Issue #51030 · vercel/next.js](vercel/next.js#51030 (comment)) strictNullChecks vercel/next.js#39942 https://www.typescriptlang.org/tsconfig/#strictNullChecks
Tried to make a test case in the next.js repo for my issue in, but wasn't able to reproduce it in there as tests first build a production build before the test are ran? My issue only applies to development mode |
@samcx Thank you! When does
|
I am a maintainer on an open-source UI library, here's the docs website that runs on next 14 and is having this issue that's been discussed since over a year, we've no idea how to fix this |
Yeah this issue has been going on since v13 (2 major versions) already :( |
I don't understand how this issue is not prioritised. It breaks so many projects in unpredictable ways, basically everything that does not import one CSS file like Tailwind. |
I have These both files contains the same spinner code I just can't figure why is it like this
|
@kutsan The team was recently had an offsite, and then I was PTO for a week—we're back to tackling this issue! Sorry for the lack of an update.
We are indeed prioritizing this! |
A report back from the last time I commented: I am working on a greenfield project and therefore has the ability to put in some mandates early on, and it seems that implementing CSS This still only fixes the symptoms of having duplicate CSS being loaded, but now that all our components have mandatory Our next.js config looks like this: /**
* @type {import('@nx/next/plugins/with-nx').WithNxOptions}
*/
const nextConfig = {
...restOfTheConfig,
webpack: (config) => {
config.plugins = [
...(config.plugins ?? []),
new webpack.BannerPlugin({
banner: `@layer ${CSS_LAYER_NAMES.join(', ')};`,
test: /\.s?css$/,
raw: true,
entryOnly: false,
}),
];
return config;
},
}; And export const CSS_LAYER_NAMES = [
'reset',
'headless',
'design-system',
'component',
'app'
] as const; Our CSS reset looks like this: @layer reset {
*, *::before, *::after {
box-sizing: border-box;
}
} And our @layer design-system { ... }
/* Used by components built on top of design system */
@layer component { ... }
/* Used by page/layout.tsx as a top-level override */
@layer app { ... } |
Ok back with a report!
This So far, I think the pressing issues that are actively known with confirmed
|
Yes :) Might be related to one of the other reported issues tho, but not 100% sure |
On Next 14 🫠
|
@samcx Man, you're my hero, thank you! Eslint simple-import-sort plugin screwed me over 🥲 Disabled it in layout.tsx with |
Verify canary release
Provide environment information
Which area(s) of Next.js are affected? (leave empty if unsure)
App directory (appDir: true)
Link to the code that reproduces this issue or a replay of the bug
https://github.com/ssijak/next-css-issue-not-working-simple
To Reproduce
Just start the app and check the styling on the buttons. Styles are imported multiple times wherever
Button
was used (page and layout) and order is also not deterministic, so it can be imported in different order on different app runs.This is another/same simple repro difference is just that it uses turbo and transpiles the UI lib, I started with that but figured that the issue is happening without it too https://github.com/ssijak/next-css-issue-not-working
Describe the Bug
-Same styles are imported multiple times
-Order of imports is not deterministic
Screenshot: https://share.cleanshot.com/nq35j7vh
Expected Behavior
Same styles should be imported once. Starting the app multiple times should not produce different results (ordering of CSS, impacting specificity)
Which browser are you using? (if relevant)
No response
How are you deploying your application? (if relevant)
No response
From SyncLinear.com | NEXT-1308
The text was updated successfully, but these errors were encountered: