Skip to content

Feat: added the ability to pass an array of functions to the minify option #72

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ module.exports = {

### `minify`

Type: `Function`
Type: `Function|Array<Function>`
Default: `undefined`

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

> ⚠️ **Always use `require` inside `minify` function when `parallel` option enabled**.

#### `Function`

**webpack.config.js**

```js
Expand Down Expand Up @@ -240,13 +242,20 @@ module.exports = {
};
```

#### `Array`

If an array of functions is passed to the `minify` option, the `minimizerOptions` must also be an array.
The function index in the `minify` array corresponds to the options object with the same index in the `minimizerOptions` array.

### `minimizerOptions`

Type: `Object`
Type: `Object|Array<Object>`
Default: `{ preset: 'default' }`

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

#### `Object`

```js
module.exports = {
optimization: {
Expand All @@ -267,6 +276,11 @@ module.exports = {
};
```

#### `Array`

If an array of functions is passed to the `minify` option, the `minimizerOptions` must also be an array.
The function index in the `minify` array corresponds to the options object with the same index in the `minimizerOptions` array.

#### `processorOptions`

Type: `Object`
Expand Down
504 changes: 276 additions & 228 deletions package-lock.json

Large diffs are not rendered by default.

71 changes: 48 additions & 23 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import * as cssNanoPackageJson from 'cssnano/package.json';
import pLimit from 'p-limit';
import Worker from 'jest-worker';

import { cssnanoMinify } from './utils';

import * as schema from './options.json';
import { minify as minifyFn } from './minify';

Expand All @@ -20,10 +22,8 @@ class CssMinimizerPlugin {
});

const {
minify,
minimizerOptions = {
preset: 'default',
},
minify = cssnanoMinify,
minimizerOptions,
test = /\.css(\?.*)?$/i,
warningsFilter = () => true,
parallel = true,
Expand Down Expand Up @@ -281,34 +281,57 @@ class CssMinimizerPlugin {
input = input.toString();
}

const minifyFns =
typeof this.options.minify === 'function'
? [this.options.minify]
: this.options.minify;
const minimizerOptions = {
name,
input,
inputSourceMap,
minimizerOptions: this.options.minimizerOptions,
minify: this.options.minify,
};

try {
output = await (getWorker
? getWorker().transform(serialize(minimizerOptions))
: minifyFn(minimizerOptions));
} catch (error) {
compilation.errors.push(
CssMinimizerPlugin.buildError(
error,
name,
compilation.requestShortener,
inputSourceMap &&
CssMinimizerPlugin.isSourceMap(inputSourceMap)
? new SourceMapConsumer(inputSourceMap)
: null
)
);
let warnings = [];

this.options.minimizerOptions = Array.isArray(
this.options.minimizerOptions
)
? this.options.minimizerOptions
: [this.options.minimizerOptions];

for await (const [i, minifyFunc] of minifyFns.entries()) {
minimizerOptions.minify = minifyFunc;
minimizerOptions.minimizerOptions = this.options.minimizerOptions[
i
];

try {
output = await (getWorker
? getWorker().transform(serialize(minimizerOptions))
: minifyFn(minimizerOptions));
} catch (error) {
compilation.errors.push(
CssMinimizerPlugin.buildError(
error,
name,
compilation.requestShortener,
inputSourceMap &&
CssMinimizerPlugin.isSourceMap(inputSourceMap)
? new SourceMapConsumer(inputSourceMap)
: null
)
);

return;
return;
}

minimizerOptions.input = output.code;
minimizerOptions.inputSourceMap = output.map;
warnings = warnings.concat(output.warnings);
}

output.warnings = warnings;

if (output.map) {
output.source = new SourceMapSource(
output.code,
Expand Down Expand Up @@ -426,4 +449,6 @@ class CssMinimizerPlugin {
}
}

CssMinimizerPlugin.cssnano = cssnanoMinify;

export default CssMinimizerPlugin;
100 changes: 9 additions & 91 deletions src/minify.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
const cssnano = require('cssnano');
/*
* We bring to the line here, because when passing result from the worker,
* the warning.toString is replaced with native Object.toString
Expand All @@ -7,34 +6,6 @@ function warningsToString(warnings) {
return warnings.map((i) => i.toString());
}

async function load(module) {
let exports;

try {
// eslint-disable-next-line import/no-dynamic-require, global-require
exports = require(module);

return exports;
} catch (requireError) {
let importESM;

try {
// eslint-disable-next-line no-new-func
importESM = new Function('id', 'return import(id);');
} catch (e) {
importESM = null;
}

if (requireError.code === 'ERR_REQUIRE_ESM' && importESM) {
exports = await importESM(module);

return exports.default;
}

throw requireError;
}
}

const minify = async (options) => {
const {
name,
Expand All @@ -44,70 +15,17 @@ const minify = async (options) => {
minify: minifyFn,
} = options;

if (minifyFn) {
const result = await minifyFn(
{ [name]: input },
inputSourceMap,
minimizerOptions
);

return {
// TODO remove `css` in future major release
code: result.code || result.css,
map: result.map,
warnings: warningsToString(result.warnings || []),
};
}

const postcssOptions = {
to: name,
from: name,
...minimizerOptions.processorOptions,
};

if (typeof postcssOptions.parser === 'string') {
try {
postcssOptions.parser = await load(postcssOptions.parser);
} catch (error) {
throw new Error(
`Loading PostCSS "${postcssOptions.parser}" parser failed: ${error.message}\n\n(@${name})`
);
}
}

if (typeof postcssOptions.stringifier === 'string') {
try {
postcssOptions.stringifier = await load(postcssOptions.stringifier);
} catch (error) {
throw new Error(
`Loading PostCSS "${postcssOptions.stringifier}" stringifier failed: ${error.message}\n\n(@${name})`
);
}
}

if (typeof postcssOptions.syntax === 'string') {
try {
postcssOptions.syntax = await load(postcssOptions.syntax);
} catch (error) {
throw new Error(
`Loading PostCSS "${postcssOptions.syntax}" syntax failed: ${error.message}\n\n(@${name})`
);
}
}

if (inputSourceMap) {
postcssOptions.map = {
annotation: false,
prev: inputSourceMap,
};
}

const result = await cssnano.process(input, postcssOptions, minimizerOptions);
const result = await minifyFn(
{ [name]: input },
inputSourceMap,
minimizerOptions
);

return {
code: result.css,
map: result.map && result.map.toString(),
warnings: warningsToString(result.warnings()),
// TODO remove `css` in future major release
code: result.code || result.css,
map: result.map,
warnings: warningsToString(result.warnings || []),
};
};

Expand Down
31 changes: 28 additions & 3 deletions src/options.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@
"$ref": "#/definitions/Rule"
}
]
},
"MinimizerOptions": {
"additionalProperties": true,
"type": "object"
}
},
"title": "CssMinimizerWebpackPluginOptions",
Expand Down Expand Up @@ -62,8 +66,18 @@
},
"minimizerOptions": {
"description": "Options for `cssMinimizerOptions`.",
"additionalProperties": true,
"type": "object"
"anyOf": [
{
"$ref": "#/definitions/MinimizerOptions"
},
{
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/definitions/MinimizerOptions"
}
}
]
},
"parallel": {
"description": "Use multi-process parallel running to improve the build speed.",
Expand All @@ -82,7 +96,18 @@
},
"minify": {
"description": "Allows you to override default minify function.",
"instanceof": "Function"
"anyOf": [
{
"instanceof": "Function"
},
{
"type": "array",
"minItems": 1,
"items": {
"instanceof": "Function"
}
}
]
}
},
"additionalProperties": false
Expand Down
Loading