mui / pigment-css

Pigment CSS is a zero-runtime CSS-in-JS library that extracts the colocated styles to their own CSS files at build time.
MIT License
782 stars 38 forks source link

Component styles are overridden when rendered inside Next.js layout #199

Closed corydeppen closed 1 month ago

corydeppen commented 2 months ago

Steps to reproduce

Review the styles being applied to the nav links in the mobile appbar of both Next.js and Vite versions of the example app. Observe how the styles are incorrect when on the home page of the Next app but are correct on the about page.

Current behavior

I've run into an issue that appears when using the Next.js plugin but doesn't exist when using the Vite plugin. As you'll see in the example app, the nav links in the appbar drawer on mobile don't have the correct alignment or padding specified by the ListItemButton styles. However, if you flip to the About page and inspect the links in the drawer, you'll see the ListItemButton styles are being applied as expected.

From what I can tell, it looks like the Next.js plugin is generating styles at a route file level (e.g. page.tsx, layout.tsx) instead of at a component/module level like the Vite plugin appears to do. In the Next app, (public)/page.tsx has another Button on the page so the base button styles from page.tsx take precedence over the styles being generated for layout.tsx that renders the SiteAppBar component containing the links. In the Vite example app, though, the styles are being generated separately for the site-app-bar.tsx module and take precedence so the ListItemButton alignment and padding are applied as expected.

Expected behavior

Styles for components rendered within Next.js layout components should not be overridden by those in page components.

Context

No response

Your environment

npx @mui/envinfo ``` System: OS: Linux 5.0 undefined Binaries: Node: 18.20.3 - /usr/local/bin/node npm: 10.2.3 - /usr/local/bin/npm pnpm: 8.15.6 - /usr/local/bin/pnpm Browsers: Chrome: Not Found npmPackages: @emotion/react: 11.13.0 @emotion/styled: 11.13.0 @mui/core-downloads-tracker: 6.0.0-dev.240424162023-9968b4889d @mui/icons-material: 6.0.0-beta.4 => 6.0.0-beta.4 @mui/material: 6.0.0-beta.4 => 6.0.0-beta.4 @mui/material-pigment-css: 6.0.0-beta.4 => 6.0.0-beta.4 @mui/private-theming: 6.0.0-beta.4 @mui/styled-engine: 6.0.0-beta.4 @mui/system: 6.0.0-beta.4 @mui/types: 7.2.15 @mui/utils: 6.0.0-beta.4 @types/react: ^18.2.47 => 18.3.3 react: ^18.2.0 => 18.3.1 react-dom: ^18.2.0 => 18.3.1 ```

Search keywords: nextjs vite plugin layout components override

corydeppen commented 2 months ago

This appears to only be an issue when building for development. If I build for production, the style sheets are generated as expected and don't cause the precedence issue that I'm seeing in development. For example, in dev, the ButtonBase styles are being generated and included in both layout.css and page.css files. However, those styles are only included in a single generated file when building for prod and allow more specific styles to be applied by style sheets being included later in the document.

siriwatknp commented 2 months ago

I am using AppBar is an example here. The AppBar is a component that wraps Paper and override the background. In Next.js app router, AppBar is used in layout.tsx and then a Paper is used in page.tsx.

The root cause comes from the styles of the Paper being generated to both layout.css and page.css and Next.js orders the <link> by loading the layout.css before page.css (meaning page.css has higher priority than layout.css for the same classes):

Because the produced HTML of AppBar includes classes of the Paper like this:

<div class="appbar paper">

// layout.css
.paper { background: white };
.appbar { background: blue };

// page.css 
.paper { background: white };

This causes .paper in page.css to win the .appbar in layout.css.

image

In production, the CSS files are built with a different process, so there are no duplicate CSS however, there is a possibility that the order of the might be different.

Update

This issue involves Next.js because page.tsx is processed before layout.tsx. This makes it hard for Pigment CSS to know if Paper is already used in the upper layout or not.

royporter7 commented 2 months ago

Just bumped into this bug as well with my project. Would love to see it resolved.

brijeshb42 commented 2 months ago

Hey folks. I am looking into this.