allow CSS nesting
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.
Source: jaredpalmer/tsdx