Problem Statement
When building a library with tsdx v2, component-level CSS files (those imported directly in .tsx files
like import './drawer.css') are processed by bunchee's inlineCss rollup plugin, which runs clean-css
v5.3.3 with default options (new CleanCSS({})).
clean-css v5.x has no support for native CSS nesting. Its tokenizer only handles { at Level.RULE
for CSS custom property values and @page margin boxes — there is no handler for the native nesting case
(e.g. .foo { &:hover { color: red } }). When it encounters nested { in a rule context, it falls
through to a generic buffer push, corrupting the token stream and silently mangling or dropping the nested
styles in the output.
This means any component-level CSS file that uses native CSS nesting syntax will produce broken output
after the tsdx build, with no error or warning.
Proposed Solution
Replace clean-css with a CSS minifier that supports native CSS nesting, such as Lightning
CSS or cssnano (via PostCSS).
Alternatively, make the CSS minifier configurable so consumers can provide their own.
In bunchee's dist/index.js, the relevant code is:
const cleanCssInstance = new CleanCSS__default.default({});
function minify(code) {
return cleanCssInstance.minify(code).styles;
}
This could be swapped to Lightning CSS:
import { transform } from 'lightningcss';
function minify(code) {
const { code: minified } = transform({
filename: 'style.css',
code: Buffer.from(code),
minify: true,
});
return minified.toString();
}
Lightning CSS has full support for native CSS nesting and is significantly faster than clean-css.
Alternatives Considered
- Pre-flattening nesting with PostCSS/Tailwind before the build: This works for styles that go through a
dedicated CSS compilation step (e.g. Tailwind's --minify flattens nesting), but doesn't help
component-level CSS files that are imported directly in components and processed by bunchee's inlineCss
plugin.
- Disabling CSS minification entirely in bunchee: Avoids the corruption but sacrifices minification for
all CSS.
- Avoiding native CSS nesting in component CSS files: A workaround, but native CSS nesting is a stable
browser feature (supported in all major browsers since Dec 2023) and developers should be able to use it.
Who Benefits?
Any library author using tsdx/bunchee who wants to use native CSS nesting in component-level CSS files. As
CSS nesting adoption grows (it's now baseline across all major browsers), this will affect an increasing
number of users.
Additional Context
- clean-css v5.x is effectively in maintenance mode and has no plans to add nesting support — the
tokenizer's Level system would require a significant architectural rewrite.
- bunchee v6.9.4 pins clean-css: ^5.3.3 as a direct runtime dependency.
- tsdx v2.0.0 delegates entirely to bunchee via execa("bunchee").
- The issue is silent — clean-css produces corrupted output without any errors or warnings, making it
difficult to diagnose.
Problem Statement
When building a library with tsdx v2, component-level CSS files (those imported directly in
.tsxfileslike
import './drawer.css') are processed by bunchee'sinlineCssrollup plugin, which runsclean-cssv5.3.3 with default options (
new CleanCSS({})).clean-css v5.x has no support for native CSS nesting. Its tokenizer only handles
{atLevel.RULEfor CSS custom property values and
@pagemargin boxes — there is no handler for the native nesting case(e.g.
.foo { &:hover { color: red } }). When it encounters nested{in a rule context, it fallsthrough to a generic buffer push, corrupting the token stream and silently mangling or dropping the nested
styles in the output.
This means any component-level CSS file that uses native CSS nesting syntax will produce broken output
after the tsdx build, with no error or warning.
Proposed Solution
Replace clean-css with a CSS minifier that supports native CSS nesting, such as Lightning
CSS or cssnano (via PostCSS).
Alternatively, make the CSS minifier configurable so consumers can provide their own.
In bunchee's
dist/index.js, the relevant code is:This could be swapped to Lightning CSS:
Lightning CSS has full support for native CSS nesting and is significantly faster than clean-css.
Alternatives Considered
dedicated CSS compilation step (e.g. Tailwind's --minify flattens nesting), but doesn't help
component-level CSS files that are imported directly in components and processed by bunchee's inlineCss
plugin.
all CSS.
browser feature (supported in all major browsers since Dec 2023) and developers should be able to use it.
Who Benefits?
Any library author using tsdx/bunchee who wants to use native CSS nesting in component-level CSS files. As
CSS nesting adoption grows (it's now baseline across all major browsers), this will affect an increasing
number of users.
Additional Context
tokenizer's Level system would require a significant architectural rewrite.
difficult to diagnose.