vite
vite copied to clipboard
CSS `@layer` bundling misses selectors inside media queries
Describe the bug
@import 'layers.css' layer(demo);
where layers.css
contains:
h1 {
color: red;
}
@media (min-width: 100px) {
h1 {
color: green;
}
}
incorrectly produces:
@layer demo {
h1 {
color: red;
}
}
@media (min-width: 100px) {
h1 {
color: green;
}
}
instead of (this is just one correct way):
@layer demo {
h1 {
color: red;
}
@media (min-width: 100px) {
h1 {
color: green;
}
}
}
This means any media queries are unlayered, giving them the top most precedence and specificity over styles in layers.
Vanilla Vite example: https://stackblitz.com/edit/vitejs-vite-vlemhc?file=layers.css,style.css Demo: https://vitejs-vite-vlemhc--5173.local.webcontainer.io/
I'd like a way to disable it for now, but don't see one.
Reproduction
https://stackblitz.com/edit/vitejs-vite-vlemhc?file=layers.css,style.css
System Info
System:
OS: macOS 12.4
CPU: (16) x64 Intel(R) Xeon(R) W-2140B CPU @ 3.20GHz
Memory: 799.40 MB / 64.00 GB
Shell: 3.2.57 - /bin/bash
Binaries:
Node: 18.2.0 - /usr/local/bin/node
npm: 8.9.0 - /usr/local/bin/npm
Browsers:
Chrome: 103.0.5060.134
Chrome Canary: 106.0.5201.0
Firefox: 102.0.1
Firefox Developer Edition: 102.0
Firefox Nightly: 103.0a1
Safari: 15.5
Safari Technology Preview: 15.4
npmPackages:
vite: 3.0.2 => 3.0.2
Used Package Manager
npm
Logs
No response
Validations
- [X] Follow our Code of Conduct
- [X] Read the Contributing Guidelines.
- [X] Read the docs.
- [X] Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.
- [X] Make sure this is a Vite issue and not a framework-specific issue. For example, if it's a Vue SFC related bug, it should likely be reported to vuejs/core instead.
- [X] Check that this is a concrete bug. For Q&A open a GitHub Discussion or join our Discord Chat Server.
- [X] The provided reproduction is a minimal reproducible example of the bug.
I suspect this will be fixed by : https://github.com/postcss/postcss-import/pull/496 Haven't verified this but it seems to be the same issue and vite uses postcss-import.
Currently (v3.0.3), both in a <style>
tag or in a linked CSS file the import rule:
@import url("https://unpkg.com/open-props/") layer(designsystem);
results in
@import url("https://unpkg.com/open-props/");
Basically importing without the layer.
A fix was released in postcss-import
as v15.0.0
https://github.com/postcss/postcss-import/blob/master/CHANGELOG.md#1500--2022-08-30
@sapphi-red Does this require an update in vite before end users can use this updated version?
@romainmenke Thanks! Yes, this requires an update in Vite.
@sapphi-red I don't know anything about Vite so maybe this doesn't make sense, but can end users easily pass plugin options to postcss-import
or does Vite do all the configuration?
@romainmenke Vite does all the configuration and currently it does not allow any configuration from users. Also Vite is shipped with postcss-import bundled in. So users cannot use the new version until a new release is cut.
In that case it is important to set a new plugin option for anonymous cascade layers : nameLayer
postcss-import
needs to desugar anonymous layers to uniquely named layers but it doesn't have enough information about how it is used to generate these unique names.
example from the tests : https://github.com/postcss/postcss-import/blob/master/test/layer.js#L67-L80
example from the postcss-preset-env
site :
const crypto = require('crypto');
const cwd = process.cwd();
module.exports = ctx => {
const isProd = ctx.env === 'production';
return {
map: !isProd,
plugins: {
'postcss-import': {
nameLayer: hashLayerName,
},
'postcss-preset-env': {
stage: 0,
preserve: true,
features: {
'custom-properties': false,
'custom-media-queries': {
preserve: false,
},
},
},
'cssnano': isProd ? {
preset: 'default',
} : false,
},
};
};
function hashLayerName(index, rootFilename) {
if (!rootFilename) {
return `import-anon-layer-${index}`;
}
// A stable, deterministic and unique layer name:
// - layer index
// - relative rootFilename to current working directory
return `import-anon-layer-${crypto
.createHash('sha256')
.update(`${index}-${rootFilename.split(cwd)[1]}`)
.digest('hex')
.slice(0, 12)}`;
}
@romainmenke I see. Thank you very much for the explanation!
@argyleink v3.1.0 was released today. Would be awesome if you could try this version to verify that this is now fully fixed.
bug is fixed 👍🏻