Skip to content

Commit 1a34e62

Browse files
feat: add built-in CSS minimizers from css-minimizer-webpack-plugin (#669)
1 parent 9ddd343 commit 1a34e62

19 files changed

Lines changed: 3563 additions & 197 deletions

.cspell.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,13 @@
4040
"nocheck",
4141
"dont",
4242
"doctype",
43-
"wilsonzlin"
43+
"wilsonzlin",
44+
"cssnano",
45+
"csso",
46+
"lightningcss",
47+
"sourcefile",
48+
"stringifier",
49+
"sourcesContent"
4450
],
4551
"ignorePaths": [
4652
"CHANGELOG.md",

.github/workflows/nodejs.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ jobs:
6565
name: Test - ${{ matrix.os }} - Node v${{ matrix.node-version }}, Webpack ${{ matrix.webpack-version }}
6666

6767
strategy:
68+
fail-fast: false
6869
matrix:
6970
os: [ubuntu-latest, windows-latest, macos-latest]
7071
node-version: [10.x, 12.x, 14.x, 16.x, 18.x, 20.x, 22.x, 24.x]
@@ -109,6 +110,14 @@ jobs:
109110
run: npm ci
110111
if: matrix.node-version != '10.x' && matrix.node-version != '12.x' && matrix.node-version != '14.x' && matrix.node-version != '16.x' && matrix.node-version != '18.x'
111112

113+
- name: Install older cssnano (Node 10/12)
114+
if: matrix.node-version == '10.x' || matrix.node-version == '12.x'
115+
run: npm install -D --no-save cssnano@^5 --force
116+
117+
- name: Install older cssnano (Node 14/16)
118+
if: matrix.node-version == '14.x' || matrix.node-version == '16.x'
119+
run: npm install -D --no-save cssnano@^6 --force
120+
112121
- name: Install webpack ${{ matrix.webpack-version }}
113122
if: matrix.webpack-version != 'latest'
114123
run: npm i webpack@${{ matrix.webpack-version }}

README.md

Lines changed: 251 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@
1414
# terser-webpack-plugin
1515

1616
This plugin minifies your assets in a webpack build. It ships with several
17-
built-in minimizers covering JavaScript, JSON, and HTML — pick one with the
18-
[`minify`](#minify) option and target the right files with [`test`](#test).
17+
built-in minimizers covering JavaScript, JSON, HTML, and CSS — pick one
18+
with the [`minify`](#minify) option and target the right files with
19+
[`test`](#test).
1920

2021
JavaScript minimizers:
2122

@@ -34,6 +35,15 @@ HTML minimizers:
3435
- [`@swc/html`](https://github.com/swc-project/swc)`TerserPlugin.swcMinifyHtml` (full HTML documents) and `TerserPlugin.swcMinifyHtmlFragment` (HTML fragments, e.g. `<template>` content). Very fast Rust-based platform for the Web. Requires `npm install --save-dev @swc/html`.
3536
- [`@minify-html/node`](https://github.com/wilsonzlin/minify-html)`TerserPlugin.minifyHtmlNode`. A Rust HTML minifier optimised for speed and effectiveness. Requires `npm install --save-dev @minify-html/node`.
3637

38+
CSS minimizers:
39+
40+
- [`cssnano`](https://cssnano.github.io/cssnano/)`TerserPlugin.cssnanoMinify`. The default CSS minimizer. Built on top of [PostCSS](https://postcss.org/). Requires `npm install --save-dev cssnano postcss`.
41+
- [`csso`](https://github.com/css/csso)`TerserPlugin.cssoMinify`. A CSS minifier with structural optimisations. Requires `npm install --save-dev csso`.
42+
- [`clean-css`](https://github.com/clean-css/clean-css)`TerserPlugin.cleanCssMinify`. A widely-used CSS optimiser. Requires `npm install --save-dev clean-css`.
43+
- [`esbuild`](https://github.com/evanw/esbuild)`TerserPlugin.esbuildMinifyCss`. Very fast CSS minification using esbuild's CSS loader. Requires `npm install --save-dev esbuild`.
44+
- [`lightningcss`](https://github.com/parcel-bundler/lightningcss)`TerserPlugin.lightningCssMinify`. A Rust-based CSS parser, transformer, and minifier. Requires `npm install --save-dev lightningcss`.
45+
- [`@swc/css`](https://github.com/swc-project/swc)`TerserPlugin.swcMinifyCss`. A very fast Rust-based CSS minifier. Requires `npm install --save-dev @swc/css`.
46+
3747
All of the non-default minimizers are declared as **optional** peer
3848
dependencies — install only the ones you actually use. You can also stack
3949
multiple `TerserPlugin` instances in the same build to handle different
@@ -1065,6 +1075,196 @@ module.exports = {
10651075

10661076
You can also stack multiple `TerserPlugin` instances to compress different files with different `minify` functions in the same build (e.g. JS with `terserMinify`, HTML with `htmlMinifierTerser`, JSON with `jsonMinify`).
10671077

1078+
### CSS
1079+
1080+
The plugin can minify CSS assets too. Pick one of the bundled CSS
1081+
minimizers and set `test` to match your CSS files.
1082+
1083+
Available CSS minimizers:
1084+
1085+
- `TerserPlugin.cssnanoMinify` — uses [`cssnano`](https://cssnano.github.io/cssnano/) (via [`postcss`](https://postcss.org/)).
1086+
- `TerserPlugin.cssoMinify` — uses [`csso`](https://github.com/css/csso).
1087+
- `TerserPlugin.cleanCssMinify` — uses [`clean-css`](https://github.com/clean-css/clean-css).
1088+
- `TerserPlugin.esbuildMinifyCss` — uses [`esbuild`](https://github.com/evanw/esbuild) with the CSS loader.
1089+
- `TerserPlugin.lightningCssMinify` — uses [`lightningcss`](https://github.com/parcel-bundler/lightningcss).
1090+
- `TerserPlugin.swcMinifyCss` — uses [`@swc/css`](https://github.com/swc-project/swc).
1091+
1092+
The CSS minimizers are optional peer dependencies — install only the ones
1093+
you actually use:
1094+
1095+
```console
1096+
npm install --save-dev cssnano postcss
1097+
# or
1098+
npm install --save-dev csso
1099+
# or
1100+
npm install --save-dev clean-css
1101+
# or
1102+
npm install --save-dev esbuild
1103+
# or
1104+
npm install --save-dev lightningcss
1105+
# or
1106+
npm install --save-dev @swc/css
1107+
```
1108+
1109+
> **Note**
1110+
>
1111+
> CSS assets typically come from plugins like
1112+
> [`mini-css-extract-plugin`](https://github.com/webpack-contrib/mini-css-extract-plugin)
1113+
> or webpack's [asset modules](https://webpack.js.org/guides/asset-modules/).
1114+
1115+
#### `cssnano`
1116+
1117+
[`cssnano`](https://cssnano.github.io/cssnano/) is the default CSS minimizer. It runs as a [PostCSS](https://postcss.org/) plugin.
1118+
1119+
**webpack.config.js**
1120+
1121+
```js
1122+
const TerserPlugin = require("terser-webpack-plugin");
1123+
1124+
module.exports = {
1125+
optimization: {
1126+
minimize: true,
1127+
minimizer: [
1128+
// Keeps the default Terser plugin for JS files
1129+
"...",
1130+
new TerserPlugin({
1131+
test: /\.css(\?.*)?$/i,
1132+
minify: TerserPlugin.cssnanoMinify,
1133+
// Options - https://cssnano.github.io/cssnano/docs/config-file/
1134+
minimizerOptions: {
1135+
preset: "default",
1136+
},
1137+
}),
1138+
],
1139+
},
1140+
};
1141+
```
1142+
1143+
#### `csso`
1144+
1145+
[`csso`](https://github.com/css/csso) is a CSS minifier with structural optimisations.
1146+
1147+
**webpack.config.js**
1148+
1149+
```js
1150+
const TerserPlugin = require("terser-webpack-plugin");
1151+
1152+
module.exports = {
1153+
optimization: {
1154+
minimize: true,
1155+
minimizer: [
1156+
"...",
1157+
new TerserPlugin({
1158+
test: /\.css(\?.*)?$/i,
1159+
minify: TerserPlugin.cssoMinify,
1160+
// Options - https://github.com/css/csso#minifysource-options
1161+
minimizerOptions: {},
1162+
}),
1163+
],
1164+
},
1165+
};
1166+
```
1167+
1168+
#### `clean-css`
1169+
1170+
[`clean-css`](https://github.com/clean-css/clean-css) is a widely-used CSS optimiser.
1171+
1172+
**webpack.config.js**
1173+
1174+
```js
1175+
const TerserPlugin = require("terser-webpack-plugin");
1176+
1177+
module.exports = {
1178+
optimization: {
1179+
minimize: true,
1180+
minimizer: [
1181+
"...",
1182+
new TerserPlugin({
1183+
test: /\.css(\?.*)?$/i,
1184+
minify: TerserPlugin.cleanCssMinify,
1185+
// Options - https://github.com/clean-css/clean-css#constructor-options
1186+
minimizerOptions: {},
1187+
}),
1188+
],
1189+
},
1190+
};
1191+
```
1192+
1193+
#### `esbuild`
1194+
1195+
[`esbuild`](https://github.com/evanw/esbuild) ships with a fast CSS minifier (used via its CSS loader).
1196+
1197+
**webpack.config.js**
1198+
1199+
```js
1200+
const TerserPlugin = require("terser-webpack-plugin");
1201+
1202+
module.exports = {
1203+
optimization: {
1204+
minimize: true,
1205+
minimizer: [
1206+
"...",
1207+
new TerserPlugin({
1208+
test: /\.css(\?.*)?$/i,
1209+
minify: TerserPlugin.esbuildMinifyCss,
1210+
// Options - https://esbuild.github.io/api/#transform-api
1211+
minimizerOptions: {},
1212+
}),
1213+
],
1214+
},
1215+
};
1216+
```
1217+
1218+
#### `lightningcss`
1219+
1220+
[`lightningcss`](https://github.com/parcel-bundler/lightningcss) is a Rust-based CSS parser, transformer, and minifier.
1221+
1222+
**webpack.config.js**
1223+
1224+
```js
1225+
const TerserPlugin = require("terser-webpack-plugin");
1226+
1227+
module.exports = {
1228+
optimization: {
1229+
minimize: true,
1230+
minimizer: [
1231+
"...",
1232+
new TerserPlugin({
1233+
test: /\.css(\?.*)?$/i,
1234+
minify: TerserPlugin.lightningCssMinify,
1235+
// Options - https://lightningcss.dev/transpilation.html
1236+
minimizerOptions: {},
1237+
}),
1238+
],
1239+
},
1240+
};
1241+
```
1242+
1243+
#### `@swc/css`
1244+
1245+
[`@swc/css`](https://github.com/swc-project/swc) is a Rust-based CSS minifier.
1246+
1247+
**webpack.config.js**
1248+
1249+
```js
1250+
const TerserPlugin = require("terser-webpack-plugin");
1251+
1252+
module.exports = {
1253+
optimization: {
1254+
minimize: true,
1255+
minimizer: [
1256+
"...",
1257+
new TerserPlugin({
1258+
test: /\.css(\?.*)?$/i,
1259+
minify: TerserPlugin.swcMinifyCss,
1260+
// Options - https://github.com/swc-project/bindings/blob/main/packages/css/index.ts
1261+
minimizerOptions: {},
1262+
}),
1263+
],
1264+
},
1265+
};
1266+
```
1267+
10681268
### Custom Minify Function
10691269

10701270
Override the default minify function - use `uglify-js` for minification.
@@ -1120,12 +1320,17 @@ With built-in minify functions:
11201320

11211321
```ts
11221322
import { type JsMinifyOptions as SwcOptions } from "@swc/core";
1323+
import { type MinifyOptions as SwcCssOptions } from "@swc/css";
11231324
import {
11241325
type FragmentOptions as SwcHtmlFragmentOptions,
11251326
type Options as SwcHtmlOptions,
11261327
} from "@swc/html";
1328+
import { type OptionsOutput as CleanCssOptions } from "clean-css";
1329+
import { type Options as CssnanoOptions } from "cssnano";
1330+
import { type CompressOptions as CssoOptions } from "csso";
11271331
import { type TransformOptions as EsbuildOptions } from "esbuild";
11281332
import { type Options as HtmlMinifierTerserOptions } from "html-minifier-terser";
1333+
import { type TransformOptions as LightningCssOptions } from "lightningcss";
11291334
import { type MinifyOptions as TerserOptions } from "terser";
11301335
import { type MinifyOptions as UglifyJSOptions } from "uglify-js";
11311336

@@ -1182,6 +1387,50 @@ module.exports = {
11821387
// `@swc/html` fragment options
11831388
},
11841389
}),
1390+
1391+
// CSS minimizers
1392+
new TerserPlugin<CssnanoOptions>({
1393+
test: /\.css(\?.*)?$/i,
1394+
minify: TerserPlugin.cssnanoMinify,
1395+
minimizerOptions: {
1396+
// `cssnano` options
1397+
},
1398+
}),
1399+
new TerserPlugin<CssoOptions>({
1400+
test: /\.css(\?.*)?$/i,
1401+
minify: TerserPlugin.cssoMinify,
1402+
minimizerOptions: {
1403+
// `csso` options
1404+
},
1405+
}),
1406+
new TerserPlugin<CleanCssOptions>({
1407+
test: /\.css(\?.*)?$/i,
1408+
minify: TerserPlugin.cleanCssMinify,
1409+
minimizerOptions: {
1410+
// `clean-css` options
1411+
},
1412+
}),
1413+
new TerserPlugin<EsbuildOptions>({
1414+
test: /\.css(\?.*)?$/i,
1415+
minify: TerserPlugin.esbuildMinifyCss,
1416+
minimizerOptions: {
1417+
// `esbuild` options (CSS loader)
1418+
},
1419+
}),
1420+
new TerserPlugin<LightningCssOptions>({
1421+
test: /\.css(\?.*)?$/i,
1422+
minify: TerserPlugin.lightningCssMinify,
1423+
minimizerOptions: {
1424+
// `lightningcss` options
1425+
},
1426+
}),
1427+
new TerserPlugin<SwcCssOptions>({
1428+
test: /\.css(\?.*)?$/i,
1429+
minify: TerserPlugin.swcMinifyCss,
1430+
minimizerOptions: {
1431+
// `@swc/css` options
1432+
},
1433+
}),
11851434
],
11861435
},
11871436
};

jest.config.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,19 @@
1+
// The bundled CSS minimizers (`cssnano@7`, `@swc/css`, `lightningcss`,
2+
// `esbuild@0.27`) require modern Node and don't reliably install on the
3+
// Windows agents. Skip the dedicated CSS test file outright on rows that
4+
// can't run them so we don't end up with stale or missing snapshots.
5+
const NODE_MAJOR = Number(process.versions.node.split(".")[0]);
6+
const IS_WINDOWS = process.platform === "win32";
7+
const RUN_CSS_TESTS = NODE_MAJOR >= 18 && !IS_WINDOWS;
8+
19
module.exports = {
210
testEnvironment: "node",
11+
// The default 5s timeout is too tight for slower CI runners (especially
12+
// older Node on macOS), where webpack + multiple minimizers per asset
13+
// routinely take longer than that.
14+
testTimeout: 60000,
315
coveragePathIgnorePatterns: ["src/serialize-javascript.js"],
16+
testPathIgnorePatterns: RUN_CSS_TESTS
17+
? []
18+
: ["/test/css-minify-option\\.test\\.js$"],
419
};

0 commit comments

Comments
 (0)