From c9a11b2349d24206bc03cf3670f50a822ef7a52b Mon Sep 17 00:00:00 2001 From: Alexander Akait <4567934+alexander-akait@users.noreply.github.com> Date: Mon, 4 Oct 2021 19:06:54 +0300 Subject: [PATCH] feat: allow returning errors from custom minimize function (#121) --- README.md | 5 +- src/index.js | 147 +++++++++++------- src/minify.js | 8 +- .../CssMinimizerPlugin.test.js.snap | 76 ++++++--- test/__snapshots__/cache-option.test.js.snap | 30 ++-- test/__snapshots__/minify-option.test.js.snap | 23 ++- .../sourceMap-option.test.js.snap | 4 +- .../warningsFilter-option.test.js.snap | 6 +- test/minify-option.test.js | 38 +++++ 9 files changed, 236 insertions(+), 101 deletions(-) diff --git a/README.md b/README.md index 36cb6e3..53ecf80 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,7 @@ module.exports = { new CssMinimizerPlugin(), ], }, + plugins: [new MiniCssExtractPlugin()], }; ``` @@ -223,7 +224,7 @@ Possible options: - CssMinimizerPlugin.cssnanoMinify - CssMinimizerPlugin.cssoMinify - CssMinimizerPlugin.cleanCssMinify -- `async (data, inputMap, minimizerOptions) => {return {code: "a{color: red}", map: "...", warnings: []}}` +- `async (data, inputMap, minimizerOptions) => {return {code: "a{color: red}", map: "...", warnings: [], errors: []}}` > ⚠️ **Always use `require` inside `minify` function when `parallel` option enabled**. @@ -278,6 +279,7 @@ module.exports = { code: `a{color: red}`, map: `{"version": "3", ...}`, warnings: [], + errors: [], }; }, ], @@ -450,6 +452,7 @@ module.exports = { optimization: { minimizer: [new CssMinimizerPlugin()], }, + plugins: [new MiniCssExtractPlugin()], }; ``` diff --git a/src/index.js b/src/index.js index efd1540..71f87e0 100644 --- a/src/index.js +++ b/src/index.js @@ -53,59 +53,6 @@ class CssMinimizerPlugin { ); } - static buildError(error, name, sourceMap, requestShortener) { - let builtError; - - if (error.line) { - const original = - sourceMap && - sourceMap.originalPositionFor({ - line: error.line, - column: error.column, - }); - - if (original && original.source && requestShortener) { - builtError = new Error( - `${name} from Css Minimizer Webpack Plugin\n${ - error.message - } [${requestShortener.shorten(original.source)}:${original.line},${ - original.column - }][${name}:${error.line},${error.column}]${ - error.stack - ? `\n${error.stack.split("\n").slice(1).join("\n")}` - : "" - }` - ); - builtError.file = name; - - return builtError; - } - - builtError = new Error( - `${name} from Css Minimizer \n${error.message} [${name}:${error.line},${ - error.column - }]${ - error.stack ? `\n${error.stack.split("\n").slice(1).join("\n")}` : "" - }` - ); - builtError.file = name; - - return builtError; - } - - if (error.stack) { - builtError = new Error(`${name} from Css Minimizer\n${error.stack}`); - builtError.file = name; - - return builtError; - } - - builtError = new Error(`${name} from Css Minimizer\n${error.message}`); - builtError.file = name; - - return builtError; - } - static buildWarning( warning, file, @@ -113,7 +60,12 @@ class CssMinimizerPlugin { requestShortener, warningsFilter ) { - let warningMessage = warning; + let warningMessage = + typeof warning === "string" + ? warning + : `${warning.plugin ? `[${warning.plugin}] ` : ""}${ + warning.text || warning.message + }`; let locationMessage = ""; let source; @@ -149,7 +101,7 @@ class CssMinimizerPlugin { } const builtWarning = new Error( - `Css Minimizer Plugin: ${warningMessage}${ + `${file} from Css Minimizer Plugin\n${warningMessage}${ locationMessage ? ` ${locationMessage}` : "" }` ); @@ -161,6 +113,70 @@ class CssMinimizerPlugin { return builtWarning; } + static buildError(error, file, sourceMap, requestShortener) { + let builtError; + + if (typeof error === "string") { + builtError = new Error(`${file} from Css Minimizer Plugin\n${error}`); + builtError.file = file; + + return builtError; + } + + if (error.line) { + const original = + sourceMap && + sourceMap.originalPositionFor({ + line: error.line, + column: error.column, + }); + + if (original && original.source && requestShortener) { + builtError = new Error( + `${file} from Css Minimizer Plugin\n${ + error.message + } [${requestShortener.shorten(original.source)}:${original.line},${ + original.column + }][${file}:${error.line},${error.column}]${ + error.stack + ? `\n${error.stack.split("\n").slice(1).join("\n")}` + : "" + }` + ); + builtError.file = file; + + return builtError; + } + + builtError = new Error( + `${file} from Css Minimizer Plugin\n${error.message} [${file}:${ + error.line + },${error.column}]${ + error.stack ? `\n${error.stack.split("\n").slice(1).join("\n")}` : "" + }` + ); + builtError.file = file; + + return builtError; + } + + if (error.stack) { + builtError = new Error( + `${file} from Css Minimizer Plugin\n${error.stack}` + ); + builtError.file = file; + + return builtError; + } + + builtError = new Error( + `${file} from Css Minimizer Plugin\n${error.message}` + ); + builtError.file = file; + + return builtError; + } + static getAvailableNumberOfCores(parallel) { // In some cases cpus() returns undefined // https://github.com/nodejs/node/issues/19022 @@ -350,6 +366,27 @@ class CssMinimizerPlugin { } } + if (result.errors && result.errors.length > 0) { + const hasSourceMap = + inputSourceMap && + CssMinimizerPlugin.isSourceMap(inputSourceMap); + + for (const error of result.errors) { + output.warnings.push( + CssMinimizerPlugin.buildError( + error, + name, + hasSourceMap + ? new SourceMapConsumer(inputSourceMap) + : // eslint-disable-next-line no-undefined + undefined, + // eslint-disable-next-line no-undefined + hasSourceMap ? compilation.requestShortener : undefined + ) + ); + } + } + if (result.warnings && result.warnings.length > 0) { const hasSourceMap = inputSourceMap && diff --git a/src/minify.js b/src/minify.js index d5b6698..25bc139 100644 --- a/src/minify.js +++ b/src/minify.js @@ -32,15 +32,11 @@ const minify = async (options) => { } if (minifyResult.errors) { - result.errors = result.errors.concat( - minifyResult.errors.map((error) => error.toString()) - ); + result.errors = result.errors.concat(minifyResult.errors); } if (minifyResult.warnings) { - result.warnings = result.warnings.concat( - minifyResult.warnings.map((warning) => warning.toString()) - ); + result.warnings = result.warnings.concat(minifyResult.warnings); } result.outputs.push({ code: minifyResult.code, map: minifyResult.map }); diff --git a/test/__snapshots__/CssMinimizerPlugin.test.js.snap b/test/__snapshots__/CssMinimizerPlugin.test.js.snap index 6b08882..f315a16 100644 --- a/test/__snapshots__/CssMinimizerPlugin.test.js.snap +++ b/test/__snapshots__/CssMinimizerPlugin.test.js.snap @@ -1,40 +1,55 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`CssMinimizerPlugin buildError method 1`] = ` -[Error: test.css from Css Minimizer +[Error: test.css from Css Minimizer Plugin Message] `; exports[`CssMinimizerPlugin buildError method 2`] = ` -[Error: test.css from Css Minimizer +[Error: test.css from Css Minimizer Plugin Message [test.css:1,1]] `; exports[`CssMinimizerPlugin buildError method 3`] = ` -[Error: test.css from Css Minimizer Webpack Plugin +[Error: test.css from Css Minimizer Plugin Message [http://example.com/www/js/one.css:1,1][test.css:1,1]] `; exports[`CssMinimizerPlugin buildError method 4`] = ` -[Error: test.css from Css Minimizer +[Error: test.css from Css Minimizer Plugin Stack] `; -exports[`CssMinimizerPlugin buildWarning method 1`] = `[Warning: Css Minimizer Plugin: Warning test.css:1:1]`; +exports[`CssMinimizerPlugin buildWarning method 1`] = ` +[Warning: undefined from Css Minimizer Plugin +Warning test.css:1:1] +`; -exports[`CssMinimizerPlugin buildWarning method 2`] = `[Warning: Css Minimizer Plugin: Warning test.css:1:1]`; +exports[`CssMinimizerPlugin buildWarning method 2`] = ` +[Warning: test.css from Css Minimizer Plugin +Warning test.css:1:1] +`; -exports[`CssMinimizerPlugin buildWarning method 3`] = `[Warning: Css Minimizer Plugin: Warning test.css:1:1]`; +exports[`CssMinimizerPlugin buildWarning method 3`] = ` +[Warning: test.css from Css Minimizer Plugin +Warning test.css:1:1] +`; -exports[`CssMinimizerPlugin buildWarning method 4`] = `[Warning: Css Minimizer Plugin: Warning http://example.com/www/js/one.css:1:1]`; +exports[`CssMinimizerPlugin buildWarning method 4`] = ` +[Warning: test.css from Css Minimizer Plugin +Warning http://example.com/www/js/one.css:1:1] +`; -exports[`CssMinimizerPlugin buildWarning method 5`] = `[Warning: Css Minimizer Plugin: Warning http://example.com/www/js/one.css:1:1]`; +exports[`CssMinimizerPlugin buildWarning method 5`] = ` +[Warning: test.css from Css Minimizer Plugin +Warning http://example.com/www/js/one.css:1:1] +`; exports[`CssMinimizerPlugin buildWarning method 6`] = `null`; exports[`CssMinimizerPlugin should build error: error 1`] = ` Array [ - "Error: error.css from Css Minimizer + "Error: error.css from Css Minimizer Plugin /error.css:1:1: Unknown word [error.css:1,1]", ] `; @@ -45,7 +60,8 @@ exports[`CssMinimizerPlugin should build warning: error 1`] = `Array []`; exports[`CssMinimizerPlugin should build warning: warning 1`] = ` Array [ - "Warning: Css Minimizer Plugin: warning-plugin:: Warning webpack://./test/foo.css:2:2", + "Warning: foo.css from Css Minimizer Plugin +[warning-plugin] Warning", ] `; @@ -71,7 +87,7 @@ exports[`CssMinimizerPlugin should run plugin against assets added later by plug exports[`CssMinimizerPlugin should throw error from postcss: error 1`] = ` Array [ - "Error: foo.css from Css Minimizer Webpack Plugin + "Error: foo.css from Css Minimizer Plugin error-plugin: /foo.css:2:3: Postcss error [webpack://./test/foo.css:2,2][foo.css:2,3]", ] `; @@ -297,9 +313,12 @@ a { exports[`CssMinimizerPlugin should work with warnings and use memory cache when the "cache" option is "true" and the asset has been changed: errors 1`] = ` Array [ - "Warning: Css Minimizer Plugin: warning-plugin: Warning from foo.css", - "Warning: Css Minimizer Plugin: warning-plugin: Warning from style-2.css", - "Warning: Css Minimizer Plugin: warning-plugin: Warning from style.css", + "Warning: foo.css from Css Minimizer Plugin +[warning-plugin] Warning from foo.css", + "Warning: style-2.css from Css Minimizer Plugin +[warning-plugin] Warning from style-2.css", + "Warning: style.css from Css Minimizer Plugin +[warning-plugin] Warning from style.css", ] `; @@ -309,9 +328,12 @@ exports[`CssMinimizerPlugin should work with warnings and use memory cache when exports[`CssMinimizerPlugin should work with warnings and use memory cache when the "cache" option is "true" and the asset has been changed: warnings 2`] = ` Array [ - "Warning: Css Minimizer Plugin: warning-plugin: Warning from foo.css", - "Warning: Css Minimizer Plugin: warning-plugin: Warning from style-2.css", - "Warning: Css Minimizer Plugin: warning-plugin: Warning from style.css", + "Warning: foo.css from Css Minimizer Plugin +[warning-plugin] Warning from foo.css", + "Warning: style-2.css from Css Minimizer Plugin +[warning-plugin] Warning from style-2.css", + "Warning: style.css from Css Minimizer Plugin +[warning-plugin] Warning from style.css", ] `; @@ -345,9 +367,12 @@ a { exports[`CssMinimizerPlugin should work with warnings and use memory cache when the "cache" option is "true": errors 1`] = ` Array [ - "Warning: Css Minimizer Plugin: warning-plugin: Warning from foo.css", - "Warning: Css Minimizer Plugin: warning-plugin: Warning from style-2.css", - "Warning: Css Minimizer Plugin: warning-plugin: Warning from style.css", + "Warning: foo.css from Css Minimizer Plugin +[warning-plugin] Warning from foo.css", + "Warning: style-2.css from Css Minimizer Plugin +[warning-plugin] Warning from style-2.css", + "Warning: style.css from Css Minimizer Plugin +[warning-plugin] Warning from style.css", ] `; @@ -357,9 +382,12 @@ exports[`CssMinimizerPlugin should work with warnings and use memory cache when exports[`CssMinimizerPlugin should work with warnings and use memory cache when the "cache" option is "true": warnings 2`] = ` Array [ - "Warning: Css Minimizer Plugin: warning-plugin: Warning from foo.css", - "Warning: Css Minimizer Plugin: warning-plugin: Warning from style-2.css", - "Warning: Css Minimizer Plugin: warning-plugin: Warning from style.css", + "Warning: foo.css from Css Minimizer Plugin +[warning-plugin] Warning from foo.css", + "Warning: style-2.css from Css Minimizer Plugin +[warning-plugin] Warning from style-2.css", + "Warning: style.css from Css Minimizer Plugin +[warning-plugin] Warning from style.css", ] `; diff --git a/test/__snapshots__/cache-option.test.js.snap b/test/__snapshots__/cache-option.test.js.snap index ff65fe7..574b5de 100644 --- a/test/__snapshots__/cache-option.test.js.snap +++ b/test/__snapshots__/cache-option.test.js.snap @@ -132,21 +132,31 @@ exports[`"cache" option should work with the "filesystem" value for the "cache.t exports[`"cache" option should work with the "filesystem" value for the "cache.type" option and output warnings: warnings 1`] = ` Array [ - "Warning: Css Minimizer Plugin: warning-plugin: Warning from five.css", - "Warning: Css Minimizer Plugin: warning-plugin: Warning from four.css", - "Warning: Css Minimizer Plugin: warning-plugin: Warning from one.css", - "Warning: Css Minimizer Plugin: warning-plugin: Warning from three.css", - "Warning: Css Minimizer Plugin: warning-plugin: Warning from two.css", + "Warning: five.css from Css Minimizer Plugin +[warning-plugin] Warning from five.css", + "Warning: four.css from Css Minimizer Plugin +[warning-plugin] Warning from four.css", + "Warning: one.css from Css Minimizer Plugin +[warning-plugin] Warning from one.css", + "Warning: three.css from Css Minimizer Plugin +[warning-plugin] Warning from three.css", + "Warning: two.css from Css Minimizer Plugin +[warning-plugin] Warning from two.css", ] `; exports[`"cache" option should work with the "filesystem" value for the "cache.type" option and output warnings: warnings 2`] = ` Array [ - "Warning: Css Minimizer Plugin: warning-plugin: Warning from five.css", - "Warning: Css Minimizer Plugin: warning-plugin: Warning from four.css", - "Warning: Css Minimizer Plugin: warning-plugin: Warning from one.css", - "Warning: Css Minimizer Plugin: warning-plugin: Warning from three.css", - "Warning: Css Minimizer Plugin: warning-plugin: Warning from two.css", + "Warning: five.css from Css Minimizer Plugin +[warning-plugin] Warning from five.css", + "Warning: four.css from Css Minimizer Plugin +[warning-plugin] Warning from four.css", + "Warning: one.css from Css Minimizer Plugin +[warning-plugin] Warning from one.css", + "Warning: three.css from Css Minimizer Plugin +[warning-plugin] Warning from three.css", + "Warning: two.css from Css Minimizer Plugin +[warning-plugin] Warning from two.css", ] `; diff --git a/test/__snapshots__/minify-option.test.js.snap b/test/__snapshots__/minify-option.test.js.snap index fa6fad6..c75434d 100644 --- a/test/__snapshots__/minify-option.test.js.snap +++ b/test/__snapshots__/minify-option.test.js.snap @@ -1,5 +1,26 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`"minify" option should work and allow to return errors and warnings from custom function: assets 1`] = ` +Object { + "foo.css": ".test { color: red; }", +} +`; + +exports[`"minify" option should work and allow to return errors and warnings from custom function: error 1`] = `Array []`; + +exports[`"minify" option should work and allow to return errors and warnings from custom function: warning 1`] = ` +Array [ + "Error: foo.css from Css Minimizer Plugin +Error 1", + "Error: foo.css from Css Minimizer Plugin +Error: Error 2", + "Warning: foo.css from Css Minimizer Plugin +Warning 1", + "Warning: foo.css from Css Minimizer Plugin +Warning 2", +] +`; + exports[`"minify" option should work if minify is array && minimizerOptions is array: assets 1`] = ` Object { "foo.css": "body { @@ -79,7 +100,7 @@ body a { exports[`"minify" option should work throw an error if minimizer function doesn't return: error 1`] = ` Array [ - "Error: foo.css from Css Minimizer + "Error: foo.css from Css Minimizer Plugin Error: Minimizer function doesn't return result", ] `; diff --git a/test/__snapshots__/sourceMap-option.test.js.snap b/test/__snapshots__/sourceMap-option.test.js.snap index 3fcbbd9..c4bbf0d 100644 --- a/test/__snapshots__/sourceMap-option.test.js.snap +++ b/test/__snapshots__/sourceMap-option.test.js.snap @@ -2,10 +2,10 @@ exports[`when applied with "sourceMap" option should work and emit warning on valid sourcemap and minimizer error: errors 1`] = ` Array [ - "Error: broken-source-map.css from Css Minimizer Webpack Plugin + "Error: broken-source-map.css from Css Minimizer Plugin error-plugin: /broken-source-map.css:1:7: Postcss error [test:1,5][broken-source-map.css:1,7]", "ModuleBuildError: Module build failed (from ../../node_modules/mini-css-extract-plugin/dist/loader.js): -Error: broken-source-map.css from Css Minimizer Webpack Plugin", +Error: broken-source-map.css from Css Minimizer Plugin", ] `; diff --git a/test/__snapshots__/warningsFilter-option.test.js.snap b/test/__snapshots__/warningsFilter-option.test.js.snap index 19a0a65..30ee0a7 100644 --- a/test/__snapshots__/warningsFilter-option.test.js.snap +++ b/test/__snapshots__/warningsFilter-option.test.js.snap @@ -36,7 +36,9 @@ exports[`warningsFilter option should match snapshot for a "function" value: err exports[`warningsFilter option should match snapshot for a "function" value: warnings 1`] = ` Array [ - "Warning: Css Minimizer Plugin: warning-plugin: Warning from bar1.css", - "Warning: Css Minimizer Plugin: warning-plugin: Warning from bar2.css", + "Warning: bar1.css from Css Minimizer Plugin +[warning-plugin] Warning from bar1.css", + "Warning: bar2.css from Css Minimizer Plugin +[warning-plugin] Warning from bar2.css", ] `; diff --git a/test/minify-option.test.js b/test/minify-option.test.js index b5ecc7e..88242fa 100644 --- a/test/minify-option.test.js +++ b/test/minify-option.test.js @@ -530,4 +530,42 @@ describe('"minify" option', () => { expect(getErrors(stats)).toMatchSnapshot("error"); expect(getWarnings(stats)).toMatchSnapshot("warning"); }); + + it("should work and allow to return errors and warnings from custom function", async () => { + const compiler = getCompiler({ + entry: { + foo: `${__dirname}/fixtures/sourcemap/foo.scss`, + }, + module: { + rules: [ + { + test: /.s?css$/i, + use: [ + MiniCssExtractPlugin.loader, + { loader: "css-loader", options: { sourceMap: true } }, + { loader: "sass-loader", options: { sourceMap: true } }, + ], + }, + ], + }, + }); + + new CssMinimizerPlugin({ + minify: async () => { + return { + code: `.test { color: red; }`, + warnings: ["Warning 1", new Error("Warning 2")], + errors: ["Error 1", new Error("Error 2")], + }; + }, + }).apply(compiler); + + const stats = await compile(compiler); + + expect(readAssets(compiler, stats, /\.css(\.map)?$/)).toMatchSnapshot( + "assets" + ); + expect(getErrors(stats)).toMatchSnapshot("error"); + expect(getWarnings(stats)).toMatchSnapshot("warning"); + }); });