Skip to content

Commit 35bef69

Browse files
feat(css): add PostCSS support with css.transformer option (#791)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent e4cbeca commit 35bef69

31 files changed

+951
-185
lines changed

docs/options/css.md

Lines changed: 140 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,19 @@ CSS support in `tsdown` is still an experimental feature. While it covers the co
55
> [!WARNING] Experimental Feature
66
> CSS support is experimental. Please test thoroughly and report any issues you encounter. The API and behavior may change as the feature matures.
77
8+
## Basic vs Advanced CSS
9+
10+
`tsdown` provides two levels of CSS support:
11+
12+
- **Built-in (basic):** CSS file extraction and bundling works out of the box — no extra dependencies needed.
13+
- **Advanced (`@tsdown/css`):** Preprocessors (Sass/Less/Stylus), CSS syntax lowering, minification, and `@import` inlining require the `@tsdown/css` package:
14+
15+
```bash
16+
npm install -D @tsdown/css
17+
```
18+
19+
When `@tsdown/css` is installed, the advanced CSS plugin is automatically used in place of the built-in one.
20+
821
## CSS Import
922

1023
Importing `.css` files from your TypeScript or JavaScript entry points is supported out of the box. The CSS content is extracted and emitted as a separate `.css` asset file:
@@ -20,8 +33,27 @@ export function greet() {
2033

2134
This produces both `index.mjs` and `index.css` in the output directory.
2235

36+
### `@import` Inlining
37+
38+
When `@tsdown/css` is installed, CSS `@import` statements are automatically resolved and inlined into the output. This means you can use `@import` to organize your CSS across multiple files without producing separate output files:
39+
40+
```css
41+
/* style.css */
42+
@import './reset.css';
43+
@import './theme.css';
44+
45+
.main {
46+
color: red;
47+
}
48+
```
49+
50+
All imported CSS is bundled into a single output file with `@import` statements removed.
51+
2352
## CSS Pre-processors
2453

54+
> [!NOTE]
55+
> Requires `@tsdown/css` to be installed.
56+
2557
`tsdown` provides built-in support for `.scss`, `.sass`, `.less`, `.styl`, and `.stylus` files. The corresponding pre-processor must be installed as a dev dependency:
2658

2759
::: code-group
@@ -104,8 +136,105 @@ export default defineConfig({
104136
})
105137
```
106138

139+
## CSS Minification
140+
141+
> [!NOTE]
142+
> Requires `@tsdown/css` to be installed.
143+
144+
Enable CSS minification via `css.minify`:
145+
146+
```ts
147+
export default defineConfig({
148+
css: {
149+
minify: true,
150+
},
151+
})
152+
```
153+
154+
Minification is powered by [Lightning CSS](https://lightningcss.dev/).
155+
156+
## CSS Target
157+
158+
> [!NOTE]
159+
> Requires `@tsdown/css` to be installed.
160+
161+
By default, CSS syntax lowering uses the top-level [`target`](/options/target) option. You can override this specifically for CSS with `css.target`:
162+
163+
```ts
164+
export default defineConfig({
165+
target: 'node18',
166+
css: {
167+
target: 'chrome90', // CSS-specific target
168+
},
169+
})
170+
```
171+
172+
Set `css.target: false` to disable CSS syntax lowering entirely, even when a top-level `target` is set:
173+
174+
```ts
175+
export default defineConfig({
176+
target: 'chrome90',
177+
css: {
178+
target: false, // Preserve modern CSS syntax
179+
},
180+
})
181+
```
182+
183+
## CSS Transformer
184+
185+
> [!NOTE]
186+
> Requires `@tsdown/css` to be installed.
187+
188+
The `css.transformer` option controls how CSS is processed. PostCSS and Lightning CSS are **mutually exclusive** processing paths:
189+
190+
- **`'postcss'`** (default): `@import` is resolved by [`postcss-import`](https://github.com/postcss/postcss-import), PostCSS plugins are applied, then Lightning CSS is used only for final syntax lowering and minification.
191+
- **`'lightningcss'`**: `@import` is resolved by Lightning CSS's `bundleAsync()`, and PostCSS is **not used at all**.
192+
193+
```ts
194+
export default defineConfig({
195+
css: {
196+
transformer: 'lightningcss', // Use Lightning CSS for everything
197+
},
198+
})
199+
```
200+
201+
When using the default `'postcss'` transformer, install `postcss` and optionally `postcss-import` for `@import` resolution:
202+
203+
```bash
204+
npm install -D postcss postcss-import
205+
```
206+
207+
### PostCSS Options
208+
209+
Configure PostCSS inline or point to a config file:
210+
211+
```ts
212+
export default defineConfig({
213+
css: {
214+
postcss: {
215+
plugins: [require('autoprefixer')],
216+
},
217+
},
218+
})
219+
```
220+
221+
Or specify a directory path to search for a PostCSS config file (`postcss.config.js`, etc.):
222+
223+
```ts
224+
export default defineConfig({
225+
css: {
226+
postcss: './config', // Search for postcss.config.js in ./config/
227+
},
228+
})
229+
```
230+
231+
When `css.postcss` is omitted, tsdown auto-detects PostCSS config from the project root.
232+
107233
## Lightning CSS
108234

235+
> [!NOTE]
236+
> Requires `@tsdown/css` to be installed.
237+
109238
`tsdown` uses [Lightning CSS](https://lightningcss.dev/) for CSS syntax lowering — transforming modern CSS features into syntax compatible with older browsers based on your `target` setting.
110239

111240
To enable CSS syntax lowering, install `lightningcss`:
@@ -166,7 +295,7 @@ export default defineConfig({
166295
```
167296

168297
> [!TIP]
169-
> When `css.lightningcss.targets` is set, it takes precedence over the top-level `target` option for CSS transformations.
298+
> When `css.lightningcss.targets` is set, it takes precedence over both the top-level `target` and `css.target` options for CSS transformations.
170299
171300
For more information on available options, refer to the [Lightning CSS documentation](https://lightningcss.dev/).
172301

@@ -216,9 +345,13 @@ dist/
216345

217346
## Options Reference
218347

219-
| Option | Type | Default | Description |
220-
| ------------------------- | --------- | ------------- | -------------------------------------------------------------- |
221-
| `css.splitting` | `boolean` | `false` | Enable CSS code splitting per chunk |
222-
| `css.fileName` | `string` | `'style.css'` | File name for the merged CSS file (when `splitting: false`) |
223-
| `css.preprocessorOptions` | `object` || Options for CSS preprocessors (scss, sass, less, styl, stylus) |
224-
| `css.lightningcss` | `object` || Options passed to Lightning CSS for syntax lowering |
348+
| Option | Type | Default | Description |
349+
| ------------------------- | ----------------------------- | --------------- | ---------------------------------------------------------------------------- |
350+
| `css.transformer` | `'postcss' \| 'lightningcss'` | `'postcss'` | CSS processing pipeline (requires `@tsdown/css`) |
351+
| `css.splitting` | `boolean` | `false` | Enable CSS code splitting per chunk |
352+
| `css.fileName` | `string` | `'style.css'` | File name for the merged CSS file (when `splitting: false`) |
353+
| `css.minify` | `boolean` | `false` | Enable CSS minification (requires `@tsdown/css`) |
354+
| `css.target` | `string \| string[] \| false` | _from `target`_ | CSS-specific syntax lowering target (requires `@tsdown/css`) |
355+
| `css.postcss` | `string \| object` || PostCSS config path or inline options (requires `@tsdown/css`) |
356+
| `css.preprocessorOptions` | `object` || Options for CSS preprocessors (requires `@tsdown/css`) |
357+
| `css.lightningcss` | `object` || Options passed to Lightning CSS for syntax lowering (requires `@tsdown/css`) |

docs/options/target.md

Lines changed: 3 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -99,34 +99,8 @@ If you need to use the **latest TC39 Stage 3 decorators**, please note that `tsd
9999
> **Note:**
100100
> The two decorator implementations are very different. Make sure you are using the correct configuration and syntax for your chosen decorator version.
101101
102-
# CSS Targeting
102+
## CSS Targeting
103103

104-
`tsdown` can also downlevel CSS features to match your specified browser targets. For example, a CSS nesting `&` selector will be flattened if the target is `chrome108` or lower.
104+
`tsdown` can also downlevel CSS features to match your specified browser targets. By default, the top-level `target` is used for CSS, but you can override it with `css.target` or disable CSS lowering independently with `css.target: false`.
105105

106-
To enable CSS downleveling, install [`lightningcss`](https://lightningcss.dev/):
107-
108-
::: code-group
109-
110-
```sh [npm]
111-
npm install -D lightningcss
112-
```
113-
114-
```sh [pnpm]
115-
pnpm add -D lightningcss
116-
```
117-
118-
```sh [yarn]
119-
yarn add -D lightningcss
120-
```
121-
122-
```sh [bun]
123-
bun add -D lightningcss
124-
```
125-
126-
:::
127-
128-
Once installed, simply set your browser target (for example, `target: 'chrome100'`) in your configuration or CLI options, and CSS downleveling will be enabled automatically.
129-
130-
You can also pass additional Lightning CSS options via `css.lightningcss`. See the [CSS documentation](/options/css.md#lightning-css) for details.
131-
132-
For more information on browser targets and CSS compatibility, refer to the [Lightning CSS documentation](https://lightningcss.dev/).
106+
For full details on CSS syntax lowering, minification, and Lightning CSS options, see the [CSS documentation](/options/css.md#css-target).

0 commit comments

Comments
 (0)