System Info
System:
OS: macOS 26.6
CPU: (15) arm64 Apple M5 Pro
Binaries:
Node: 24.15.0
npm: 11.12.1
Browsers:
Chrome: 150.0.7871.125
Firefox: 151.0.4
Safari: 26.5
npmPackages:
@rspack/cli: 2.1.4
@rspack/core: 2.1.4
Details
When LightningCssMinimizerRspackPlugin is used without minimizerOptions.targets, and the project's target is not a browserslist-related value (e.g. the default target: "web"), the plugin falls back to targets: ["fully supports es6"] — a ~2015-era browser baseline.
With that baseline, Lightning CSS treats modern CSS as something it must downlevel for old browsers, so it expands rules instead of shrinking them. Modern logical / RTL syntax is the worst case:
text-align: start / end → duplicated into LTR and RTL rules gated on a 19-entry :lang(...) list
:dir(rtl) → rewritten to that same :lang(...) list
- each such rule is then emitted three times, once for
:-webkit-any(), :-moz-any(), and :is()
- logical box properties (
padding-inline-*, border-block-*, …) → expanded to physical pairs
For a stylesheet that leans on these features, minified output can be larger than the unminified input. In the minimal repro, a 1.3 KB stylesheet becomes 12 KB after minification (9.2×). On a real app using a component library with pervasive logical/RTL CSS (CloudScape), this inflated total emitted CSS ~2.7× versus webpack 5 (9.8 MB → 3.6 MB); webpack's cssnano-based minifier reads browserslist and does not downlevel.
Reproduces identically on the css-loader + CssExtractRspackPlugin chain and on native experiments.css, confirming it is the minimizer, not the CSS pipeline.
This is partly a docs issue. The plugin docs point the wrong way on two counts:
- They say the ES6 fallback "ensures that minification does not introduce advanced syntax that could cause browser incompatibility." In practice the fallback causes aggressive downleveling that multiplies rule count and inflates size. The size cost of the fallback isn't mentioned and is easy to hit by accident.
- They say the plugin "excludes all features by default to avoid syntax downgrading during the minimize process." This does not match observed behavior — with no
exclude set, downgrading clearly still happens. Either the default isn't actually "exclude all features", or the sentence needs correcting.
Workaround: pass explicit targets (any browserslist query, or your project's browserslist config):
new rspack.LightningCssMinimizerRspackPlugin({
minimizerOptions: { targets: ["chrome >= 120", "firefox >= 120", "safari >= 17"] },
});
This restores expected behavior (in the real app, it shrank CSS below webpack's output).
Suggested resolution (docs, and optionally code):
- Warn on the plugin page that when
targets is unset and target is not browserslist-related, the "fully supports es6" fallback can significantly increase CSS size by downleveling modern syntax; recommend setting minimizerOptions.targets.
- Reconcile the "excludes all features by default" sentence with actual behavior (if downgrading happens by default, that's either a docs error or a code bug).
- On the target inheritance page, make explicit that
target: "web" (and other non-browserslist targets) does not feed targets into the CSS minimizer, so the ES6 fallback applies.
- Optionally, consider defaulting the minimizer's
targets to the project's resolved browserslist when available (matching css-minimizer-webpack-plugin/cssnano and builtin:lightningcss-loader).
Reproduce link
https://github.com/TrevorBurnham/rspack-css-minrepro
Reproduce Steps
npm install
npm run build # default targets -> dist/main.css
npm run build:fixed # explicit modern targets -> dist-fixed/main.css
npm run measure
Observed (@rspack/core@2.1.4; also present in 2.1.2):
variant | CSS bytes | :-webkit-any( expansions
-------------------------------------|-----------|-------------------------
source styles.css | 1314 | 0
minified (default targets, BUGGY) | 12093 | 16
minified (modern targets, FIXED) | 490 | 0
BUG: minified output is 9.20x the size of the unminified source.
npm run build:native (native experiments.css, no css-loader) produces byte-identical bloat (12,093 bytes), confirming the issue is in the minimizer.
System Info
Details
When
LightningCssMinimizerRspackPluginis used withoutminimizerOptions.targets, and the project'stargetis not a browserslist-related value (e.g. the defaulttarget: "web"), the plugin falls back totargets: ["fully supports es6"]— a ~2015-era browser baseline.With that baseline, Lightning CSS treats modern CSS as something it must downlevel for old browsers, so it expands rules instead of shrinking them. Modern logical / RTL syntax is the worst case:
text-align: start/end→ duplicated into LTR and RTL rules gated on a 19-entry:lang(...)list:dir(rtl)→ rewritten to that same:lang(...)list:-webkit-any(),:-moz-any(), and:is()padding-inline-*,border-block-*, …) → expanded to physical pairsFor a stylesheet that leans on these features, minified output can be larger than the unminified input. In the minimal repro, a 1.3 KB stylesheet becomes 12 KB after minification (9.2×). On a real app using a component library with pervasive logical/RTL CSS (CloudScape), this inflated total emitted CSS ~2.7× versus webpack 5 (9.8 MB → 3.6 MB); webpack's cssnano-based minifier reads browserslist and does not downlevel.
Reproduces identically on the
css-loader+CssExtractRspackPluginchain and on nativeexperiments.css, confirming it is the minimizer, not the CSS pipeline.This is partly a docs issue. The plugin docs point the wrong way on two counts:
excludeset, downgrading clearly still happens. Either the default isn't actually "exclude all features", or the sentence needs correcting.Workaround: pass explicit targets (any browserslist query, or your project's browserslist config):
This restores expected behavior (in the real app, it shrank CSS below webpack's output).
Suggested resolution (docs, and optionally code):
targetsis unset andtargetis not browserslist-related, the"fully supports es6"fallback can significantly increase CSS size by downleveling modern syntax; recommend settingminimizerOptions.targets.target: "web"(and other non-browserslist targets) does not feed targets into the CSS minimizer, so the ES6 fallback applies.targetsto the project's resolvedbrowserslistwhen available (matchingcss-minimizer-webpack-plugin/cssnano andbuiltin:lightningcss-loader).Reproduce link
https://github.com/TrevorBurnham/rspack-css-minrepro
Reproduce Steps
Observed (
@rspack/core@2.1.4; also present in 2.1.2):npm run build:native(nativeexperiments.css, no css-loader) produces byte-identical bloat (12,093 bytes), confirming the issue is in the minimizer.