Skip to content

Commit 91f9977

Browse files
feat: added the ability to pass an array of functions to the minify
1 parent 35b04ea commit 91f9977

13 files changed

+773
-354
lines changed

README.md

+16-2
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ module.exports = {
187187

188188
### `minify`
189189

190-
Type: `Function`
190+
Type: `Function|Array<Function>`
191191
Default: `undefined`
192192

193193
Allows you to override default minify function.
@@ -196,6 +196,8 @@ Useful for using and testing unpublished versions or forks.
196196

197197
> ⚠️ **Always use `require` inside `minify` function when `parallel` option enabled**.
198198
199+
#### `Function`
200+
199201
**webpack.config.js**
200202

201203
```js
@@ -240,13 +242,20 @@ module.exports = {
240242
};
241243
```
242244

245+
#### `Array`
246+
247+
If an array of functions is passed to the `minify` option, the `minimizerOptions` must also be an array.
248+
The function index in the `minify` array corresponds to the options object with the same index in the `minimizerOptions` array.
249+
243250
### `minimizerOptions`
244251

245-
Type: `Object`
252+
Type: `Object|Array<Object>`
246253
Default: `{ preset: 'default' }`
247254

248255
Cssnano optimisations [options](https://cssnano.co/docs/optimisations).
249256

257+
#### `Object`
258+
250259
```js
251260
module.exports = {
252261
optimization: {
@@ -267,6 +276,11 @@ module.exports = {
267276
};
268277
```
269278

279+
#### `Array`
280+
281+
If an array of functions is passed to the `minify` option, the `minimizerOptions` must also be an array.
282+
The function index in the `minify` array corresponds to the options object with the same index in the `minimizerOptions` array.
283+
270284
#### `processorOptions`
271285

272286
Type: `Object`

package-lock.json

+276-228
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/index.js

+48-23
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import * as cssNanoPackageJson from 'cssnano/package.json';
77
import pLimit from 'p-limit';
88
import Worker from 'jest-worker';
99

10+
import { cssnanoMinify } from './utils';
11+
1012
import * as schema from './options.json';
1113
import { minify as minifyFn } from './minify';
1214

@@ -20,10 +22,8 @@ class CssMinimizerPlugin {
2022
});
2123

2224
const {
23-
minify,
24-
minimizerOptions = {
25-
preset: 'default',
26-
},
25+
minify = cssnanoMinify,
26+
minimizerOptions,
2727
test = /\.css(\?.*)?$/i,
2828
warningsFilter = () => true,
2929
parallel = true,
@@ -281,34 +281,57 @@ class CssMinimizerPlugin {
281281
input = input.toString();
282282
}
283283

284+
const minifyFns =
285+
typeof this.options.minify === 'function'
286+
? [this.options.minify]
287+
: this.options.minify;
284288
const minimizerOptions = {
285289
name,
286290
input,
287291
inputSourceMap,
288-
minimizerOptions: this.options.minimizerOptions,
289-
minify: this.options.minify,
290292
};
291293

292-
try {
293-
output = await (getWorker
294-
? getWorker().transform(serialize(minimizerOptions))
295-
: minifyFn(minimizerOptions));
296-
} catch (error) {
297-
compilation.errors.push(
298-
CssMinimizerPlugin.buildError(
299-
error,
300-
name,
301-
compilation.requestShortener,
302-
inputSourceMap &&
303-
CssMinimizerPlugin.isSourceMap(inputSourceMap)
304-
? new SourceMapConsumer(inputSourceMap)
305-
: null
306-
)
307-
);
294+
let warnings = [];
295+
296+
this.options.minimizerOptions = Array.isArray(
297+
this.options.minimizerOptions
298+
)
299+
? this.options.minimizerOptions
300+
: [this.options.minimizerOptions];
301+
302+
for await (const [i, minifyFunc] of minifyFns.entries()) {
303+
minimizerOptions.minify = minifyFunc;
304+
minimizerOptions.minimizerOptions = this.options.minimizerOptions[
305+
i
306+
];
307+
308+
try {
309+
output = await (getWorker
310+
? getWorker().transform(serialize(minimizerOptions))
311+
: minifyFn(minimizerOptions));
312+
} catch (error) {
313+
compilation.errors.push(
314+
CssMinimizerPlugin.buildError(
315+
error,
316+
name,
317+
compilation.requestShortener,
318+
inputSourceMap &&
319+
CssMinimizerPlugin.isSourceMap(inputSourceMap)
320+
? new SourceMapConsumer(inputSourceMap)
321+
: null
322+
)
323+
);
308324

309-
return;
325+
return;
326+
}
327+
328+
minimizerOptions.input = output.code;
329+
minimizerOptions.inputSourceMap = output.map;
330+
warnings = warnings.concat(output.warnings);
310331
}
311332

333+
output.warnings = warnings;
334+
312335
if (output.map) {
313336
output.source = new SourceMapSource(
314337
output.code,
@@ -426,4 +449,6 @@ class CssMinimizerPlugin {
426449
}
427450
}
428451

452+
CssMinimizerPlugin.cssnano = cssnanoMinify;
453+
429454
export default CssMinimizerPlugin;

src/minify.js

+9-91
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
const cssnano = require('cssnano');
21
/*
32
* We bring to the line here, because when passing result from the worker,
43
* the warning.toString is replaced with native Object.toString
@@ -7,34 +6,6 @@ function warningsToString(warnings) {
76
return warnings.map((i) => i.toString());
87
}
98

10-
async function load(module) {
11-
let exports;
12-
13-
try {
14-
// eslint-disable-next-line import/no-dynamic-require, global-require
15-
exports = require(module);
16-
17-
return exports;
18-
} catch (requireError) {
19-
let importESM;
20-
21-
try {
22-
// eslint-disable-next-line no-new-func
23-
importESM = new Function('id', 'return import(id);');
24-
} catch (e) {
25-
importESM = null;
26-
}
27-
28-
if (requireError.code === 'ERR_REQUIRE_ESM' && importESM) {
29-
exports = await importESM(module);
30-
31-
return exports.default;
32-
}
33-
34-
throw requireError;
35-
}
36-
}
37-
389
const minify = async (options) => {
3910
const {
4011
name,
@@ -44,70 +15,17 @@ const minify = async (options) => {
4415
minify: minifyFn,
4516
} = options;
4617

47-
if (minifyFn) {
48-
const result = await minifyFn(
49-
{ [name]: input },
50-
inputSourceMap,
51-
minimizerOptions
52-
);
53-
54-
return {
55-
// TODO remove `css` in future major release
56-
code: result.code || result.css,
57-
map: result.map,
58-
warnings: warningsToString(result.warnings || []),
59-
};
60-
}
61-
62-
const postcssOptions = {
63-
to: name,
64-
from: name,
65-
...minimizerOptions.processorOptions,
66-
};
67-
68-
if (typeof postcssOptions.parser === 'string') {
69-
try {
70-
postcssOptions.parser = await load(postcssOptions.parser);
71-
} catch (error) {
72-
throw new Error(
73-
`Loading PostCSS "${postcssOptions.parser}" parser failed: ${error.message}\n\n(@${name})`
74-
);
75-
}
76-
}
77-
78-
if (typeof postcssOptions.stringifier === 'string') {
79-
try {
80-
postcssOptions.stringifier = await load(postcssOptions.stringifier);
81-
} catch (error) {
82-
throw new Error(
83-
`Loading PostCSS "${postcssOptions.stringifier}" stringifier failed: ${error.message}\n\n(@${name})`
84-
);
85-
}
86-
}
87-
88-
if (typeof postcssOptions.syntax === 'string') {
89-
try {
90-
postcssOptions.syntax = await load(postcssOptions.syntax);
91-
} catch (error) {
92-
throw new Error(
93-
`Loading PostCSS "${postcssOptions.syntax}" syntax failed: ${error.message}\n\n(@${name})`
94-
);
95-
}
96-
}
97-
98-
if (inputSourceMap) {
99-
postcssOptions.map = {
100-
annotation: false,
101-
prev: inputSourceMap,
102-
};
103-
}
104-
105-
const result = await cssnano.process(input, postcssOptions, minimizerOptions);
18+
const result = await minifyFn(
19+
{ [name]: input },
20+
inputSourceMap,
21+
minimizerOptions
22+
);
10623

10724
return {
108-
code: result.css,
109-
map: result.map && result.map.toString(),
110-
warnings: warningsToString(result.warnings()),
25+
// TODO remove `css` in future major release
26+
code: result.code || result.css,
27+
map: result.map,
28+
warnings: warningsToString(result.warnings || []),
11129
};
11230
};
11331

src/options.json

+28-3
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@
3131
"$ref": "#/definitions/Rule"
3232
}
3333
]
34+
},
35+
"MinimizerOptions": {
36+
"additionalProperties": true,
37+
"type": "object"
3438
}
3539
},
3640
"title": "CssMinimizerWebpackPluginOptions",
@@ -62,8 +66,18 @@
6266
},
6367
"minimizerOptions": {
6468
"description": "Options for `cssMinimizerOptions`.",
65-
"additionalProperties": true,
66-
"type": "object"
69+
"anyOf": [
70+
{
71+
"$ref": "#/definitions/MinimizerOptions"
72+
},
73+
{
74+
"type": "array",
75+
"minItems": 1,
76+
"items": {
77+
"$ref": "#/definitions/MinimizerOptions"
78+
}
79+
}
80+
]
6781
},
6882
"parallel": {
6983
"description": "Use multi-process parallel running to improve the build speed.",
@@ -82,7 +96,18 @@
8296
},
8397
"minify": {
8498
"description": "Allows you to override default minify function.",
85-
"instanceof": "Function"
99+
"anyOf": [
100+
{
101+
"instanceof": "Function"
102+
},
103+
{
104+
"type": "array",
105+
"minItems": 1,
106+
"items": {
107+
"instanceof": "Function"
108+
}
109+
}
110+
]
86111
}
87112
},
88113
"additionalProperties": false

0 commit comments

Comments
 (0)