From a08eaf7fb8216d718aa2a4476304241ec6effb4c Mon Sep 17 00:00:00 2001 From: alexander-akait Date: Fri, 5 Dec 2025 14:04:05 +0300 Subject: [PATCH 1/3] fix: respect errors and warnings without code --- src/index.js | 139 +++++++++--------- src/utils.js | 1 - test/__snapshots__/minify-option.test.js.snap | 17 +++ test/minify-option.test.js | 16 ++ 4 files changed, 106 insertions(+), 67 deletions(-) diff --git a/src/index.js b/src/index.js index 2b2cbb9..686916e 100644 --- a/src/index.js +++ b/src/index.js @@ -559,8 +559,6 @@ class TerserPlugin { `${name} from Terser plugin\nMinimizer doesn't return result`, ), ); - - return; } if (output.warnings && output.warnings.length > 0) { @@ -615,82 +613,87 @@ class TerserPlugin { ); } - if (output.map) { - output.source = new SourceMapSource( - output.code, - name, - output.map, - input, - /** @type {RawSourceMap} */ - (inputSourceMap), - true, - ); - } else { - output.source = new RawSource(output.code); - } + if (output.code) { + if (output.map) { + output.source = new SourceMapSource( + output.code, + name, + output.map, + input, + /** @type {RawSourceMap} */ + (inputSourceMap), + true, + ); + } else { + output.source = new RawSource(output.code); + } - if (output.extractedComments && output.extractedComments.length > 0) { - const commentsFilename = - /** @type {ExtractCommentsObject} */ - (this.options.extractComments).filename || - "[file].LICENSE.txt[query]"; + if ( + output.extractedComments && + output.extractedComments.length > 0 + ) { + const commentsFilename = + /** @type {ExtractCommentsObject} */ + (this.options.extractComments).filename || + "[file].LICENSE.txt[query]"; - let query = ""; - let filename = name; + let query = ""; + let filename = name; - const querySplit = filename.indexOf("?"); + const querySplit = filename.indexOf("?"); - if (querySplit >= 0) { - query = filename.slice(querySplit); - filename = filename.slice(0, querySplit); - } + if (querySplit >= 0) { + query = filename.slice(querySplit); + filename = filename.slice(0, querySplit); + } - const lastSlashIndex = filename.lastIndexOf("/"); - const basename = - lastSlashIndex === -1 - ? filename - : filename.slice(lastSlashIndex + 1); - const data = { filename, basename, query }; + const lastSlashIndex = filename.lastIndexOf("/"); + const basename = + lastSlashIndex === -1 + ? filename + : filename.slice(lastSlashIndex + 1); + const data = { filename, basename, query }; - output.commentsFilename = compilation.getPath( - commentsFilename, - data, - ); + output.commentsFilename = compilation.getPath( + commentsFilename, + data, + ); - let banner; + let banner; - // Add a banner to the original file - if ( - /** @type {ExtractCommentsObject} */ - (this.options.extractComments).banner !== false - ) { - banner = + // Add a banner to the original file + if ( /** @type {ExtractCommentsObject} */ - (this.options.extractComments).banner || - `For license information please see ${path - .relative(path.dirname(name), output.commentsFilename) - .replace(/\\/g, "/")}`; - - if (typeof banner === "function") { - banner = banner(output.commentsFilename); + (this.options.extractComments).banner !== false + ) { + banner = + /** @type {ExtractCommentsObject} */ + (this.options.extractComments).banner || + `For license information please see ${path + .relative(path.dirname(name), output.commentsFilename) + .replace(/\\/g, "/")}`; + + if (typeof banner === "function") { + banner = banner(output.commentsFilename); + } + + if (banner) { + output.source = new ConcatSource( + shebang ? `${shebang}\n` : "", + `/*! ${banner} */\n`, + output.source, + ); + } } - if (banner) { - output.source = new ConcatSource( - shebang ? `${shebang}\n` : "", - `/*! ${banner} */\n`, - output.source, - ); - } - } + const extractedCommentsString = output.extractedComments + .sort() + .join("\n\n"); - const extractedCommentsString = output.extractedComments - .sort() - .join("\n\n"); - - output.extractedCommentsSource = new RawSource( - `${extractedCommentsString}\n`, - ); + output.extractedCommentsSource = new RawSource( + `${extractedCommentsString}\n`, + ); + } } await cacheItem.storePromise({ @@ -714,6 +717,10 @@ class TerserPlugin { } } + if (!output.source) { + return; + } + /** @type {AssetInfo} */ const newInfo = { minimized: true }; const { source, extractedCommentsSource } = output; diff --git a/src/utils.js b/src/utils.js index f8f327e..191fed9 100644 --- a/src/utils.js +++ b/src/utils.js @@ -523,7 +523,6 @@ async function uglifyJsMinify( return { code: result.code, - map: result.map ? JSON.parse(result.map) : undefined, errors: result.error ? [result.error] : [], warnings: result.warnings || [], diff --git a/test/__snapshots__/minify-option.test.js.snap b/test/__snapshots__/minify-option.test.js.snap index 24d295a..9063e48 100644 --- a/test/__snapshots__/minify-option.test.js.snap +++ b/test/__snapshots__/minify-option.test.js.snap @@ -1,5 +1,20 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`minify option should output errors and warning: errors 1`] = ` +Array [ + "Error: main.js from Terser plugin +Minimizer doesn't return result", + "Error: main.js from Terser plugin +error", +] +`; + +exports[`minify option should output errors and warning: warnings 1`] = ` +Array [ + "Warning: Error: warning", +] +`; + exports[`minify option should snapshot with extracting comments: assets 1`] = ` Object { "main.js": "/*! For license information please see main.js.LICENSE.txt */ @@ -400,6 +415,8 @@ exports[`minify option should work using when the \`minify\` option is \`uglifyJ Array [ "Error: broken.js from Terser plugin Minimizer doesn't return result", + "Error: broken.js from Terser plugin +Unterminated template literal [broken.js:1,undefined]", ] `; diff --git a/test/minify-option.test.js b/test/minify-option.test.js index b480a22..e83dca6 100644 --- a/test/minify-option.test.js +++ b/test/minify-option.test.js @@ -157,6 +157,22 @@ describe("minify option", () => { expect(getWarnings(stats)).toMatchSnapshot("warnings"); }); + it("should output errors and warning", async () => { + const compiler = getCompiler(); + + new TerserPlugin({ + minify: () => ({ + errors: [new Error("error")], + warnings: [new Error("warning")], + }), + }).apply(compiler); + + const stats = await compile(compiler); + + expect(getErrors(stats)).toMatchSnapshot("errors"); + expect(getWarnings(stats)).toMatchSnapshot("warnings"); + }); + it("should snapshot with extracting comments", async () => { const compiler = getCompiler({ entry: path.resolve(__dirname, "./fixtures/minify/es5.js"), From e079528e11f2f67b632fa135e18d8c94f058806c Mon Sep 17 00:00:00 2001 From: alexander-akait Date: Fri, 5 Dec 2025 14:07:48 +0300 Subject: [PATCH 2/3] test: update snapshot --- test/__snapshots__/TerserPlugin.test.js.snap | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/test/__snapshots__/TerserPlugin.test.js.snap b/test/__snapshots__/TerserPlugin.test.js.snap index 220ecff..4f20bc0 100644 --- a/test/__snapshots__/TerserPlugin.test.js.snap +++ b/test/__snapshots__/TerserPlugin.test.js.snap @@ -3377,8 +3377,14 @@ exports[`TerserPlugin should work, extract comments in one file and use memory c exports[`TerserPlugin should write stdout and stderr of workers to stdout and stderr of main process in not parallel mode: assets 1`] = ` Object { - "one.js": "", - "two.js": "", + "one.js": "/******/ (() => { // webpackBootstrap + +/******/ })() +;", + "two.js": "/******/ (() => { // webpackBootstrap + +/******/ })() +;", } `; @@ -3400,8 +3406,14 @@ exports[`TerserPlugin should write stdout and stderr of workers to stdout and st exports[`TerserPlugin should write stdout and stderr of workers to stdout and stderr of main process in parallel mode: assets 1`] = ` Object { - "one.js": "", - "two.js": "", + "one.js": "/******/ (() => { // webpackBootstrap + +/******/ })() +;", + "two.js": "/******/ (() => { // webpackBootstrap + +/******/ })() +;", } `; From 31adcef51c1cd1b2b9935aeea28a6ccab538781b Mon Sep 17 00:00:00 2001 From: alexander-akait Date: Fri, 5 Dec 2025 14:30:32 +0300 Subject: [PATCH 3/3] refactor: better --- src/index.js | 30 +++++++++---------- test/__snapshots__/minify-option.test.js.snap | 2 +- test/minify-option.test.js | 4 +-- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/index.js b/src/index.js index 686916e..d4aa5ec 100644 --- a/src/index.js +++ b/src/index.js @@ -596,24 +596,24 @@ class TerserPlugin { ); } - let shebang; + if (output.code) { + let shebang; - if ( - /** @type {ExtractCommentsObject} */ - (this.options.extractComments).banner !== false && - output.extractedComments && - output.extractedComments.length > 0 && - output.code.startsWith("#!") - ) { - const firstNewlinePosition = output.code.indexOf("\n"); + if ( + /** @type {ExtractCommentsObject} */ + (this.options.extractComments).banner !== false && + output.extractedComments && + output.extractedComments.length > 0 && + output.code.startsWith("#!") + ) { + const firstNewlinePosition = output.code.indexOf("\n"); - shebang = output.code.slice(0, Math.max(0, firstNewlinePosition)); - output.code = output.code.slice( - Math.max(0, firstNewlinePosition + 1), - ); - } + shebang = output.code.slice(0, Math.max(0, firstNewlinePosition)); + output.code = output.code.slice( + Math.max(0, firstNewlinePosition + 1), + ); + } - if (output.code) { if (output.map) { output.source = new SourceMapSource( output.code, diff --git a/test/__snapshots__/minify-option.test.js.snap b/test/__snapshots__/minify-option.test.js.snap index 9063e48..4e0448b 100644 --- a/test/__snapshots__/minify-option.test.js.snap +++ b/test/__snapshots__/minify-option.test.js.snap @@ -11,7 +11,7 @@ error", exports[`minify option should output errors and warning: warnings 1`] = ` Array [ - "Warning: Error: warning", + "Warning: warning", ] `; diff --git a/test/minify-option.test.js b/test/minify-option.test.js index e83dca6..c0ca6e3 100644 --- a/test/minify-option.test.js +++ b/test/minify-option.test.js @@ -162,8 +162,8 @@ describe("minify option", () => { new TerserPlugin({ minify: () => ({ - errors: [new Error("error")], - warnings: [new Error("warning")], + errors: ["error"], + warnings: ["warning"], }), }).apply(compiler);