Description
When a CSS file contains a standalone @layer ordering declaration followed by @layer blocks for the same layer names, transform() (and bundle()) silently drops the ordering declaration from the output — regardless of the minify option.
Environment
- lightningcss:
1.32.0
- Reproduced on:
- macOS 26.3.1, arm64, Node.js v24.13.0
- Linux (Alpine), x86_64, Node.js v24.15.0
- Linux (Alpine), arm64, Node.js v24.15.0
Reproduction
// repro.mjs
import { transform } from "lightningcss";
const input = `
@layer base, layout, components, utils;
@layer base { body { margin: 0; } }
@layer layout { .container { max-width: 1200px; } }
@layer components { .btn { padding: 8px 16px; } }
@layer utils { .hidden { display: none; } }
`.trim();
for (const minify of [false, true]) {
const { code } = transform({
filename: "test.css",
code: Buffer.from(input),
minify,
});
const output = code.toString();
const needle = minify
? "@layer base,layout,components,utils;"
: "@layer base, layout, components, utils;";
console.log(
`minify: ${minify} → ordering preserved: ${output.includes(needle) ? "✓ OK" : "✗ BUG"}`,
);
console.log(output);
console.log("---");
}
$ node repro.mjs
minify: false → ordering preserved: ✗ BUG
@layer base {
body {
margin: 0;
}
}
@layer layout {
.container {
max-width: 1200px;
}
}
@layer components {
.btn {
padding: 8px 16px;
}
}
@layer utils {
.hidden {
display: none;
}
}
---
minify: true → ordering preserved: ✗ BUG
@layer base{body{margin:0}}@layer layout{.container{max-width:1200px}}@layer components{.btn{padding:8px 16px}}@layer utils{.hidden{display:none}}
---
Expected
The ordering declaration @layer base, layout, components, utils; should be preserved in the output
in both minify: false and minify: true modes.
Actual
The ordering declaration is completely absent from the output. The @layer blocks themselves are preserved, so the layers exist but their explicit ordering is gone.
Additional findings
Testing two variations narrows down the trigger:
| Input |
minify: false |
minify: true |
| ordering declaration only (no blocks) |
✓ preserved |
✓ preserved |
| ordering declaration + blocks (original repro) |
✗ dropped |
✗ dropped |
The drop only occurs when the same layer names appear in both the ordering declaration and
subsequent @layer blocks. When the ordering declaration appears alone (no blocks), it is
preserved as expected.
bundle() is also affected:
import { bundle } from "lightningcss";
// with the same input written to a file:
bundle({ filename: "test.css", minify: false });
// → ordering declaration is also dropped
Notes
Per MDN:
"the initial order in which layers are declared indicates which layer has precedence"
A standalone @layer ordering declaration is explicitly described as a mechanism to establish
layer precedence order. This indicates it carries semantic meaning and should be preserved in the output.
Description
When a CSS file contains a standalone
@layerordering declaration followed by@layerblocks for the same layer names,transform()(andbundle()) silently drops the ordering declaration from the output — regardless of theminifyoption.Environment
1.32.0Reproduction
Expected
The ordering declaration
@layer base, layout, components, utils;should be preserved in the outputin both
minify: falseandminify: truemodes.Actual
The ordering declaration is completely absent from the output. The
@layerblocks themselves are preserved, so the layers exist but their explicit ordering is gone.Additional findings
Testing two variations narrows down the trigger:
The drop only occurs when the same layer names appear in both the ordering declaration and
subsequent
@layerblocks. When the ordering declaration appears alone (no blocks), it ispreserved as expected.
bundle()is also affected:Notes
Per MDN:
A standalone
@layerordering declaration is explicitly described as a mechanism to establishlayer precedence order. This indicates it carries semantic meaning and should be preserved in the output.