vitejs / vite

Next generation frontend tooling. It's fast!
http://vitejs.dev
MIT License
67.06k stars 6.02k forks source link

PostCSS not applied to imports via `composes` #10079

Open elisehein opened 1 year ago

elisehein commented 1 year ago

Describe the bug

I'm trying to have styles included in a CSS module via composes processed by PostCSS, but it's not happening. All other styles are processed by PostCSS correctly.

Take the following CSS modules and PostCSS config:

{
  "plugins": {
    "postcss-preset-env": {
      "browsers": "defaults, ie >= 11",
      "importFrom": [
        "./src/variables.css"
      ]
    },
    "postcss-nested": { }
  }
}
/* variables.css */
:root {
  --color-red: red;
  --color-blue: blue;
}

/* component.module.css */
.component {
  color: var(--color-red);

  .nested {
    width: 100%;
  }
}

/* main.module.css */
.main {
  composes: component from "./component.module.css";
  color: var(--color-blue);

  .nested {
    display: block;
  }
}

Expected result

I exect to see the styles I include with .main via `composes: component from "./component.module.css" to be valid (with PostCSS plugins applied). Expected result:

 ._component_xs2hm_5 {
  color: red;
  color: var(--color-red);
 }

 ._component_xs2hm_5 ._nested_xs2hm_13 {
  width: 100%;
}

._foo_1mrk0_1 {
  color: blue;
  color: var(--color-blue);
}

._foo_1mrk0_1 ._nested_1mrk0_7 {
  width: 100%;
}

Actual result

The styles included via composes are not processed by PostCSS. They are included in the <style> tag as-is, resulting in invalid CSS.

 ._component_xs2hm_5 {
  color: var(--color-red);

  ._nested_xs2hm_13 {
    width: 100%;
  }
}

._foo_1mrk0_1 {
  color: blue;
  color: var(--color-blue);
}

._foo_1mrk0_1 ._nested-bar_1mrk0_7 {
  width: 100%;
}

The same bug can be observed in the production build.

There was a similar issue logged and fixed in vue-loader: https://github.com/vuejs/vue-loader/issues/959

Reproduction

https://github.com/elisehein/vite-postcss-compose-repro

System Info

System:
    OS: macOS 12.4
    CPU: (10) arm64 Apple M1 Pro
    Memory: 721.78 MB / 32.00 GB
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 16.16.0 - ~/.asdf/installs/nodejs/16.16.0/bin/node
    Yarn: 1.22.10 - /usr/local/bin/yarn
    npm: 8.15.0 - ~/.asdf/plugins/nodejs/shims/npm
    Watchman: 2022.05.16.00 - /usr/local/bin/watchman
  Browsers:
    Firefox: 103.0.2
    Safari: 15.5
    Safari Technology Preview: 15.4
  npmPackages:
    @vitejs/plugin-legacy: ^1.8.2 => 1.8.2 
    @vitejs/plugin-react: ^1.0.0 => 1.3.2 
    vite: ^3.0.2 => 3.1.0

Used Package Manager

npm

Logs

No response

Validations

sapphi-red commented 1 year ago

Vite puts postcss plugins in the following order.

[postcssImport, postcssModules, ...userPlugins, postcssViteRewriteUrl]

In this order ([postcssModules, postcssNested]), the output is:

._component_8abi2_1 {
  color: var(--color-red);

  ._nested_8abi2_7 {
    width: 100%;
  }
}

._foo_15itx_1 {
  color: red;
}

But when the order is [postcssNested, postcssModules], the output is:

._component_8abi2_1 {
  color: var(--color-red);
}._component_8abi2_1 ._nested_8abi2_7 {
    width: 100%;
  }._foo_15itx_1 {
  color: red;
}

stackblitz

So I think we need an option to apply a plugin before default ones, or reorders the plugins.

patak-dev commented 1 year ago

We had a related PR to change the order of PostCSS plugins, and have the user ones before the internal ones:

In that case, it was closed because the issue should have been fixed upstream. But it could count as another case where having the chance to inject plugins before Vite plugins could have been useful. Maybe we could have a { order: 'pre', ...plugin } for PostCSS plugins too?

sapphi-red commented 1 year ago

I took a look around postcss plugin specs. Maybe it's possible to solve on plugins' side?

https://github.com/postcss/postcss/releases/tag/8.0.0#:~:text=Plugins%20will%20re%2Dvisit%20changed%20nodes%20to%20reduce%20compatibility%20issues%20between%20plugins.%20Now%20the%20order%20of%20plugins%20in%20your%20PostCSS%20config%20will%20be%20less%20important.

764 #296

I feel it's better to avoid extending the plugin interface of PostCSS.

patak-dev commented 1 year ago

Another point in favor of waiting here is that there is a chance we end up replacing PostCSS with LigthingCSS in the future

basmilius commented 1 year ago

Another point in favor of waiting here is that there is a chance we end up replacing PostCSS with LigthingCSS in the future

Any news on when this will happen? I'm deciding if it's worth waithing for a fix to this issue or just go with plain old css :)

Inok commented 1 year ago

The current approach with postcss-modules running as the first plugin seems wrong because postcss doesn't apply user plugins in that case. Now it's either composes X from '...' or other plugins, but not both. Or at least composed file must be a native CSS file because it won't be processed anyway.

Precisely, now I can't compose a rule from another module and customize that rule with a custom media query at the same time.

Is there any chance that the issue will be fixed somehow?

alkorlos commented 1 year ago

@patak-dev LigthingCSS faster then PostCSS and probably LigthingCSS or CSSTree better for minifying and other tasks. But not LigthingCSS or CSSTree have not so many plugins as PostCSS. And LigthingCSS written in rust, plugins for it can be written on JS, but it's harder than PostCSS.

It is unlikely that in the near future it will be possible to completely abandon PostCSS, while there is no support injecting plugins before except this

[postcssImport, postcssModules, ...userPlugins, postcssViteRewriteUrl]

This isuue and #12336 will be relevant.

privatenumber commented 6 months ago

I've implemented a fix via https://github.com/privatenumber/vite-css-modules (which is getting integrated into Vite core via https://github.com/vitejs/vite/pull/16018).

Testing and feedback will be appreciated!