vercel / next.js

The React Framework
https://nextjs.org
MIT License
122.59k stars 26.23k forks source link

Production CSS optimization breaks nesting of at-rules #67193

Open brian123zx opened 3 days ago

brian123zx commented 3 days ago

Link to the code that reproduces this issue

https://codesandbox.io/p/devbox/css-module-compilation-mashing-ghp469

To Reproduce

  1. Build the app
  2. Run the app
  3. Load the default page
  4. Resize the window across the 300px width boundary

Current vs. Expected behavior

The background color of the centered div is expected to be red at all screen widths, but isn't.

Provide environment information

Operating System:
  Platform: linux
  Arch: x64
  Version: #1 SMP PREEMPT_DYNAMIC Sun Aug  6 20:05:33 UTC 2023
  Available memory (MB): 4102
  Available CPU cores: 2
Binaries:
  Node: 20.11.1
  npm: 10.2.4
  Yarn: 1.22.19
  pnpm: 8.15.4
Relevant Packages:
  next: 14.2.4 // Latest available version is detected (14.2.4).
  eslint-config-next: 14.2.1
  react: 18.2.0
  react-dom: 18.2.0
  typescript: 5.3.3
Next.js Config:
  output: N/A

Which area(s) are affected? (Select all that apply)

Webpack

Which stage(s) are affected? (Select all that apply)

next build (local)

Additional context

A CSS module defined as

.backgroundMobile {
  @media (max-width: 300px) {
    background-color: red;
  }
}
.backgroundDesktop {
  @media (min-width: 301px) {
    background-color: red;
  }
}

gets compiled to a single rule

.page_backgroundDesktop___7nSc, .page_backgroundMobile__9v2l5 {
    @media (min-width: 301px) {
        background-color: red;
    }
}

It appears the media query is ignored when determining how to optimize the CSS. CSS nesting is a new feature, but nesting @ rules is part of the spec (MDN). It looks like nextjs uses postcss-nested, which I suspect is where the root issue is, but that package looks to be unmaintained, not updated in over a year, in favor of postcss-nesting, which is intended to implement the draft spec.

Workarounds

Reorder css nesting

Reordering the nesting as

@media (max-width: 300px) {
  .backgroundMobile {
    background-color: red;
  }
}
@media (min-width: 301px) {
  .backgroundDesktop {
    background-color: red;
  }
}

appears to compile correctly

Add postcss-nesting plugin

Adding "plugins": ["postcss-nesting"] to postcss.config.js causes the css to be compiled correctly.