From a69c08550315f2b87632a5832e45e43688add866 Mon Sep 17 00:00:00 2001 From: Hartorn Date: Sat, 24 Jun 2017 22:55:48 +0200 Subject: [PATCH 01/15] Updating to Uglify 3 (both ES6 or ES5), using new API # Conflicts: # src/index.js --- package.json | 4 +- src/index.js | 340 ++++++++++++++++----------------------------------- 2 files changed, 103 insertions(+), 241 deletions(-) diff --git a/package.json b/package.json index 54b30298..c0301e91 100644 --- a/package.json +++ b/package.json @@ -31,8 +31,7 @@ }, "dependencies": { "source-map": "^0.5.6", - "uglify-js": "^2.8.29", - "webpack-sources": "^1.0.1" + "uglify-es": "^3.0.19", "webpack-sources": "^1.0.1" }, "devDependencies": { "babel-cli": "^6.24.1", @@ -51,7 +50,6 @@ "nsp": "^2.6.3", "pre-commit": "^1.2.2", "standard-version": "^4.1.0", - "uglify-js": "^2.8.18", "webpack": "^3.0.0", "webpack-defaults": "^1.4.0" }, diff --git a/src/index.js b/src/index.js index 4ea3f161..69c53317 100644 --- a/src/index.js +++ b/src/index.js @@ -1,7 +1,14 @@ /* - MIT License http://www.opensource.org/licenses/mit-license.php - Author Tobias Koppers @sokra + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra */ +"use strict"; + +const SourceMapSource = require("webpack-sources").SourceMapSource; +const RawSource = require("webpack-sources").RawSource; +const RequestShortener = require("webpack/lib/RequestShortener"); +const ModuleFilenameHelpers = require("webpack/lib/ModuleFilenameHelpers"); +const uglify = require("uglify-es"); // TODO: temporarily disabled rules /* eslint-disable @@ -10,244 +17,101 @@ no-underscore-dangle, import/order */ -import { SourceMapConsumer } from 'source-map'; -import { ConcatSource, RawSource, SourceMapSource } from 'webpack-sources'; -import RequestShortener from 'webpack/lib/RequestShortener'; -import ModuleFilenameHelpers from 'webpack/lib/ModuleFilenameHelpers'; +class UglifyJsPlugin { + constructor(options) { + if(typeof options !== "object" || Array.isArray(options)) options = {}; + + this.options = Object.assign({}, options); + this.options.test = this.options.test || /\.js($|\?)/i; + this.options.warningsFilter = this.options.warningsFilter || (() => true); -import uglify from 'uglify-js'; + this.uglifyOptions = Object.assign({}, this.options.uglifyOptions || {}, { sourceMap: null }); -class UglifyJsPlugin { - constructor(options) { - if (typeof options !== 'object' || Array.isArray(options)) { - options = {}; - } - if (typeof options.compressor !== 'undefined') { - options.compress = options.compressor; - } - - this.options = options; - } - - apply(compiler) { - const { options } = this; - options.test = options.test || /\.js($|\?)/i; - const warningsFilter = options.warningsFilter || (() => true); - - const requestShortener = new RequestShortener(compiler.context); - compiler.plugin('compilation', (compilation) => { - if (options.sourceMap) { - compilation.plugin('build-module', (module) => { - // to get detailed location info about errors - module.useSourceMap = true; - }); - } - compilation.plugin('optimize-chunk-assets', (chunks, callback) => { - const files = []; - // eslint-disable-next-line prefer-spread - chunks.forEach(chunk => files.push.apply(files, chunk.files)); - // eslint-disable-next-line prefer-spread - files.push.apply(files, compilation.additionalChunkAssets); - const filteredFiles = files.filter(ModuleFilenameHelpers.matchObject.bind(undefined, options)); - const uglifiedAssets = new WeakSet(); - filteredFiles.forEach((file) => { - const oldWarnFunction = uglify.AST_Node.warn_function; - const warnings = []; - let sourceMap; - try { - const asset = compilation.assets[file]; - if (uglifiedAssets.has(asset)) { - return; - } - let input; - let inputSourceMap; - if (options.sourceMap) { - if (asset.sourceAndMap) { - const sourceAndMap = asset.sourceAndMap(); - inputSourceMap = sourceAndMap.map; - input = sourceAndMap.source; - } else { - inputSourceMap = asset.map(); - input = asset.source(); - } - sourceMap = new SourceMapConsumer(inputSourceMap); - uglify.AST_Node.warn_function = (warning) => { // eslint-disable-line camelcase - const match = /\[.+:([0-9]+),([0-9]+)\]/.exec(warning); - const line = +match[1]; - const column = +match[2]; - const original = sourceMap.originalPositionFor({ - line, - column, - }); - if (!original || !original.source || original.source === file) return; - if (!warningsFilter(original.source)) return; - warnings.push(`${warning.replace(/\[.+:([0-9]+),([0-9]+)\]/, '') - }[${requestShortener.shorten(original.source)}:${original.line},${original.column}]`); - }; - } else { - input = asset.source(); - uglify.AST_Node.warn_function = (warning) => { // eslint-disable-line camelcase - warnings.push(warning); - }; - } - uglify.base54.reset(); - let ast = uglify.parse(input, { - filename: file, - }); - if (options.compress !== false) { - ast.figure_out_scope(); - const compress = uglify.Compressor(options.compress || { - warnings: false, - }); // eslint-disable-line new-cap - ast = compress.compress(ast); - } - if (options.mangle !== false) { - ast.figure_out_scope(options.mangle || {}); - ast.compute_char_frequency(options.mangle || {}); - ast.mangle_names(options.mangle || {}); - if (options.mangle && options.mangle.props) { - uglify.mangle_properties(ast, options.mangle.props); - } - } - const output = {}; - output.comments = Object.prototype.hasOwnProperty.call(options, 'comments') ? options.comments : /^\**!|@preserve|@license/; - output.beautify = options.beautify; - for (const k in options.output) { // eslint-disable-line guard-for-in - output[k] = options.output[k]; - } - const extractedComments = []; - if (options.extractComments) { - const condition = {}; - if (typeof options.extractComments === 'string' || options.extractComments instanceof RegExp) { - // extractComments specifies the extract condition and output.comments specifies the preserve condition - condition.preserve = output.comments; - condition.extract = options.extractComments; - } else if (Object.prototype.hasOwnProperty.call(options.extractComments, 'condition')) { - // Extract condition is given in extractComments.condition - condition.preserve = output.comments; - condition.extract = options.extractComments.condition; - } else { - // No extract condition is given. Extract comments that match output.comments instead of preserving them - condition.preserve = false; - condition.extract = output.comments; - } - - // Ensure that both conditions are functions - ['preserve', 'extract'].forEach((key) => { - switch (typeof condition[key]) { - case 'boolean': { - const b = condition[key]; - condition[key] = () => b; - break; - } - case 'function': - break; - case 'string': { - if (condition[key] === 'all') { - condition[key] = () => true; - break; - } - const regex = new RegExp(condition[key]); - condition[key] = (astNode, comment) => regex.test(comment.value); - break; - } - default: { - const defaultRegex = condition[key]; - condition[key] = (astNode, comment) => defaultRegex.test(comment.value); - } - } - }); - - // Redefine the comments function to extract and preserve - // comments according to the two conditions - output.comments = (astNode, comment) => { - if (condition.extract(astNode, comment)) { - extractedComments.push( - comment.type === 'comment2' ? `/*${comment.value}*/` : `//${comment.value}`, - ); - } - return condition.preserve(astNode, comment); - }; - } - let map; - if (options.sourceMap) { - map = uglify.SourceMap({ // eslint-disable-line new-cap - file, - root: '', - }); - output.source_map = map; // eslint-disable-line camelcase - } - const stream = uglify.OutputStream(output); // eslint-disable-line new-cap - ast.print(stream); - if (map) map += ''; - const stringifiedStream = `${stream}`; - let outputSource = map ? new SourceMapSource( - stringifiedStream, file, JSON.parse(map), input, inputSourceMap // eslint-disable-line comma-dangle - ) : new RawSource(stringifiedStream); - if (extractedComments.length > 0) { - let commentsFile = options.extractComments.filename || `${file}.LICENSE`; - if (typeof commentsFile === 'function') { - commentsFile = commentsFile(file); - } - - // Write extracted comments to commentsFile - const commentsSource = new RawSource(`${extractedComments.join('\n\n')}\n`); - if (commentsFile in compilation.assets) { - // commentsFile already exists, append new comments... - if (compilation.assets[commentsFile] instanceof ConcatSource) { - compilation.assets[commentsFile].add('\n'); - compilation.assets[commentsFile].add(commentsSource); - } else { - compilation.assets[commentsFile] = new ConcatSource( - compilation.assets[commentsFile], '\n', commentsSource, - ); - } - } else { - compilation.assets[commentsFile] = commentsSource; - } - - // Add a banner to the original file - if (options.extractComments.banner !== false) { - let banner = options.extractComments.banner || `For license information please see ${commentsFile}`; - if (typeof banner === 'function') { - banner = banner(commentsFile); - } - if (banner) { - outputSource = new ConcatSource( - `/*! ${banner} */\n`, outputSource, - ); - } - } - } - uglifiedAssets.add(compilation.assets[file] = outputSource); - if (warnings.length > 0) { - compilation.warnings.push(new Error(`${file} from UglifyJs\n${warnings.join('\n')}`)); - } - } catch (err) { - if (err.line) { - const original = sourceMap && sourceMap.originalPositionFor({ - line: err.line, - column: err.col, - }); - if (original && original.source) { - compilation.errors.push(new Error(`${file} from UglifyJs\n${err.message} [${requestShortener.shorten(original.source)}:${original.line},${original.column}][${file}:${err.line},${err.col}]`)); - } else { - compilation.errors.push(new Error(`${file} from UglifyJs\n${err.message} [${file}:${err.line},${err.col}]`)); - } - } else if (err.msg) { - compilation.errors.push(new Error(`${file} from UglifyJs\n${err.msg}`)); - } else { - compilation.errors.push(new Error(`${file} from UglifyJs\n${err.stack}`)); - } - } finally { - uglify.AST_Node.warn_function = oldWarnFunction; // eslint-disable-line camelcase - } - }); - callback(); - }); - }); - } + } + + apply(compiler) { + + const requestShortener = new RequestShortener(compiler.context); + compiler.plugin("compilation", (compilation) => { + if(this.options.sourceMap) { + compilation.plugin("build-module", (module) => { + // to get detailed location info about errors + module.useSourceMap = true; + }); + } + compilation.plugin("optimize-chunk-assets", (chunks, callback) => { + const files = []; + chunks.forEach((chunk) => files.push.apply(files, chunk.files)); + files.push.apply(files, compilation.additionalChunkAssets); + const filteredFiles = files.filter(ModuleFilenameHelpers.matchObject.bind(undefined, this.options)); + filteredFiles.forEach((file) => { + // Copy uglify options + const uglifyOptions = Object.assign({}, this.uglifyOptions); + + let sourceMap; + try { + const asset = compilation.assets[file]; + if(asset.__UglifyJsPlugin) { + compilation.assets[file] = asset.__UglifyJsPlugin; + return; + } + let input; + let inputSourceMap; + if(this.options.sourceMap) { + if(asset.sourceAndMap) { + const sourceAndMap = asset.sourceAndMap(); + inputSourceMap = sourceAndMap.map; + input = sourceAndMap.source; + } else { + inputSourceMap = asset.map(); + input = asset.source(); + } + // Add source map data + uglifyOptions.sourceMap = { + content: inputSourceMap + }; + } else { + input = asset.source(); + } + + let minifyResult = uglify.minify({ [file]: input }, uglifyOptions); + + let outputSource = (minifyResult.map ? + new SourceMapSource(minifyResult.code, file, JSON.parse(minifyResult.map), input, inputSourceMap) : + new RawSource(minifyResult.code)); + + if(minifyResult.error) { + throw minifyResult.error; + } + + asset.__UglifyJsPlugin = compilation.assets[file] = outputSource; + + if(minifyResult.warnings && minifyResult.warnings.filter(this.options.warningsFilter).length > 0) { + compilation.warnings.push(new Error(file + " from UglifyJs\n" + minifyResult.warnings.filter(this.options.warningsFilter).join("\n"))); + } + + } catch(err) { + if(err.line) { + const original = sourceMap && sourceMap.originalPositionFor({ + line: err.line, + column: err.col + }); + if(original && original.source) { + compilation.errors.push(new Error(file + " from UglifyJs\n" + err.message + " [" + requestShortener.shorten(original.source) + ":" + original.line + "," + original.column + "][" + file + ":" + err.line + "," + err.col + "]")); + } else { + compilation.errors.push(new Error(file + " from UglifyJs\n" + err.message + " [" + file + ":" + err.line + "," + err.col + "]")); + } + } else if(err.msg) { + compilation.errors.push(new Error(file + " from UglifyJs\n" + err.msg)); + } else + compilation.errors.push(new Error(file + " from UglifyJs\n" + err.stack)); + } + }); + callback(); + }); + }); + } } -export default UglifyJsPlugin; +module.exports = UglifyJsPlugin; From 315a5e4777e6ec289d9bf1391f8bf62362f8791b Mon Sep 17 00:00:00 2001 From: Hartorn Date: Mon, 26 Jun 2017 15:40:06 +0200 Subject: [PATCH 02/15] Adding extractComments options handling --- src/extract-comments-handling.js | 60 ++++++++++++++++++++++++++++++++ src/index.js | 47 +++++++++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 src/extract-comments-handling.js diff --git a/src/extract-comments-handling.js b/src/extract-comments-handling.js new file mode 100644 index 00000000..2ac6cb30 --- /dev/null +++ b/src/extract-comments-handling.js @@ -0,0 +1,60 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Hartorn +*/ +"use strict"; +const buildCommentsFunction = (options, uglifyOptions, extractedComments) => { + const condition = {}; + const commentsOpts = uglifyOptions.comments || "some"; + if(typeof options.extractComments === "string" || options.extractComments instanceof RegExp) { + // extractComments specifies the extract condition and commentsOpts specifies the preserve condition + condition.preserve = commentsOpts; + condition.extract = options.extractComments; + } else if(Object.prototype.hasOwnProperty.call(options.extractComments, "condition")) { + // Extract condition is given in extractComments.condition + condition.preserve = commentsOpts; + condition.extract = options.extractComments.condition; + } else { + // No extract condition is given. Extract comments that match commentsOpts instead of preserving them + condition.preserve = false; + condition.extract = commentsOpts; + } + + // Ensure that both conditions are functions + ["preserve", "extract"].forEach(key => { + switch(typeof condition[key]) { + case "boolean": + var b = condition[key]; + condition[key] = () => b; + break; + case "function": + break; + case "string": + if(condition[key] === "all") { + condition[key] = () => true; + break; + } + if(condition[key] === "some") { + condition[key] = (astNode, comment) => comment.type === "comment2" && /@preserve|@license|@cc_on/i.test(comment.value); + } + var regex = new RegExp(condition[key]); + condition[key] = (astNode, comment) => regex.test(comment.value); + break; + default: + regex = condition[key]; + condition[key] = (astNode, comment) => regex.test(comment.value); + } + }); + + // Redefine the comments function to extract and preserve + // comments according to the two conditions + return (astNode, comment) => { + if(condition.extract(astNode, comment)) { + extractedComments.push( + comment.type === "comment2" ? "/*" + comment.value + "*/" : "//" + comment.value + ); + } + return condition.preserve(astNode, comment); + }; +}; +module.exports = buildCommentsFunction; diff --git a/src/index.js b/src/index.js index 69c53317..ef2cdee8 100644 --- a/src/index.js +++ b/src/index.js @@ -6,9 +6,11 @@ const SourceMapSource = require("webpack-sources").SourceMapSource; const RawSource = require("webpack-sources").RawSource; +const ConcatSource = require("webpack-sources").ConcatSource; const RequestShortener = require("webpack/lib/RequestShortener"); const ModuleFilenameHelpers = require("webpack/lib/ModuleFilenameHelpers"); const uglify = require("uglify-es"); +const extractCommentsHandler = require("./extract-comments-handling"); // TODO: temporarily disabled rules /* eslint-disable @@ -75,12 +77,39 @@ class UglifyJsPlugin { input = asset.source(); } + // Handling comment extraction + const extractedComments = []; + let commentsFile = false; + if(this.options.extractComments) { + uglifyOptions.comments = extractCommentsHandler(this.options, uglifyOptions, extractedComments); + + let commentsFile = this.options.extractComments.filename || file + ".LICENSE"; + if(typeof commentsFile === "function") { + commentsFile = commentsFile(file); + } + + // Handling banner + if(this.options.extractComments.banner !== false) { + let banner = this.options.extractComments.banner || "For license information please see " + commentsFile; + if(typeof banner === "function") { + banner = banner(commentsFile); + } + if(banner) { + uglifyOptions.output = uglifyOptions.output || {}; + uglifyOptions.output.preamble = uglifyOptions.output.preamble ? banner + "\n" + uglifyOptions.output.preamble : banner; + } + } + } + + // Call uglify let minifyResult = uglify.minify({ [file]: input }, uglifyOptions); + // Handling results let outputSource = (minifyResult.map ? new SourceMapSource(minifyResult.code, file, JSON.parse(minifyResult.map), input, inputSourceMap) : new RawSource(minifyResult.code)); + if(minifyResult.error) { throw minifyResult.error; } @@ -91,6 +120,24 @@ class UglifyJsPlugin { compilation.warnings.push(new Error(file + " from UglifyJs\n" + minifyResult.warnings.filter(this.options.warningsFilter).join("\n"))); } + // Write extracted comments to commentsFile + if(commentsFile) { + const commentsSource = new RawSource(extractedComments.join("\n\n") + "\n"); + if(commentsFile in compilation.assets) { + // commentsFile already exists, append new comments... + if(compilation.assets[commentsFile] instanceof ConcatSource) { + compilation.assets[commentsFile].add("\n"); + compilation.assets[commentsFile].add(commentsSource); + } else { + compilation.assets[commentsFile] = new ConcatSource( + compilation.assets[commentsFile], "\n", commentsSource + ); + } + } else { + compilation.assets[commentsFile] = commentsSource; + } + } + } catch(err) { if(err.line) { const original = sourceMap && sourceMap.originalPositionFor({ From 7152f948e887c14edce0b3c2be573b3f33301c97 Mon Sep 17 00:00:00 2001 From: Hartorn Date: Mon, 26 Jun 2017 16:46:15 +0200 Subject: [PATCH 03/15] Handling error and warnings correctly, moving comments function into class --- src/extract-comments-handling.js | 60 --------- src/index.js | 214 +++++++++++++++++++++---------- 2 files changed, 145 insertions(+), 129 deletions(-) delete mode 100644 src/extract-comments-handling.js diff --git a/src/extract-comments-handling.js b/src/extract-comments-handling.js deleted file mode 100644 index 2ac6cb30..00000000 --- a/src/extract-comments-handling.js +++ /dev/null @@ -1,60 +0,0 @@ -/* - MIT License http://www.opensource.org/licenses/mit-license.php - Author Hartorn -*/ -"use strict"; -const buildCommentsFunction = (options, uglifyOptions, extractedComments) => { - const condition = {}; - const commentsOpts = uglifyOptions.comments || "some"; - if(typeof options.extractComments === "string" || options.extractComments instanceof RegExp) { - // extractComments specifies the extract condition and commentsOpts specifies the preserve condition - condition.preserve = commentsOpts; - condition.extract = options.extractComments; - } else if(Object.prototype.hasOwnProperty.call(options.extractComments, "condition")) { - // Extract condition is given in extractComments.condition - condition.preserve = commentsOpts; - condition.extract = options.extractComments.condition; - } else { - // No extract condition is given. Extract comments that match commentsOpts instead of preserving them - condition.preserve = false; - condition.extract = commentsOpts; - } - - // Ensure that both conditions are functions - ["preserve", "extract"].forEach(key => { - switch(typeof condition[key]) { - case "boolean": - var b = condition[key]; - condition[key] = () => b; - break; - case "function": - break; - case "string": - if(condition[key] === "all") { - condition[key] = () => true; - break; - } - if(condition[key] === "some") { - condition[key] = (astNode, comment) => comment.type === "comment2" && /@preserve|@license|@cc_on/i.test(comment.value); - } - var regex = new RegExp(condition[key]); - condition[key] = (astNode, comment) => regex.test(comment.value); - break; - default: - regex = condition[key]; - condition[key] = (astNode, comment) => regex.test(comment.value); - } - }); - - // Redefine the comments function to extract and preserve - // comments according to the two conditions - return (astNode, comment) => { - if(condition.extract(astNode, comment)) { - extractedComments.push( - comment.type === "comment2" ? "/*" + comment.value + "*/" : "//" + comment.value - ); - } - return condition.preserve(astNode, comment); - }; -}; -module.exports = buildCommentsFunction; diff --git a/src/index.js b/src/index.js index ef2cdee8..1387c9d0 100644 --- a/src/index.js +++ b/src/index.js @@ -4,13 +4,13 @@ */ "use strict"; +const SourceMapConsumer = require("source-map").SourceMapConsumer; const SourceMapSource = require("webpack-sources").SourceMapSource; const RawSource = require("webpack-sources").RawSource; const ConcatSource = require("webpack-sources").ConcatSource; const RequestShortener = require("webpack/lib/RequestShortener"); const ModuleFilenameHelpers = require("webpack/lib/ModuleFilenameHelpers"); const uglify = require("uglify-es"); -const extractCommentsHandler = require("./extract-comments-handling"); // TODO: temporarily disabled rules /* eslint-disable @@ -24,24 +24,117 @@ class UglifyJsPlugin { constructor(options) { if(typeof options !== "object" || Array.isArray(options)) options = {}; - this.options = Object.assign({}, options); + this.options = options || {}; this.options.test = this.options.test || /\.js($|\?)/i; this.options.warningsFilter = this.options.warningsFilter || (() => true); this.uglifyOptions = Object.assign({}, this.options.uglifyOptions || {}, { sourceMap: null }); + } + + buildError(err, file, sourceMap, requestShortener) { + if(err.line) { // Handling error which should have line, col, filename and message + const original = sourceMap && sourceMap.originalPositionFor({ + line: err.line, + column: err.col + }); + if(original && original.source) { + return new Error(file + " from UglifyJs\n" + err.message + " [" + requestShortener.shorten(original.source) + ":" + original.line + "," + original.column + "][" + file + ":" + err.line + "," + err.col + "]"); + } + return new Error(file + " from UglifyJs\n" + err.message + " [" + file + ":" + err.line + "," + err.col + "]"); + } else if(err.msg) { + return new Error(file + " from UglifyJs\n" + err.msg); + } else if(err.message) { //Pretty sure if should be message and not msg + return new Error(file + " from UglifyJs\n" + err.message); + } + return new Error(file + " from UglifyJs\n" + err.stack); + } + buildWarnings(warnings, file, sourceMap, warningsFilter, requestShortener) { + return warnings.reduce((accWarnings, warning) => { + if(!sourceMap) { + accWarnings.push(warning); + } else { + const match = /\[.+:([0-9]+),([0-9]+)\]/.exec(warning); + const line = +match[1]; + const column = +match[2]; + const original = sourceMap.originalPositionFor({ + line: line, + column: column + }); + + if(original && !original.source && original.source !== file && !warningsFilter(original.source)) { + accWarnings.push(warning.replace(/\[.+:([0-9]+),([0-9]+)\]/, "") + "[" + requestShortener.shorten(original.source) + ":" + original.line + "," + original.column + "]"); + } + + } + return accWarnings; + }, []); + } + + buildCommentsFunction(options, uglifyOptions, extractedComments) { + const condition = {}; + const commentsOpts = uglifyOptions.comments || "some"; + if(typeof options.extractComments === "string" || options.extractComments instanceof RegExp) { + // extractComments specifies the extract condition and commentsOpts specifies the preserve condition + condition.preserve = commentsOpts; + condition.extract = options.extractComments; + } else if(Object.prototype.hasOwnProperty.call(options.extractComments, "condition")) { + // Extract condition is given in extractComments.condition + condition.preserve = commentsOpts; + condition.extract = options.extractComments.condition; + } else { + // No extract condition is given. Extract comments that match commentsOpts instead of preserving them + condition.preserve = false; + condition.extract = commentsOpts; + } + + // Ensure that both conditions are functions + ["preserve", "extract"].forEach(key => { + switch(typeof condition[key]) { + case "boolean": + condition[key] = () => condition[key]; + break; + case "function": + break; + case "string": + if(condition[key] === "all") { + condition[key] = () => true; + break; + } + if(condition[key] === "some") { + condition[key] = (astNode, comment) => comment.type === "comment2" && /@preserve|@license|@cc_on/i.test(comment.value); + } + condition[key] = (astNode, comment) => new RegExp(condition[key]).test(comment.value); + break; + default: + condition[key] = (astNode, comment) => condition[key].test(comment.value); + } + }); + + // Redefine the comments function to extract and preserve + // comments according to the two conditions + return (astNode, comment) => { + if(condition.extract(astNode, comment)) { + extractedComments.push( + comment.type === "comment2" ? "/*" + comment.value + "*/" : "//" + comment.value + ); + } + return condition.preserve(astNode, comment); + }; } apply(compiler) { const requestShortener = new RequestShortener(compiler.context); compiler.plugin("compilation", (compilation) => { + if(this.options.sourceMap) { compilation.plugin("build-module", (module) => { // to get detailed location info about errors module.useSourceMap = true; }); } + compilation.plugin("optimize-chunk-assets", (chunks, callback) => { const files = []; chunks.forEach((chunk) => files.push.apply(files, chunk.files)); @@ -51,73 +144,72 @@ class UglifyJsPlugin { // Copy uglify options const uglifyOptions = Object.assign({}, this.uglifyOptions); - let sourceMap; - try { - const asset = compilation.assets[file]; - if(asset.__UglifyJsPlugin) { - compilation.assets[file] = asset.__UglifyJsPlugin; - return; - } - let input; - let inputSourceMap; - if(this.options.sourceMap) { - if(asset.sourceAndMap) { - const sourceAndMap = asset.sourceAndMap(); - inputSourceMap = sourceAndMap.map; - input = sourceAndMap.source; - } else { - inputSourceMap = asset.map(); - input = asset.source(); - } - // Add source map data - uglifyOptions.sourceMap = { - content: inputSourceMap - }; + const asset = compilation.assets[file]; + if(asset.__UglifyJsPlugin) { + compilation.assets[file] = asset.__UglifyJsPlugin; + return; + } + let input, inputSourceMap, sourceMap; + + if(this.options.sourceMap) { + if(asset.sourceAndMap) { + const sourceAndMap = asset.sourceAndMap(); + inputSourceMap = sourceAndMap.map; + input = sourceAndMap.source; } else { + inputSourceMap = asset.map(); input = asset.source(); } + sourceMap = new SourceMapConsumer(inputSourceMap); + // Add source map data + uglifyOptions.sourceMap = { + content: inputSourceMap + }; + } else { + input = asset.source(); + } - // Handling comment extraction - const extractedComments = []; - let commentsFile = false; - if(this.options.extractComments) { - uglifyOptions.comments = extractCommentsHandler(this.options, uglifyOptions, extractedComments); + // Handling comment extraction + const extractedComments = []; + let commentsFile = false; + if(this.options.extractComments) { + uglifyOptions.comments = this.buildCommentsFunction(this.options, uglifyOptions, extractedComments); - let commentsFile = this.options.extractComments.filename || file + ".LICENSE"; - if(typeof commentsFile === "function") { - commentsFile = commentsFile(file); - } + let commentsFile = this.options.extractComments.filename || file + ".LICENSE"; + if(typeof commentsFile === "function") { + commentsFile = commentsFile(file); + } - // Handling banner - if(this.options.extractComments.banner !== false) { - let banner = this.options.extractComments.banner || "For license information please see " + commentsFile; - if(typeof banner === "function") { - banner = banner(commentsFile); - } - if(banner) { - uglifyOptions.output = uglifyOptions.output || {}; - uglifyOptions.output.preamble = uglifyOptions.output.preamble ? banner + "\n" + uglifyOptions.output.preamble : banner; - } + // Handling banner + if(this.options.extractComments.banner !== false) { + let banner = this.options.extractComments.banner || "For license information please see " + commentsFile; + if(typeof banner === "function") { + banner = banner(commentsFile); + } + if(banner) { + uglifyOptions.output = uglifyOptions.output || {}; + uglifyOptions.output.preamble = uglifyOptions.output.preamble ? banner + "\n" + uglifyOptions.output.preamble : banner; } } + } - // Call uglify - let minifyResult = uglify.minify({ [file]: input }, uglifyOptions); + // Calling uglify + let minifyResult = uglify.minify({ [file]: input }, uglifyOptions); - // Handling results + // Handling results + if(minifyResult.error) { + compilation.errors.push(this.buildError(minifyResult.error, file, sourceMap, compilation, requestShortener)); + } else { let outputSource = (minifyResult.map ? new SourceMapSource(minifyResult.code, file, JSON.parse(minifyResult.map), input, inputSourceMap) : new RawSource(minifyResult.code)); - - if(minifyResult.error) { - throw minifyResult.error; - } - asset.__UglifyJsPlugin = compilation.assets[file] = outputSource; - if(minifyResult.warnings && minifyResult.warnings.filter(this.options.warningsFilter).length > 0) { - compilation.warnings.push(new Error(file + " from UglifyJs\n" + minifyResult.warnings.filter(this.options.warningsFilter).join("\n"))); + // Handling warnings + if(minifyResult.warnings) { + const buildWarnings = this.buildWarnings(minifyResult.warnings, file, sourceMap, this.options.warningsFilter, requestShortener); + compilation.warnings.push(new Error(file + " from UglifyJs\n" + buildWarnings.join("\n"))); } // Write extracted comments to commentsFile @@ -137,22 +229,6 @@ class UglifyJsPlugin { compilation.assets[commentsFile] = commentsSource; } } - - } catch(err) { - if(err.line) { - const original = sourceMap && sourceMap.originalPositionFor({ - line: err.line, - column: err.col - }); - if(original && original.source) { - compilation.errors.push(new Error(file + " from UglifyJs\n" + err.message + " [" + requestShortener.shorten(original.source) + ":" + original.line + "," + original.column + "][" + file + ":" + err.line + "," + err.col + "]")); - } else { - compilation.errors.push(new Error(file + " from UglifyJs\n" + err.message + " [" + file + ":" + err.line + "," + err.col + "]")); - } - } else if(err.msg) { - compilation.errors.push(new Error(file + " from UglifyJs\n" + err.msg)); - } else - compilation.errors.push(new Error(file + " from UglifyJs\n" + err.stack)); } }); callback(); From 07b37a06b0e9c45b1b5873d7114771d40ac78c1b Mon Sep 17 00:00:00 2001 From: Hartorn Date: Mon, 26 Jun 2017 23:35:26 +0200 Subject: [PATCH 04/15] Correcting small mistakes --- src/index.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/index.js b/src/index.js index 1387c9d0..4ff8d7d0 100644 --- a/src/index.js +++ b/src/index.js @@ -62,7 +62,7 @@ class UglifyJsPlugin { column: column }); - if(original && !original.source && original.source !== file && !warningsFilter(original.source)) { + if(original && original.source && original.source !== file && warningsFilter(original.source)) { accWarnings.push(warning.replace(/\[.+:([0-9]+),([0-9]+)\]/, "") + "[" + requestShortener.shorten(original.source) + ":" + original.line + "," + original.column + "]"); } @@ -73,7 +73,7 @@ class UglifyJsPlugin { buildCommentsFunction(options, uglifyOptions, extractedComments) { const condition = {}; - const commentsOpts = uglifyOptions.comments || "some"; + const commentsOpts = uglifyOptions.output && uglifyOptions.output.comments || "some"; if(typeof options.extractComments === "string" || options.extractComments instanceof RegExp) { // extractComments specifies the extract condition and commentsOpts specifies the preserve condition condition.preserve = commentsOpts; @@ -87,12 +87,11 @@ class UglifyJsPlugin { condition.preserve = false; condition.extract = commentsOpts; } - // Ensure that both conditions are functions ["preserve", "extract"].forEach(key => { switch(typeof condition[key]) { case "boolean": - condition[key] = () => condition[key]; + condition[key] = condition[key] ? () => true : () => false; break; case "function": break; @@ -173,16 +172,17 @@ class UglifyJsPlugin { const extractedComments = []; let commentsFile = false; if(this.options.extractComments) { - uglifyOptions.comments = this.buildCommentsFunction(this.options, uglifyOptions, extractedComments); + uglifyOptions.output = uglifyOptions.output || {}; + uglifyOptions.output.comments = this.buildCommentsFunction(this.options, uglifyOptions, extractedComments); - let commentsFile = this.options.extractComments.filename || file + ".LICENSE"; + commentsFile = this.options.extractComments.filename || file + ".LICENSE"; if(typeof commentsFile === "function") { commentsFile = commentsFile(file); } // Handling banner if(this.options.extractComments.banner !== false) { - let banner = this.options.extractComments.banner || "For license information please see " + commentsFile; + let banner = this.options.extractComments.banner || "/** For license information please see " + commentsFile + " */"; if(typeof banner === "function") { banner = banner(commentsFile); } From 49c199d4c3228e2a6ec12586f38effc68c5f6505 Mon Sep 17 00:00:00 2001 From: Hartorn Date: Wed, 28 Jun 2017 14:44:16 +0200 Subject: [PATCH 05/15] Correcting lint (tab, space, ...) --- src/index.js | 455 ++++++++++++++++++++++++++------------------------- 1 file changed, 229 insertions(+), 226 deletions(-) diff --git a/src/index.js b/src/index.js index 4ff8d7d0..1a515a2e 100644 --- a/src/index.js +++ b/src/index.js @@ -1,240 +1,243 @@ /* - MIT License http://www.opensource.org/licenses/mit-license.php - Author Tobias Koppers @sokra + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra */ -"use strict"; -const SourceMapConsumer = require("source-map").SourceMapConsumer; -const SourceMapSource = require("webpack-sources").SourceMapSource; -const RawSource = require("webpack-sources").RawSource; -const ConcatSource = require("webpack-sources").ConcatSource; -const RequestShortener = require("webpack/lib/RequestShortener"); -const ModuleFilenameHelpers = require("webpack/lib/ModuleFilenameHelpers"); -const uglify = require("uglify-es"); +import { SourceMapConsumer } from 'source-map'; +import { SourceMapSource, RawSource, ConcatSource } from 'webpack-sources'; +import { RequestShortener } from 'webpack/lib/RequestShortener'; +import ModuleFilenameHelpers from 'webpack/lib/ModuleFilenameHelpers'; +import uglify from 'uglify-es'; // TODO: temporarily disabled rules /* eslint-disable no-undefined, no-param-reassign, - no-underscore-dangle, - import/order + no-underscore-dangle */ class UglifyJsPlugin { - constructor(options) { - if(typeof options !== "object" || Array.isArray(options)) options = {}; - - this.options = options || {}; - this.options.test = this.options.test || /\.js($|\?)/i; - this.options.warningsFilter = this.options.warningsFilter || (() => true); - - this.uglifyOptions = Object.assign({}, this.options.uglifyOptions || {}, { sourceMap: null }); - } - - buildError(err, file, sourceMap, requestShortener) { - if(err.line) { // Handling error which should have line, col, filename and message - const original = sourceMap && sourceMap.originalPositionFor({ - line: err.line, - column: err.col - }); - if(original && original.source) { - return new Error(file + " from UglifyJs\n" + err.message + " [" + requestShortener.shorten(original.source) + ":" + original.line + "," + original.column + "][" + file + ":" + err.line + "," + err.col + "]"); - } - return new Error(file + " from UglifyJs\n" + err.message + " [" + file + ":" + err.line + "," + err.col + "]"); - } else if(err.msg) { - return new Error(file + " from UglifyJs\n" + err.msg); - } else if(err.message) { //Pretty sure if should be message and not msg - return new Error(file + " from UglifyJs\n" + err.message); - } - return new Error(file + " from UglifyJs\n" + err.stack); - } - - buildWarnings(warnings, file, sourceMap, warningsFilter, requestShortener) { - return warnings.reduce((accWarnings, warning) => { - if(!sourceMap) { - accWarnings.push(warning); - } else { - const match = /\[.+:([0-9]+),([0-9]+)\]/.exec(warning); - const line = +match[1]; - const column = +match[2]; - const original = sourceMap.originalPositionFor({ - line: line, - column: column - }); - - if(original && original.source && original.source !== file && warningsFilter(original.source)) { - accWarnings.push(warning.replace(/\[.+:([0-9]+),([0-9]+)\]/, "") + "[" + requestShortener.shorten(original.source) + ":" + original.line + "," + original.column + "]"); - } - - } - return accWarnings; - }, []); - } - - buildCommentsFunction(options, uglifyOptions, extractedComments) { - const condition = {}; - const commentsOpts = uglifyOptions.output && uglifyOptions.output.comments || "some"; - if(typeof options.extractComments === "string" || options.extractComments instanceof RegExp) { - // extractComments specifies the extract condition and commentsOpts specifies the preserve condition - condition.preserve = commentsOpts; - condition.extract = options.extractComments; - } else if(Object.prototype.hasOwnProperty.call(options.extractComments, "condition")) { - // Extract condition is given in extractComments.condition - condition.preserve = commentsOpts; - condition.extract = options.extractComments.condition; - } else { - // No extract condition is given. Extract comments that match commentsOpts instead of preserving them - condition.preserve = false; - condition.extract = commentsOpts; - } - // Ensure that both conditions are functions - ["preserve", "extract"].forEach(key => { - switch(typeof condition[key]) { - case "boolean": - condition[key] = condition[key] ? () => true : () => false; - break; - case "function": - break; - case "string": - if(condition[key] === "all") { - condition[key] = () => true; - break; - } - if(condition[key] === "some") { - condition[key] = (astNode, comment) => comment.type === "comment2" && /@preserve|@license|@cc_on/i.test(comment.value); - } - condition[key] = (astNode, comment) => new RegExp(condition[key]).test(comment.value); - break; - default: - condition[key] = (astNode, comment) => condition[key].test(comment.value); - } - }); - - // Redefine the comments function to extract and preserve - // comments according to the two conditions - return (astNode, comment) => { - if(condition.extract(astNode, comment)) { - extractedComments.push( - comment.type === "comment2" ? "/*" + comment.value + "*/" : "//" + comment.value - ); - } - return condition.preserve(astNode, comment); - }; - } - - apply(compiler) { - - const requestShortener = new RequestShortener(compiler.context); - compiler.plugin("compilation", (compilation) => { - - if(this.options.sourceMap) { - compilation.plugin("build-module", (module) => { - // to get detailed location info about errors - module.useSourceMap = true; - }); - } - - compilation.plugin("optimize-chunk-assets", (chunks, callback) => { - const files = []; - chunks.forEach((chunk) => files.push.apply(files, chunk.files)); - files.push.apply(files, compilation.additionalChunkAssets); - const filteredFiles = files.filter(ModuleFilenameHelpers.matchObject.bind(undefined, this.options)); - filteredFiles.forEach((file) => { - // Copy uglify options - const uglifyOptions = Object.assign({}, this.uglifyOptions); - - const asset = compilation.assets[file]; - if(asset.__UglifyJsPlugin) { - compilation.assets[file] = asset.__UglifyJsPlugin; - return; - } - let input, inputSourceMap, sourceMap; - - if(this.options.sourceMap) { - if(asset.sourceAndMap) { - const sourceAndMap = asset.sourceAndMap(); - inputSourceMap = sourceAndMap.map; - input = sourceAndMap.source; - } else { - inputSourceMap = asset.map(); - input = asset.source(); - } - sourceMap = new SourceMapConsumer(inputSourceMap); - // Add source map data - uglifyOptions.sourceMap = { - content: inputSourceMap - }; - } else { - input = asset.source(); - } - - // Handling comment extraction - const extractedComments = []; - let commentsFile = false; - if(this.options.extractComments) { - uglifyOptions.output = uglifyOptions.output || {}; - uglifyOptions.output.comments = this.buildCommentsFunction(this.options, uglifyOptions, extractedComments); - - commentsFile = this.options.extractComments.filename || file + ".LICENSE"; - if(typeof commentsFile === "function") { - commentsFile = commentsFile(file); - } - - // Handling banner - if(this.options.extractComments.banner !== false) { - let banner = this.options.extractComments.banner || "/** For license information please see " + commentsFile + " */"; - if(typeof banner === "function") { - banner = banner(commentsFile); - } - if(banner) { - uglifyOptions.output = uglifyOptions.output || {}; - uglifyOptions.output.preamble = uglifyOptions.output.preamble ? banner + "\n" + uglifyOptions.output.preamble : banner; - } - } - } - - // Calling uglify - let minifyResult = uglify.minify({ [file]: input }, uglifyOptions); - - // Handling results - if(minifyResult.error) { - compilation.errors.push(this.buildError(minifyResult.error, file, sourceMap, compilation, requestShortener)); - } else { - let outputSource = (minifyResult.map ? - new SourceMapSource(minifyResult.code, file, JSON.parse(minifyResult.map), input, inputSourceMap) : - new RawSource(minifyResult.code)); - - asset.__UglifyJsPlugin = compilation.assets[file] = outputSource; - - // Handling warnings - if(minifyResult.warnings) { - const buildWarnings = this.buildWarnings(minifyResult.warnings, file, sourceMap, this.options.warningsFilter, requestShortener); - compilation.warnings.push(new Error(file + " from UglifyJs\n" + buildWarnings.join("\n"))); - } - - // Write extracted comments to commentsFile - if(commentsFile) { - const commentsSource = new RawSource(extractedComments.join("\n\n") + "\n"); - if(commentsFile in compilation.assets) { - // commentsFile already exists, append new comments... - if(compilation.assets[commentsFile] instanceof ConcatSource) { - compilation.assets[commentsFile].add("\n"); - compilation.assets[commentsFile].add(commentsSource); - } else { - compilation.assets[commentsFile] = new ConcatSource( - compilation.assets[commentsFile], "\n", commentsSource - ); - } - } else { - compilation.assets[commentsFile] = commentsSource; - } - } - } - }); - callback(); - }); - }); - } + constructor(options) { + if (typeof options !== 'object' || Array.isArray(options)) { + this.options = {}; + } else { + this.options = options || {}; + } + + this.options.test = this.options.test || /\.js($|\?)/i; + this.options.warningsFilter = this.options.warningsFilter || (() => true); + + this.uglifyOptions = { ...this.options.uglifyOptions, sourceMap: null }; + } + + static buildError(err, file, sourceMap, requestShortener) { + // Handling error which should have line, col, filename and message + if (err.line) { + const original = sourceMap && sourceMap.originalPositionFor({ + line: err.line, + column: err.col, + }); + if (original && original.source) { + return new Error(`${file} from UglifyJs\n${err.message} [${requestShortener.shorten(original.source)}:${original.line},${original.column}][${file}:${err.line},${err.col}]`); + } + return new Error(`${file} from UglifyJs\n${err.message} [${file}:${err.line},${err.col}]`); + } else if (err.msg) { + return new Error(`${file} from UglifyJs\n${err.msg}`); + } else if (err.message) { + // Pretty sure if should be message and not msg + return new Error(`${file} from UglifyJs\n${err.message}`); + } + return new Error(`${file} from UglifyJs\n${err.stack}`); + } + + static buildWarnings(warnings, file, sourceMap, warningsFilter, requestShortener) { + return warnings.reduce((accWarnings, warning) => { + if (!sourceMap) { + accWarnings.push(warning); + } else { + const match = /\[.+:([0-9]+),([0-9]+)\]/.exec(warning); + const line = +match[1]; + const column = +match[2]; + const original = sourceMap.originalPositionFor({ + line, + column, + }); + + if (original && original.source && original.source !== file && warningsFilter(original.source)) { + accWarnings.push(`${warning.replace(/\[.+:([0-9]+),([0-9]+)\]/, '')}[${requestShortener.shorten(original.source)}:${original.line},${original.column}]`); + } + } + return accWarnings; + }, []); + } + + static buildCommentsFunction(options, uglifyOptions, extractedComments) { + const condition = {}; + const commentsOpts = (uglifyOptions.output && uglifyOptions.output.comments) || 'some'; + if (typeof options.extractComments === 'string' || options.extractComments instanceof RegExp) { + // extractComments specifies the extract condition and commentsOpts specifies the preserve condition + condition.preserve = commentsOpts; + condition.extract = options.extractComments; + } else if (Object.prototype.hasOwnProperty.call(options.extractComments, 'condition')) { + // Extract condition is given in extractComments.condition + condition.preserve = commentsOpts; + condition.extract = options.extractComments.condition; + } else { + // No extract condition is given. Extract comments that match commentsOpts instead of preserving them + condition.preserve = false; + condition.extract = commentsOpts; + } + // Ensure that both conditions are functions + ['preserve', 'extract'].forEach((key) => { + switch (typeof condition[key]) { + case 'boolean': + condition[key] = condition[key] ? () => true : () => false; + break; + case 'function': + break; + case 'string': + if (condition[key] === 'all') { + condition[key] = () => true; + break; + } + if (condition[key] === 'some') { + condition[key] = (astNode, comment) => comment.type === 'comment2' && /@preserve|@license|@cc_on/i.test(comment.value); + } + condition[key] = (astNode, comment) => new RegExp(condition[key]).test(comment.value); + break; + default: + condition[key] = (astNode, comment) => condition[key].test(comment.value); + } + }); + + // Redefine the comments function to extract and preserve + // comments according to the two conditions + return (astNode, comment) => { + if (condition.extract(astNode, comment)) { + extractedComments.push( + comment.type === 'comment2' ? `/*${comment.value}*/` : `//${comment.value}`, + ); + } + return condition.preserve(astNode, comment); + }; + } + + apply(compiler) { + const requestShortener = new RequestShortener(compiler.context); + compiler.plugin('compilation', (compilation) => { + if (this.options.sourceMap) { + compilation.plugin('build-module', (module) => { + // to get detailed location info about errors + module.useSourceMap = true; + }); + } + + compilation.plugin('optimize-chunk-assets', (chunks, callback) => { + const files = []; + chunks.forEach(chunk => files.push(...chunk.files)); + files.push(...compilation.additionalChunkAssets); + const filteredFiles = files.filter(ModuleFilenameHelpers.matchObject.bind(undefined, this.options)); + filteredFiles.forEach((file) => { + // Copy uglify options + const uglifyOptions = Object.assign({}, this.uglifyOptions); + + const asset = compilation.assets[file]; + if (asset.__UglifyJsPlugin) { + compilation.assets[file] = asset.__UglifyJsPlugin; + return; + } + let input; + let inputSourceMap; + let sourceMap; + + if (this.options.sourceMap) { + if (asset.sourceAndMap) { + const sourceAndMap = asset.sourceAndMap(); + inputSourceMap = sourceAndMap.map; + input = sourceAndMap.source; + } else { + inputSourceMap = asset.map(); + input = asset.source(); + } + sourceMap = new SourceMapConsumer(inputSourceMap); + // Add source map data + uglifyOptions.sourceMap = { + content: inputSourceMap, + }; + } else { + input = asset.source(); + } + + // Handling comment extraction + const extractedComments = []; + let commentsFile = false; + if (this.options.extractComments) { + uglifyOptions.output = uglifyOptions.output || {}; + uglifyOptions.output.comments = this.buildCommentsFunction(this.options, uglifyOptions, extractedComments); + + commentsFile = this.options.extractComments.filename || `${file}.LICENSE`; + if (typeof commentsFile === 'function') { + commentsFile = commentsFile(file); + } + + // Handling banner + if (this.options.extractComments.banner !== false) { + let banner = this.options.extractComments.banner || `/** For license information please see ${commentsFile} */`; + if (typeof banner === 'function') { + banner = banner(commentsFile); + } + if (banner) { + uglifyOptions.output = uglifyOptions.output || {}; + uglifyOptions.output.preamble = uglifyOptions.output.preamble ? `${banner}\n${uglifyOptions.output.preamble}` : banner; + } + } + } + + // Calling uglify + const { error, map, code, warnings } = uglify.minify({ [file]: input }, uglifyOptions); + + // Handling results + if (error) { + compilation.errors.push(this.buildError(error, file, sourceMap, compilation, requestShortener)); + } else { + let outputSource; + if (map) { + outputSource = new SourceMapSource(code, file, JSON.parse(map), input, inputSourceMap); + } else { + outputSource = new RawSource(code); + } + compilation.assets[file] = outputSource; + asset.__UglifyJsPlugin = outputSource; + + // Handling warnings + if (warnings) { + const buildWarnings = this.buildWarnings(warnings, file, sourceMap, this.options.warningsFilter, requestShortener); + compilation.warnings.push(new Error(`${file} from UglifyJs\n${buildWarnings.join('\n')}`)); + } + + // Write extracted comments to commentsFile + if (commentsFile) { + const commentsSource = new RawSource(`${extractedComments.join('\n\n')}\n`); + if (commentsFile in compilation.assets) { + // commentsFile already exists, append new comments... + if (compilation.assets[commentsFile] instanceof ConcatSource) { + compilation.assets[commentsFile].add('\n'); + compilation.assets[commentsFile].add(commentsSource); + } else { + compilation.assets[commentsFile] = new ConcatSource( + compilation.assets[commentsFile], '\n', commentsSource, + ); + } + } else { + compilation.assets[commentsFile] = commentsSource; + } + } + } + }); + callback(); + }); + }); + } } module.exports = UglifyJsPlugin; From 35d9f9d1578c7225539cdd873971dbb72960512b Mon Sep 17 00:00:00 2001 From: Hartorn Date: Wed, 28 Jun 2017 15:01:18 +0200 Subject: [PATCH 06/15] Correcting package.json spacing, correcting export # Conflicts: # package.json --- package.json | 6 ++++-- src/index.js | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index c0301e91..7249bb7b 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,8 @@ }, "dependencies": { "source-map": "^0.5.6", - "uglify-es": "^3.0.19", "webpack-sources": "^1.0.1" + "uglify-es": "^3.0.19", + "webpack-sources": "^1.0.1" }, "devDependencies": { "babel-cli": "^6.24.1", @@ -78,5 +79,6 @@ "eslint --fix", "git add" ] - } } +} + diff --git a/src/index.js b/src/index.js index 1a515a2e..d5e38f5b 100644 --- a/src/index.js +++ b/src/index.js @@ -240,4 +240,4 @@ class UglifyJsPlugin { } } -module.exports = UglifyJsPlugin; +export default UglifyJsPlugin; From 7e42082a8d6fb1bd5b4905f6f288f74befa30c4e Mon Sep 17 00:00:00 2001 From: Hartorn Date: Thu, 29 Jun 2017 23:09:15 +0200 Subject: [PATCH 07/15] Correcting static function calls, changing file list building, fixing eslint --- package.json | 3 +- src/index.js | 185 +++++++++++++++++++++++++-------------------------- 2 files changed, 91 insertions(+), 97 deletions(-) diff --git a/package.json b/package.json index 7249bb7b..6a995cb6 100644 --- a/package.json +++ b/package.json @@ -79,6 +79,5 @@ "eslint --fix", "git add" ] + } } -} - diff --git a/src/index.js b/src/index.js index d5e38f5b..0c0c6765 100644 --- a/src/index.js +++ b/src/index.js @@ -5,17 +5,10 @@ import { SourceMapConsumer } from 'source-map'; import { SourceMapSource, RawSource, ConcatSource } from 'webpack-sources'; -import { RequestShortener } from 'webpack/lib/RequestShortener'; +import RequestShortener from 'webpack/lib/RequestShortener'; import ModuleFilenameHelpers from 'webpack/lib/ModuleFilenameHelpers'; import uglify from 'uglify-es'; -// TODO: temporarily disabled rules -/* eslint-disable - no-undefined, - no-param-reassign, - no-underscore-dangle -*/ - class UglifyJsPlugin { constructor(options) { if (typeof options !== 'object' || Array.isArray(options)) { @@ -124,116 +117,118 @@ class UglifyJsPlugin { apply(compiler) { const requestShortener = new RequestShortener(compiler.context); - compiler.plugin('compilation', (compilation) => { + compiler.plugin('compilation', (compilationArg) => { + const compilation = compilationArg; + if (this.options.sourceMap) { - compilation.plugin('build-module', (module) => { + compilation.plugin('build-module', (moduleArg) => { // to get detailed location info about errors - module.useSourceMap = true; + const moduleVar = moduleArg; + moduleVar.useSourceMap = true; }); } compilation.plugin('optimize-chunk-assets', (chunks, callback) => { - const files = []; - chunks.forEach(chunk => files.push(...chunk.files)); - files.push(...compilation.additionalChunkAssets); - const filteredFiles = files.filter(ModuleFilenameHelpers.matchObject.bind(undefined, this.options)); - filteredFiles.forEach((file) => { - // Copy uglify options - const uglifyOptions = Object.assign({}, this.uglifyOptions); - - const asset = compilation.assets[file]; - if (asset.__UglifyJsPlugin) { - compilation.assets[file] = asset.__UglifyJsPlugin; - return; - } - let input; - let inputSourceMap; - let sourceMap; - - if (this.options.sourceMap) { - if (asset.sourceAndMap) { - const sourceAndMap = asset.sourceAndMap(); - inputSourceMap = sourceAndMap.map; - input = sourceAndMap.source; + chunks.reduce((acc, chunk) => acc.concat(chunk.files || []), []) + .concat(compilation.additionalChunkAssets || []) + .filter(ModuleFilenameHelpers.matchObject.bind(null, this.options)) + .forEach((file) => { + // Copy uglify options + const uglifyOptions = Object.assign({}, this.uglifyOptions); + + const asset = compilation.assets[file]; + if (asset.uglifiedAsset) { + compilation.assets[file] = asset.uglifiedAsset; + return; + } + let input; + let inputSourceMap; + let sourceMap; + + if (this.options.sourceMap) { + if (asset.sourceAndMap) { + const sourceAndMap = asset.sourceAndMap(); + inputSourceMap = sourceAndMap.map; + input = sourceAndMap.source; + } else { + inputSourceMap = asset.map(); + input = asset.source(); + } + sourceMap = new SourceMapConsumer(inputSourceMap); + // Add source map data + uglifyOptions.sourceMap = { + content: inputSourceMap, + }; } else { - inputSourceMap = asset.map(); input = asset.source(); } - sourceMap = new SourceMapConsumer(inputSourceMap); - // Add source map data - uglifyOptions.sourceMap = { - content: inputSourceMap, - }; - } else { - input = asset.source(); - } - // Handling comment extraction - const extractedComments = []; - let commentsFile = false; - if (this.options.extractComments) { - uglifyOptions.output = uglifyOptions.output || {}; - uglifyOptions.output.comments = this.buildCommentsFunction(this.options, uglifyOptions, extractedComments); + // Handling comment extraction + const extractedComments = []; + let commentsFile = false; + if (this.options.extractComments) { + uglifyOptions.output = uglifyOptions.output || {}; + uglifyOptions.output.comments = UglifyJsPlugin.buildCommentsFunction(this.options, uglifyOptions, extractedComments); - commentsFile = this.options.extractComments.filename || `${file}.LICENSE`; - if (typeof commentsFile === 'function') { - commentsFile = commentsFile(file); - } - - // Handling banner - if (this.options.extractComments.banner !== false) { - let banner = this.options.extractComments.banner || `/** For license information please see ${commentsFile} */`; - if (typeof banner === 'function') { - banner = banner(commentsFile); + commentsFile = this.options.extractComments.filename || `${file}.LICENSE`; + if (typeof commentsFile === 'function') { + commentsFile = commentsFile(file); } - if (banner) { - uglifyOptions.output = uglifyOptions.output || {}; - uglifyOptions.output.preamble = uglifyOptions.output.preamble ? `${banner}\n${uglifyOptions.output.preamble}` : banner; + + // Handling banner + if (this.options.extractComments.banner !== false) { + let banner = this.options.extractComments.banner || `/** For license information please see ${commentsFile} */`; + if (typeof banner === 'function') { + banner = banner(commentsFile); + } + if (banner) { + uglifyOptions.output = uglifyOptions.output || {}; + uglifyOptions.output.preamble = uglifyOptions.output.preamble ? `${banner}\n${uglifyOptions.output.preamble}` : banner; + } } } - } - // Calling uglify - const { error, map, code, warnings } = uglify.minify({ [file]: input }, uglifyOptions); + // Calling uglify + const { error, map, code, warnings } = uglify.minify({ [file]: input }, uglifyOptions); - // Handling results - if (error) { - compilation.errors.push(this.buildError(error, file, sourceMap, compilation, requestShortener)); - } else { - let outputSource; - if (map) { - outputSource = new SourceMapSource(code, file, JSON.parse(map), input, inputSourceMap); + // Handling results + if (error) { + compilation.errors.push(UglifyJsPlugin.buildError(error, file, sourceMap, compilation, requestShortener)); } else { - outputSource = new RawSource(code); - } - compilation.assets[file] = outputSource; - asset.__UglifyJsPlugin = outputSource; + let outputSource; + if (map) { + outputSource = new SourceMapSource(code, file, JSON.parse(map), input, inputSourceMap); + } else { + outputSource = new RawSource(code); + } + compilation.assets[file] = outputSource; + asset.uglifiedAsset = outputSource; - // Handling warnings - if (warnings) { - const buildWarnings = this.buildWarnings(warnings, file, sourceMap, this.options.warningsFilter, requestShortener); - compilation.warnings.push(new Error(`${file} from UglifyJs\n${buildWarnings.join('\n')}`)); - } + // Handling warnings + if (warnings) { + const warnArr = UglifyJsPlugin.buildWarnings(warnings, file, sourceMap, this.options.warningsFilter, requestShortener); + compilation.warnings.push(new Error(`${file} from UglifyJs\n${warnArr.join('\n')}`)); + } - // Write extracted comments to commentsFile - if (commentsFile) { - const commentsSource = new RawSource(`${extractedComments.join('\n\n')}\n`); - if (commentsFile in compilation.assets) { - // commentsFile already exists, append new comments... - if (compilation.assets[commentsFile] instanceof ConcatSource) { - compilation.assets[commentsFile].add('\n'); - compilation.assets[commentsFile].add(commentsSource); + // Write extracted comments to commentsFile + if (commentsFile) { + const commentsSource = new RawSource(`${extractedComments.join('\n\n')}\n`); + if (commentsFile in compilation.assets) { + // commentsFile already exists, append new comments... + if (compilation.assets[commentsFile] instanceof ConcatSource) { + compilation.assets[commentsFile].add('\n'); + compilation.assets[commentsFile].add(commentsSource); + } else { + compilation.assets[commentsFile] = new ConcatSource( + compilation.assets[commentsFile], '\n', commentsSource, + ); + } } else { - compilation.assets[commentsFile] = new ConcatSource( - compilation.assets[commentsFile], '\n', commentsSource, - ); + compilation.assets[commentsFile] = commentsSource; } - } else { - compilation.assets[commentsFile] = commentsSource; } } - } - }); + }); callback(); }); }); From 890ea1256839cb4ecf59e42af8939106ead91597 Mon Sep 17 00:00:00 2001 From: Hartorn Date: Fri, 30 Jun 2017 01:46:48 +0200 Subject: [PATCH 08/15] Correcting test cases (by restructuring options) --- test/all-options.test.js | 44 +++++++++++-------- test/extract-comments-options.test.js | 28 ++++++++---- ...xtract-option-set-to-a-single-file.test.js | 6 ++- test/invalid-options.test.js | 12 +++-- 4 files changed, 58 insertions(+), 32 deletions(-) diff --git a/test/all-options.test.js b/test/all-options.test.js index 13a79a2c..db8f36be 100644 --- a/test/all-options.test.js +++ b/test/all-options.test.js @@ -18,12 +18,6 @@ describe('when applied with all options', () => { const plugin = new UglifyJsPlugin({ sourceMap: true, - compress: { - warnings: true, - }, - mangle: false, - beautify: true, - comments: false, extractComments: { condition: 'should be extracted', filename(file) { @@ -33,6 +27,14 @@ describe('when applied with all options', () => { return `License information can be found in ${licenseFile}`; }, }, + uglifyOptions: { + warnings: true, + mangle: false, + output: { + beautify: true, + comments: false, + }, + }, }); plugin.apply(compilerEnv); eventBindings = pluginEnvironment.getEventBindings(); @@ -42,12 +44,14 @@ describe('when applied with all options', () => { const compiler = createCompiler(); new UglifyJsPlugin({ sourceMap: true, - compress: { + uglifyOptions: { + mangle: false, + output: { + beautify: true, + comments: false, + }, warnings: true, }, - mangle: false, - beautify: true, - comments: false, extractComments: { condition: 'should be extracted', filename(file) { @@ -273,12 +277,14 @@ describe('when applied with all options', () => { const plugin = new UglifyJsPlugin({ warningsFilter: () => true, sourceMap: true, - compress: { + uglifyOptions: { warnings: true, + mangle: false, + output: { + beautify: true, + comments: false, + }, }, - mangle: false, - beautify: true, - comments: false, }); plugin.apply(compilerEnv); eventBindings = pluginEnvironment.getEventBindings(); @@ -325,12 +331,14 @@ describe('when applied with all options', () => { const plugin = new UglifyJsPlugin({ warningsFilter: () => false, sourceMap: true, - compressor: { + uglifyOptions: { warnings: true, + mangle: false, + output: { + beautify: true, + comments: false, + }, }, - mangle: false, - beautify: true, - comments: false, }); plugin.apply(compilerEnv); eventBindings = pluginEnvironment.getEventBindings(); diff --git a/test/extract-comments-options.test.js b/test/extract-comments-options.test.js index 3ea84b27..54d6386c 100644 --- a/test/extract-comments-options.test.js +++ b/test/extract-comments-options.test.js @@ -11,16 +11,18 @@ describe('when options.extractComments', () => { compilerEnv.context = ''; const plugin = new UglifyJsPlugin({ - compress: { + uglifyOptions: { warnings: true, - }, - comments: false, - extractComments: 1, - mangle: { - props: { - builtins: true, + output: { + comments: false, + }, + mangle: { + properties: { + builtins: true, + }, }, }, + extractComments: 1, }); plugin.apply(compilerEnv); @@ -75,7 +77,11 @@ describe('when options.extractComments', () => { compilerEnv.context = ''; const plugin = new UglifyJsPlugin({ - comments: false, + uglifyOptions: { + output: { + comments: false, + }, + }, extractComments: /foo/, }); plugin.apply(compilerEnv); @@ -105,7 +111,11 @@ describe('when options.extractComments', () => { compilerEnv.context = ''; const plugin = new UglifyJsPlugin({ - comments: false, + uglifyOptions: { + output: { + comments: false, + }, + }, extractComments: { condition: true, filename(file) { diff --git a/test/extract-option-set-to-a-single-file.test.js b/test/extract-option-set-to-a-single-file.test.js index ad7ee987..1db7af40 100644 --- a/test/extract-option-set-to-a-single-file.test.js +++ b/test/extract-option-set-to-a-single-file.test.js @@ -11,7 +11,11 @@ describe('when applied with extract option set to a single file', () => { compilerEnv.context = ''; const plugin = new UglifyJsPlugin({ - comments: 'all', + uglifyOptions: { + output: { + comments: 'all', + }, + }, extractComments: { condition: /.*/, filename: 'extracted-comments.js', diff --git a/test/invalid-options.test.js b/test/invalid-options.test.js index ed2ccb10..f14c018a 100644 --- a/test/invalid-options.test.js +++ b/test/invalid-options.test.js @@ -10,8 +10,10 @@ describe('when applied with invalid options', () => { it('matches snapshot', () => { const compiler = createCompiler(); new UglifyJsPlugin({ - output: { - 'invalid-option': true, + uglifyOptions: { + output: { + 'invalid-option': true, + }, }, }).apply(compiler); @@ -36,8 +38,10 @@ describe('when applied with invalid options', () => { compilerEnv.context = ''; const plugin = new UglifyJsPlugin({ - output: { - 'invalid-option': true, + uglifyOptions: { + output: { + 'invalid-option': true, + }, }, }); plugin.apply(compilerEnv); From c9c39d5cc03e336526e9901e8d9b72daaecf87b8 Mon Sep 17 00:00:00 2001 From: Hartorn Date: Fri, 30 Jun 2017 01:54:42 +0200 Subject: [PATCH 09/15] Corrections to respect test * Putting back try-catch (wrong asset handling) * Adding banner for comments after being sure comments are presents * Correcting filter extraction * Correcting error handling --- src/index.js | 166 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 101 insertions(+), 65 deletions(-) diff --git a/src/index.js b/src/index.js index 0c0c6765..ef1034ad 100644 --- a/src/index.js +++ b/src/index.js @@ -9,6 +9,15 @@ import RequestShortener from 'webpack/lib/RequestShortener'; import ModuleFilenameHelpers from 'webpack/lib/ModuleFilenameHelpers'; import uglify from 'uglify-es'; +const defaultUglifyOptions = { + output: { + comments: /^\**!|@preserve|@license|@cc_on/, + beautify: false, + semicolons: true, + shebang: true, + }, +}; + class UglifyJsPlugin { constructor(options) { if (typeof options !== 'object' || Array.isArray(options)) { @@ -20,7 +29,24 @@ class UglifyJsPlugin { this.options.test = this.options.test || /\.js($|\?)/i; this.options.warningsFilter = this.options.warningsFilter || (() => true); - this.uglifyOptions = { ...this.options.uglifyOptions, sourceMap: null }; + this.uglifyOptions = this.options.uglifyOptions || {}; + } + + static buildDefaultUglifyOptions({ ecma, warnings, parse, compress, mangle, output, toplevel, ie8 }) { + return { + ecma, + warnings, + parse: parse || {}, + compress: compress || {}, + /* eslint-disable no-undefined */ + mangle: mangle === undefined || mangle === null ? true : mangle, + /* eslint-enable no-undefined */ + // Ignoring sourcemap from options + sourceMap: null, + output: { ...defaultUglifyOptions.output, ...output }, + toplevel, + ie8, + }; } static buildError(err, file, sourceMap, requestShortener) { @@ -36,9 +62,6 @@ class UglifyJsPlugin { return new Error(`${file} from UglifyJs\n${err.message} [${file}:${err.line},${err.col}]`); } else if (err.msg) { return new Error(`${file} from UglifyJs\n${err.msg}`); - } else if (err.message) { - // Pretty sure if should be message and not msg - return new Error(`${file} from UglifyJs\n${err.message}`); } return new Error(`${file} from UglifyJs\n${err.stack}`); } @@ -66,7 +89,7 @@ class UglifyJsPlugin { static buildCommentsFunction(options, uglifyOptions, extractedComments) { const condition = {}; - const commentsOpts = (uglifyOptions.output && uglifyOptions.output.comments) || 'some'; + const commentsOpts = uglifyOptions.output.comments; if (typeof options.extractComments === 'string' || options.extractComments instanceof RegExp) { // extractComments specifies the extract condition and commentsOpts specifies the preserve condition condition.preserve = commentsOpts; @@ -80,9 +103,12 @@ class UglifyJsPlugin { condition.preserve = false; condition.extract = commentsOpts; } + // Ensure that both conditions are functions ['preserve', 'extract'].forEach((key) => { - switch (typeof condition[key]) { + let regexStr; + let regex; + switch (typeof (condition[key])) { case 'boolean': condition[key] = condition[key] ? () => true : () => false; break; @@ -95,11 +121,14 @@ class UglifyJsPlugin { } if (condition[key] === 'some') { condition[key] = (astNode, comment) => comment.type === 'comment2' && /@preserve|@license|@cc_on/i.test(comment.value); + break; } - condition[key] = (astNode, comment) => new RegExp(condition[key]).test(comment.value); + regexStr = condition[key]; + condition[key] = (astNode, comment) => new RegExp(regexStr).test(comment.value); break; default: - condition[key] = (astNode, comment) => condition[key].test(comment.value); + regex = condition[key]; + condition[key] = (astNode, comment) => (regex.test(comment.value)); } }); @@ -129,89 +158,83 @@ class UglifyJsPlugin { } compilation.plugin('optimize-chunk-assets', (chunks, callback) => { + const uglifiedAssets = new WeakSet(); chunks.reduce((acc, chunk) => acc.concat(chunk.files || []), []) .concat(compilation.additionalChunkAssets || []) .filter(ModuleFilenameHelpers.matchObject.bind(null, this.options)) .forEach((file) => { // Copy uglify options - const uglifyOptions = Object.assign({}, this.uglifyOptions); - + const uglifyOptions = UglifyJsPlugin.buildDefaultUglifyOptions(this.uglifyOptions); + let sourceMap; const asset = compilation.assets[file]; - if (asset.uglifiedAsset) { - compilation.assets[file] = asset.uglifiedAsset; + if (uglifiedAssets.has(asset)) { return; } - let input; - let inputSourceMap; - let sourceMap; - if (this.options.sourceMap) { - if (asset.sourceAndMap) { - const sourceAndMap = asset.sourceAndMap(); - inputSourceMap = sourceAndMap.map; - input = sourceAndMap.source; + try { + let input; + let inputSourceMap; + if (this.options.sourceMap) { + if (asset.sourceAndMap) { + const sourceAndMap = asset.sourceAndMap(); + inputSourceMap = sourceAndMap.map; + input = sourceAndMap.source; + } else { + inputSourceMap = asset.map(); + input = asset.source(); + } + sourceMap = new SourceMapConsumer(inputSourceMap); + // Add source map data + uglifyOptions.sourceMap = { + content: inputSourceMap, + }; } else { - inputSourceMap = asset.map(); input = asset.source(); } - sourceMap = new SourceMapConsumer(inputSourceMap); - // Add source map data - uglifyOptions.sourceMap = { - content: inputSourceMap, - }; - } else { - input = asset.source(); - } - // Handling comment extraction - const extractedComments = []; - let commentsFile = false; - if (this.options.extractComments) { - uglifyOptions.output = uglifyOptions.output || {}; - uglifyOptions.output.comments = UglifyJsPlugin.buildCommentsFunction(this.options, uglifyOptions, extractedComments); + // Handling comment extraction + const extractedComments = []; + let commentsFile = false; + if (this.options.extractComments) { + uglifyOptions.output = uglifyOptions.output || {}; + uglifyOptions.output.comments = UglifyJsPlugin.buildCommentsFunction(this.options, uglifyOptions, extractedComments); - commentsFile = this.options.extractComments.filename || `${file}.LICENSE`; - if (typeof commentsFile === 'function') { - commentsFile = commentsFile(file); - } - - // Handling banner - if (this.options.extractComments.banner !== false) { - let banner = this.options.extractComments.banner || `/** For license information please see ${commentsFile} */`; - if (typeof banner === 'function') { - banner = banner(commentsFile); - } - if (banner) { - uglifyOptions.output = uglifyOptions.output || {}; - uglifyOptions.output.preamble = uglifyOptions.output.preamble ? `${banner}\n${uglifyOptions.output.preamble}` : banner; + commentsFile = this.options.extractComments.filename || `${file}.LICENSE`; + if (typeof commentsFile === 'function') { + commentsFile = commentsFile(file); } } - } - // Calling uglify - const { error, map, code, warnings } = uglify.minify({ [file]: input }, uglifyOptions); + // Calling uglify + const { error, map, code, warnings } = uglify.minify({ [file]: input }, uglifyOptions); + + // Handling results + if (error) { + throw error; + } - // Handling results - if (error) { - compilation.errors.push(UglifyJsPlugin.buildError(error, file, sourceMap, compilation, requestShortener)); - } else { let outputSource; if (map) { outputSource = new SourceMapSource(code, file, JSON.parse(map), input, inputSourceMap); } else { outputSource = new RawSource(code); } - compilation.assets[file] = outputSource; - asset.uglifiedAsset = outputSource; - - // Handling warnings - if (warnings) { - const warnArr = UglifyJsPlugin.buildWarnings(warnings, file, sourceMap, this.options.warningsFilter, requestShortener); - compilation.warnings.push(new Error(`${file} from UglifyJs\n${warnArr.join('\n')}`)); - } // Write extracted comments to commentsFile - if (commentsFile) { + if (commentsFile && extractedComments.length > 0) { + // Add a banner to the original file + if (this.options.extractComments.banner !== false) { + let banner = this.options.extractComments.banner || `For license information please see ${commentsFile}`; + if (typeof banner === 'function') { + banner = banner(commentsFile); + } + if (banner) { + outputSource = new ConcatSource( + `/*! ${banner} */\n`, outputSource, + ); + } + } + const commentsSource = new RawSource(`${extractedComments.join('\n\n')}\n`); if (commentsFile in compilation.assets) { // commentsFile already exists, append new comments... @@ -227,6 +250,19 @@ class UglifyJsPlugin { compilation.assets[commentsFile] = commentsSource; } } + + // Updating assets + uglifiedAssets.add(compilation.assets[file] = outputSource); + + // Handling warnings + if (warnings) { + const warnArr = UglifyJsPlugin.buildWarnings(warnings, file, sourceMap, this.options.warningsFilter, requestShortener); + if (warnArr.length > 0) { + compilation.warnings.push(new Error(`${file} from UglifyJs\n${warnArr.join('\n')}`)); + } + } + } catch (error) { + compilation.errors.push(UglifyJsPlugin.buildError(error, file, sourceMap, compilation, requestShortener)); } }); callback(); From f317b26ff457ae5ff72b3591692c3bb3df475ad7 Mon Sep 17 00:00:00 2001 From: Hartorn Date: Fri, 30 Jun 2017 02:35:50 +0200 Subject: [PATCH 10/15] Updating package-lock.json and package.json for uglify-es --- package-lock.json | 61 ++++++++++++++++++++++++++++++++++------------- package.json | 2 +- 2 files changed, 45 insertions(+), 18 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8adb0d2c..973066b4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -72,7 +72,8 @@ "align-text": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", - "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=" + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "dev": true }, "amdefine": { "version": "1.0.1", @@ -810,7 +811,8 @@ "camelcase": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=" + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "dev": true }, "camelcase-keys": { "version": "2.1.0", @@ -847,7 +849,8 @@ "center-align": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", - "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=" + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "dev": true }, "chalk": { "version": "1.1.3", @@ -926,7 +929,8 @@ "cliui": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=" + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "dev": true }, "co": { "version": "4.6.0", @@ -1279,7 +1283,8 @@ "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true }, "deep-extend": { "version": "0.4.2", @@ -2583,8 +2588,7 @@ "graceful-readlink": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", - "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", - "dev": true + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=" }, "growly": { "version": "1.3.0", @@ -2801,7 +2805,8 @@ "is-buffer": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz", - "integrity": "sha1-Hzsm72E7IUuIy8ojzGwB2Hlh7sw=" + "integrity": "sha1-Hzsm72E7IUuIy8ojzGwB2Hlh7sw=", + "dev": true }, "is-builtin-module": { "version": "1.0.0", @@ -3381,7 +3386,8 @@ "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=" + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true }, "latest-version": { "version": "3.1.0", @@ -3392,7 +3398,8 @@ "lazy-cache": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", - "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=" + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", + "dev": true }, "lcid": { "version": "1.0.0", @@ -3611,7 +3618,8 @@ "longest": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", - "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=" + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", + "dev": true }, "loose-envify": { "version": "1.3.1", @@ -4705,7 +4713,8 @@ "repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true }, "repeating": { "version": "2.0.1", @@ -4764,7 +4773,8 @@ "right-align": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", - "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=" + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", + "dev": true }, "rimraf": { "version": "2.6.1", @@ -5399,15 +5409,29 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, + "uglify-es": { + "version": "3.0.21", + "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.0.21.tgz", + "integrity": "sha512-hJ0lb3CoazL8TANWJCb6TusMOvcBSZp5vRiA3PST+LzwedUOguvf4xcpPwQGRS5GnaLYll9DQEL/jr8HPAioMg==", + "dependencies": { + "commander": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=" + } + } + }, "uglify-js": { "version": "2.8.29", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", - "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=" + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "dev": true }, "uglify-to-browserify": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "dev": true, "optional": true }, "uglifyjs-webpack-plugin": { @@ -5676,12 +5700,14 @@ "window-size": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", - "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=" + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", + "dev": true }, "wordwrap": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=" + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "dev": true }, "worker-farm": { "version": "1.3.1", @@ -5760,7 +5786,8 @@ "yargs": { "version": "3.10.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", - "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=" + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "dev": true }, "yargs-parser": { "version": "5.0.0", diff --git a/package.json b/package.json index 6a995cb6..890680a0 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ }, "dependencies": { "source-map": "^0.5.6", - "uglify-es": "^3.0.19", + "uglify-es": "^3.0.21", "webpack-sources": "^1.0.1" }, "devDependencies": { From d950f5b514f436f6ecaa323e31dd3fa07474375c Mon Sep 17 00:00:00 2001 From: Hartorn Date: Fri, 30 Jun 2017 02:51:48 +0200 Subject: [PATCH 11/15] Using eslint-disable-next-line instead of eslint-disable --- src/index.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/index.js b/src/index.js index ef1034ad..eca5959b 100644 --- a/src/index.js +++ b/src/index.js @@ -38,9 +38,8 @@ class UglifyJsPlugin { warnings, parse: parse || {}, compress: compress || {}, - /* eslint-disable no-undefined */ + // eslint-disable-next-line no-undefined mangle: mangle === undefined || mangle === null ? true : mangle, - /* eslint-enable no-undefined */ // Ignoring sourcemap from options sourceMap: null, output: { ...defaultUglifyOptions.output, ...output }, From b9399e4ec11574d029ed776d0f69569aecd81482 Mon Sep 17 00:00:00 2001 From: Steven Hargrove Date: Thu, 29 Jun 2017 22:58:53 -0400 Subject: [PATCH 12/15] added snapshot tests for uglify-es usage --- test/__snapshots__/all-options.test.js.snap | 12 +- test/__snapshots__/empty-options.test.js.snap | 4 +- .../es2015-module-options.test.js.snap | 386 ++++++++++++++++++ .../invalid-options.test.js.snap | 10 +- test/es2015-module-options.test.js | 155 +++++++ test/helpers.js | 18 +- test/stubs/es-dep.js | 2 + test/stubs/es-entry.js | 15 + 8 files changed, 587 insertions(+), 15 deletions(-) create mode 100644 test/__snapshots__/es2015-module-options.test.js.snap create mode 100644 test/es2015-module-options.test.js create mode 100644 test/stubs/es-dep.js create mode 100644 test/stubs/es-entry.js diff --git a/test/__snapshots__/all-options.test.js.snap b/test/__snapshots__/all-options.test.js.snap index e881fa7c..97d91c65 100644 --- a/test/__snapshots__/all-options.test.js.snap +++ b/test/__snapshots__/all-options.test.js.snap @@ -2,7 +2,7 @@ exports[`errors 1`] = `Array []`; -exports[`main.js 1`] = ` +exports[`main.0c220ec66316af2c1b24.js 1`] = ` "webpackJsonp([ 0 ], [ function(module, exports) { module.exports = function() { console.log(7); @@ -10,7 +10,7 @@ exports[`main.js 1`] = ` } ], [ 0 ]);" `; -exports[`manifest.js 1`] = ` +exports[`manifest.6afe1bc6685e9ab36c1c.js 1`] = ` "!function(modules) { function __webpack_require__(moduleId) { if (installedModules[moduleId]) return installedModules[moduleId].exports; @@ -53,7 +53,11 @@ exports[`manifest.js 1`] = ` var head = document.getElementsByTagName(\\"head\\")[0], script = document.createElement(\\"script\\"); script.type = \\"text/javascript\\", script.charset = \\"utf-8\\", script.async = !0, script.timeout = 12e4, __webpack_require__.nc && script.setAttribute(\\"nonce\\", __webpack_require__.nc), - script.src = __webpack_require__.p + \\"\\" + chunkId + \\".js\\"; + script.src = __webpack_require__.p + \\"\\" + chunkId + \\".\\" + ({ + \\"0\\": \\"main\\" + }[chunkId] || chunkId) + \\".\\" + { + \\"0\\": \\"0c220ec66316af2c1b24\\" + }[chunkId] + \\".js\\"; var timeout = setTimeout(onScriptComplete, 12e4); return script.onerror = script.onload = onScriptComplete, head.appendChild(script), promise; @@ -80,7 +84,7 @@ exports[`manifest.js 1`] = ` exports[`warnings 1`] = ` Array [ - "Error: main.js from UglifyJs + "Error: main.0c220ec66316af2c1b24.js from UglifyJs Dropping unused variable a [./test/stubs/entry.js:4,0]", ] `; diff --git a/test/__snapshots__/empty-options.test.js.snap b/test/__snapshots__/empty-options.test.js.snap index c543bed2..868100bb 100644 --- a/test/__snapshots__/empty-options.test.js.snap +++ b/test/__snapshots__/empty-options.test.js.snap @@ -2,8 +2,8 @@ exports[`errors 1`] = `Array []`; -exports[`main.js 1`] = `"webpackJsonp([0],[function(o,n){o.exports=function(){console.log(7)}}],[0]);"`; +exports[`main.0c220ec66316af2c1b24.js 1`] = `"webpackJsonp([0],[function(o,n){o.exports=function(){console.log(7)}}],[0]);"`; -exports[`manifest.js 1`] = `"!function(e){function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}var r=window.webpackJsonp;window.webpackJsonp=function(t,c,u){for(var i,a,f,l=0,s=[];l ({ + a: b + __WEBPACK_IMPORTED_MODULE_0__es_dep__.a + baz, + b: b, + baz: baz + }); + }; +}, function(module, __webpack_exports__, __webpack_require__) { + \\"use strict\\"; + __webpack_exports__.a = \\"bar\\", __webpack_exports__.b = \\"foo\\"; +} ], [ 0 ]);" +`; + +exports[`es5: manifest.c9894ec3f7740efa3954.js 1`] = ` +"!function(modules) { + function __webpack_require__(moduleId) { + if (installedModules[moduleId]) return installedModules[moduleId].exports; + var module = installedModules[moduleId] = { + i: moduleId, + l: !1, + exports: {} + }; + return modules[moduleId].call(module.exports, module, module.exports, __webpack_require__), + module.l = !0, module.exports; + } + var parentJsonpFunction = window.webpackJsonp; + window.webpackJsonp = function(chunkIds, moreModules, executeModules) { + for (var moduleId, chunkId, result, i = 0, resolves = []; i < chunkIds.length; i++) chunkId = chunkIds[i], + installedChunks[chunkId] && resolves.push(installedChunks[chunkId][0]), installedChunks[chunkId] = 0; + for (moduleId in moreModules) Object.prototype.hasOwnProperty.call(moreModules, moduleId) && (modules[moduleId] = moreModules[moduleId]); + for (parentJsonpFunction && parentJsonpFunction(chunkIds, moreModules, executeModules); resolves.length; ) resolves.shift()(); + if (executeModules) for (i = 0; i < executeModules.length; i++) result = __webpack_require__(__webpack_require__.s = executeModules[i]); + return result; + }; + var installedModules = {}, installedChunks = { + 1: 0 + }; + __webpack_require__.e = function(chunkId) { + function onScriptComplete() { + script.onerror = script.onload = null, clearTimeout(timeout); + var chunk = installedChunks[chunkId]; + 0 !== chunk && (chunk && chunk[1](new Error(\\"Loading chunk \\" + chunkId + \\" failed.\\")), + installedChunks[chunkId] = void 0); + } + var installedChunkData = installedChunks[chunkId]; + if (0 === installedChunkData) return new Promise(function(resolve) { + resolve(); + }); + if (installedChunkData) return installedChunkData[2]; + var promise = new Promise(function(resolve, reject) { + installedChunkData = installedChunks[chunkId] = [ resolve, reject ]; + }); + installedChunkData[2] = promise; + var head = document.getElementsByTagName(\\"head\\")[0], script = document.createElement(\\"script\\"); + script.type = \\"text/javascript\\", script.charset = \\"utf-8\\", script.async = !0, script.timeout = 12e4, + __webpack_require__.nc && script.setAttribute(\\"nonce\\", __webpack_require__.nc), + script.src = __webpack_require__.p + \\"\\" + chunkId + \\".\\" + ({ + \\"0\\": \\"main\\" + }[chunkId] || chunkId) + \\".\\" + { + \\"0\\": \\"6d1285604735ae61eff6\\" + }[chunkId] + \\".js\\"; + var timeout = setTimeout(onScriptComplete, 12e4); + return script.onerror = script.onload = onScriptComplete, head.appendChild(script), + promise; + }, __webpack_require__.m = modules, __webpack_require__.c = installedModules, __webpack_require__.d = function(exports, name, getter) { + __webpack_require__.o(exports, name) || Object.defineProperty(exports, name, { + configurable: !1, + enumerable: !0, + get: getter + }); + }, __webpack_require__.n = function(module) { + var getter = module && module.__esModule ? function() { + return module.default; + } : function() { + return module; + }; + return __webpack_require__.d(getter, \\"a\\", getter), getter; + }, __webpack_require__.o = function(object, property) { + return Object.prototype.hasOwnProperty.call(object, property); + }, __webpack_require__.p = \\"\\", __webpack_require__.oe = function(err) { + throw console.error(err), err; + }; +}([]);" +`; + +exports[`es5: warnings 1`] = `Array []`; + +exports[`es6: errors 1`] = `Array []`; + +exports[`es6: main.6d1285604735ae61eff6.js 1`] = ` +"webpackJsonp([ 0 ], [ (module, __webpack_exports__, __webpack_require__) => { + \\"use strict\\"; + Object.defineProperty(__webpack_exports__, \\"__esModule\\", { + value: !0 + }); + var __WEBPACK_IMPORTED_MODULE_0__es_dep__ = __webpack_require__(1); + __webpack_exports__.default = function() { + const b = __WEBPACK_IMPORTED_MODULE_0__es_dep__.b, baz = \\"baz\\" + Math.random(); + return () => ({ + a: b + __WEBPACK_IMPORTED_MODULE_0__es_dep__.a + baz, + b, + baz + }); + }; +}, (module, __webpack_exports__, __webpack_require__) => { + \\"use strict\\"; + __webpack_exports__.a = \\"bar\\", __webpack_exports__.b = \\"foo\\"; +} ], [ 0 ]);" +`; + +exports[`es6: manifest.c9894ec3f7740efa3954.js 1`] = ` +"!(modules => { + function __webpack_require__(moduleId) { + if (installedModules[moduleId]) return installedModules[moduleId].exports; + var module = installedModules[moduleId] = { + i: moduleId, + l: !1, + exports: {} + }; + return modules[moduleId].call(module.exports, module, module.exports, __webpack_require__), + module.l = !0, module.exports; + } + var parentJsonpFunction = window.webpackJsonp; + window.webpackJsonp = function(chunkIds, moreModules, executeModules) { + for (var moduleId, chunkId, result, i = 0, resolves = []; i < chunkIds.length; i++) chunkId = chunkIds[i], + installedChunks[chunkId] && resolves.push(installedChunks[chunkId][0]), installedChunks[chunkId] = 0; + for (moduleId in moreModules) Object.prototype.hasOwnProperty.call(moreModules, moduleId) && (modules[moduleId] = moreModules[moduleId]); + for (parentJsonpFunction && parentJsonpFunction(chunkIds, moreModules, executeModules); resolves.length; ) resolves.shift()(); + if (executeModules) for (i = 0; i < executeModules.length; i++) result = __webpack_require__(__webpack_require__.s = executeModules[i]); + return result; + }; + var installedModules = {}, installedChunks = { + 1: 0 + }; + __webpack_require__.e = function(chunkId) { + function onScriptComplete() { + script.onerror = script.onload = null, clearTimeout(timeout); + var chunk = installedChunks[chunkId]; + 0 !== chunk && (chunk && chunk[1](new Error(\\"Loading chunk \\" + chunkId + \\" failed.\\")), + installedChunks[chunkId] = void 0); + } + var installedChunkData = installedChunks[chunkId]; + if (0 === installedChunkData) return new Promise(resolve => { + resolve(); + }); + if (installedChunkData) return installedChunkData[2]; + var promise = new Promise((resolve, reject) => { + installedChunkData = installedChunks[chunkId] = [ resolve, reject ]; + }); + installedChunkData[2] = promise; + var head = document.getElementsByTagName(\\"head\\")[0], script = document.createElement(\\"script\\"); + script.type = \\"text/javascript\\", script.charset = \\"utf-8\\", script.async = !0, script.timeout = 12e4, + __webpack_require__.nc && script.setAttribute(\\"nonce\\", __webpack_require__.nc), + script.src = __webpack_require__.p + \\"\\" + chunkId + \\".\\" + ({ + \\"0\\": \\"main\\" + }[chunkId] || chunkId) + \\".\\" + { + \\"0\\": \\"6d1285604735ae61eff6\\" + }[chunkId] + \\".js\\"; + var timeout = setTimeout(onScriptComplete, 12e4); + return script.onerror = script.onload = onScriptComplete, head.appendChild(script), + promise; + }, __webpack_require__.m = modules, __webpack_require__.c = installedModules, __webpack_require__.d = ((exports, name, getter) => { + __webpack_require__.o(exports, name) || Object.defineProperty(exports, name, { + configurable: !1, + enumerable: !0, + get: getter + }); + }), __webpack_require__.n = (module => { + var getter = module && module.__esModule ? function() { + return module.default; + } : function() { + return module; + }; + return __webpack_require__.d(getter, \\"a\\", getter), getter; + }), __webpack_require__.o = ((object, property) => Object.prototype.hasOwnProperty.call(object, property)), + __webpack_require__.p = \\"\\", __webpack_require__.oe = (err => { + throw console.error(err), err; + }); +})([]);" +`; + +exports[`es6: warnings 1`] = `Array []`; + +exports[`es7: errors 1`] = `Array []`; + +exports[`es7: main.6d1285604735ae61eff6.js 1`] = ` +"webpackJsonp([ 0 ], [ (module, __webpack_exports__, __webpack_require__) => { + \\"use strict\\"; + Object.defineProperty(__webpack_exports__, \\"__esModule\\", { + value: !0 + }); + var __WEBPACK_IMPORTED_MODULE_0__es_dep__ = __webpack_require__(1); + __webpack_exports__.default = function() { + const b = __WEBPACK_IMPORTED_MODULE_0__es_dep__.b, baz = \\"baz\\" + Math.random(); + return () => ({ + a: b + __WEBPACK_IMPORTED_MODULE_0__es_dep__.a + baz, + b, + baz + }); + }; +}, (module, __webpack_exports__, __webpack_require__) => { + \\"use strict\\"; + __webpack_exports__.a = \\"bar\\", __webpack_exports__.b = \\"foo\\"; +} ], [ 0 ]);" +`; + +exports[`es7: manifest.c9894ec3f7740efa3954.js 1`] = ` +"!(modules => { + function __webpack_require__(moduleId) { + if (installedModules[moduleId]) return installedModules[moduleId].exports; + var module = installedModules[moduleId] = { + i: moduleId, + l: !1, + exports: {} + }; + return modules[moduleId].call(module.exports, module, module.exports, __webpack_require__), + module.l = !0, module.exports; + } + var parentJsonpFunction = window.webpackJsonp; + window.webpackJsonp = function(chunkIds, moreModules, executeModules) { + for (var moduleId, chunkId, result, i = 0, resolves = []; i < chunkIds.length; i++) chunkId = chunkIds[i], + installedChunks[chunkId] && resolves.push(installedChunks[chunkId][0]), installedChunks[chunkId] = 0; + for (moduleId in moreModules) Object.prototype.hasOwnProperty.call(moreModules, moduleId) && (modules[moduleId] = moreModules[moduleId]); + for (parentJsonpFunction && parentJsonpFunction(chunkIds, moreModules, executeModules); resolves.length; ) resolves.shift()(); + if (executeModules) for (i = 0; i < executeModules.length; i++) result = __webpack_require__(__webpack_require__.s = executeModules[i]); + return result; + }; + var installedModules = {}, installedChunks = { + 1: 0 + }; + __webpack_require__.e = function(chunkId) { + function onScriptComplete() { + script.onerror = script.onload = null, clearTimeout(timeout); + var chunk = installedChunks[chunkId]; + 0 !== chunk && (chunk && chunk[1](new Error(\\"Loading chunk \\" + chunkId + \\" failed.\\")), + installedChunks[chunkId] = void 0); + } + var installedChunkData = installedChunks[chunkId]; + if (0 === installedChunkData) return new Promise(resolve => { + resolve(); + }); + if (installedChunkData) return installedChunkData[2]; + var promise = new Promise((resolve, reject) => { + installedChunkData = installedChunks[chunkId] = [ resolve, reject ]; + }); + installedChunkData[2] = promise; + var head = document.getElementsByTagName(\\"head\\")[0], script = document.createElement(\\"script\\"); + script.type = \\"text/javascript\\", script.charset = \\"utf-8\\", script.async = !0, script.timeout = 12e4, + __webpack_require__.nc && script.setAttribute(\\"nonce\\", __webpack_require__.nc), + script.src = __webpack_require__.p + \\"\\" + chunkId + \\".\\" + ({ + \\"0\\": \\"main\\" + }[chunkId] || chunkId) + \\".\\" + { + \\"0\\": \\"6d1285604735ae61eff6\\" + }[chunkId] + \\".js\\"; + var timeout = setTimeout(onScriptComplete, 12e4); + return script.onerror = script.onload = onScriptComplete, head.appendChild(script), + promise; + }, __webpack_require__.m = modules, __webpack_require__.c = installedModules, __webpack_require__.d = ((exports, name, getter) => { + __webpack_require__.o(exports, name) || Object.defineProperty(exports, name, { + configurable: !1, + enumerable: !0, + get: getter + }); + }), __webpack_require__.n = (module => { + var getter = module && module.__esModule ? function() { + return module.default; + } : function() { + return module; + }; + return __webpack_require__.d(getter, \\"a\\", getter), getter; + }), __webpack_require__.o = ((object, property) => Object.prototype.hasOwnProperty.call(object, property)), + __webpack_require__.p = \\"\\", __webpack_require__.oe = (err => { + throw console.error(err), err; + }); +})([]);" +`; + +exports[`es7: warnings 1`] = `Array []`; + +exports[`es8: errors 1`] = `Array []`; + +exports[`es8: main.6d1285604735ae61eff6.js 1`] = ` +"webpackJsonp([ 0 ], [ (module, __webpack_exports__, __webpack_require__) => { + \\"use strict\\"; + Object.defineProperty(__webpack_exports__, \\"__esModule\\", { + value: !0 + }); + var __WEBPACK_IMPORTED_MODULE_0__es_dep__ = __webpack_require__(1); + __webpack_exports__.default = function() { + const b = __WEBPACK_IMPORTED_MODULE_0__es_dep__.b, baz = \\"baz\\" + Math.random(); + return () => ({ + a: b + __WEBPACK_IMPORTED_MODULE_0__es_dep__.a + baz, + b, + baz + }); + }; +}, (module, __webpack_exports__, __webpack_require__) => { + \\"use strict\\"; + __webpack_exports__.a = \\"bar\\", __webpack_exports__.b = \\"foo\\"; +} ], [ 0 ]);" +`; + +exports[`es8: manifest.c9894ec3f7740efa3954.js 1`] = ` +"!(modules => { + function __webpack_require__(moduleId) { + if (installedModules[moduleId]) return installedModules[moduleId].exports; + var module = installedModules[moduleId] = { + i: moduleId, + l: !1, + exports: {} + }; + return modules[moduleId].call(module.exports, module, module.exports, __webpack_require__), + module.l = !0, module.exports; + } + var parentJsonpFunction = window.webpackJsonp; + window.webpackJsonp = function(chunkIds, moreModules, executeModules) { + for (var moduleId, chunkId, result, i = 0, resolves = []; i < chunkIds.length; i++) chunkId = chunkIds[i], + installedChunks[chunkId] && resolves.push(installedChunks[chunkId][0]), installedChunks[chunkId] = 0; + for (moduleId in moreModules) Object.prototype.hasOwnProperty.call(moreModules, moduleId) && (modules[moduleId] = moreModules[moduleId]); + for (parentJsonpFunction && parentJsonpFunction(chunkIds, moreModules, executeModules); resolves.length; ) resolves.shift()(); + if (executeModules) for (i = 0; i < executeModules.length; i++) result = __webpack_require__(__webpack_require__.s = executeModules[i]); + return result; + }; + var installedModules = {}, installedChunks = { + 1: 0 + }; + __webpack_require__.e = function(chunkId) { + function onScriptComplete() { + script.onerror = script.onload = null, clearTimeout(timeout); + var chunk = installedChunks[chunkId]; + 0 !== chunk && (chunk && chunk[1](new Error(\\"Loading chunk \\" + chunkId + \\" failed.\\")), + installedChunks[chunkId] = void 0); + } + var installedChunkData = installedChunks[chunkId]; + if (0 === installedChunkData) return new Promise(resolve => { + resolve(); + }); + if (installedChunkData) return installedChunkData[2]; + var promise = new Promise((resolve, reject) => { + installedChunkData = installedChunks[chunkId] = [ resolve, reject ]; + }); + installedChunkData[2] = promise; + var head = document.getElementsByTagName(\\"head\\")[0], script = document.createElement(\\"script\\"); + script.type = \\"text/javascript\\", script.charset = \\"utf-8\\", script.async = !0, script.timeout = 12e4, + __webpack_require__.nc && script.setAttribute(\\"nonce\\", __webpack_require__.nc), + script.src = __webpack_require__.p + \\"\\" + chunkId + \\".\\" + ({ + \\"0\\": \\"main\\" + }[chunkId] || chunkId) + \\".\\" + { + \\"0\\": \\"6d1285604735ae61eff6\\" + }[chunkId] + \\".js\\"; + var timeout = setTimeout(onScriptComplete, 12e4); + return script.onerror = script.onload = onScriptComplete, head.appendChild(script), + promise; + }, __webpack_require__.m = modules, __webpack_require__.c = installedModules, __webpack_require__.d = ((exports, name, getter) => { + __webpack_require__.o(exports, name) || Object.defineProperty(exports, name, { + configurable: !1, + enumerable: !0, + get: getter + }); + }), __webpack_require__.n = (module => { + var getter = module && module.__esModule ? function() { + return module.default; + } : function() { + return module; + }; + return __webpack_require__.d(getter, \\"a\\", getter), getter; + }), __webpack_require__.o = ((object, property) => Object.prototype.hasOwnProperty.call(object, property)), + __webpack_require__.p = \\"\\", __webpack_require__.oe = (err => { + throw console.error(err), err; + }); +})([]);" +`; + +exports[`es8: warnings 1`] = `Array []`; diff --git a/test/__snapshots__/invalid-options.test.js.snap b/test/__snapshots__/invalid-options.test.js.snap index 2791ba0b..43f332bc 100644 --- a/test/__snapshots__/invalid-options.test.js.snap +++ b/test/__snapshots__/invalid-options.test.js.snap @@ -2,14 +2,14 @@ exports[`errors 1`] = ` Array [ - "Error: main.js from UglifyJs + "Error: main.0c220ec66316af2c1b24.js from UglifyJs DefaultsError: \`invalid-option\` is not a supported option", - "Error: manifest.js from UglifyJs + "Error: manifest.6afe1bc6685e9ab36c1c.js from UglifyJs DefaultsError: \`invalid-option\` is not a supported option", ] `; -exports[`main.js 1`] = ` +exports[`main.0c220ec66316af2c1b24.js 1`] = ` "webpackJsonp([0],[ /* 0 */ /***/ (function(module, exports) { @@ -29,7 +29,7 @@ module.exports = function Foo() { ],[0]);" `; -exports[`manifest.js 1`] = ` +exports[`manifest.6afe1bc6685e9ab36c1c.js 1`] = ` "/******/ (function(modules) { // webpackBootstrap /******/ // install a JSONP callback for chunk loading /******/ var parentJsonpFunction = window[\\"webpackJsonp\\"]; @@ -123,7 +123,7 @@ exports[`manifest.js 1`] = ` /******/ if (__webpack_require__.nc) { /******/ script.setAttribute(\\"nonce\\", __webpack_require__.nc); /******/ } -/******/ script.src = __webpack_require__.p + \\"\\" + chunkId + \\".js\\"; +/******/ script.src = __webpack_require__.p + \\"\\" + chunkId + \\".\\" + ({\\"0\\":\\"main\\"}[chunkId]||chunkId) + \\".\\" + {\\"0\\":\\"0c220ec66316af2c1b24\\"}[chunkId] + \\".js\\"; /******/ var timeout = setTimeout(onScriptComplete, 120000); /******/ script.onerror = script.onload = onScriptComplete; /******/ function onScriptComplete() { diff --git a/test/es2015-module-options.test.js b/test/es2015-module-options.test.js new file mode 100644 index 00000000..64653b17 --- /dev/null +++ b/test/es2015-module-options.test.js @@ -0,0 +1,155 @@ +import UglifyJsPlugin from '../src/index'; +import { + cleanErrorStack, + createCompiler, + compile, +} from './helpers'; + +describe('when applied with uglifyOptions.ecma', () => { + it('matches snapshot for ecma 5', () => { + const compiler = createCompiler({ + entry: `${__dirname}/stubs/es-entry.js`, + output: { + path: `${__dirname}/dist-es`, + filename: '[name].[chunkhash].js', + chunkFilename: '[id].[name].[chunkhash].js', + }, + }); + + new UglifyJsPlugin({ + uglifyOptions: { + ecma: 5, + mangle: false, + warnings: true, + output: { + beautify: true, + comments: false, + }, + }, + }).apply(compiler); + + return compile(compiler).then((stats) => { + const errors = stats.compilation.errors.map(cleanErrorStack); + const warnings = stats.compilation.warnings.map(cleanErrorStack); + + expect(errors).toMatchSnapshot('es5: errors'); + expect(warnings).toMatchSnapshot('es5: warnings'); + + for (const file in stats.compilation.assets) { + if (Object.prototype.hasOwnProperty.call(stats.compilation.assets, file)) { + expect(stats.compilation.assets[file].source()).toMatchSnapshot(`es5: ${file}`); + } + } + }); + }); + + it('matches snapshot for ecma 6', () => { + const compiler = createCompiler({ + entry: `${__dirname}/stubs/es-entry.js`, + output: { + path: `${__dirname}/dist-es`, + filename: '[name].[chunkhash].js', + chunkFilename: '[id].[name].[chunkhash].js', + }, + }); + + new UglifyJsPlugin({ + uglifyOptions: { + ecma: 6, + mangle: false, + warnings: true, + output: { + beautify: true, + comments: false, + }, + }, + }).apply(compiler); + + return compile(compiler).then((stats) => { + const errors = stats.compilation.errors.map(cleanErrorStack); + const warnings = stats.compilation.warnings.map(cleanErrorStack); + + expect(errors).toMatchSnapshot('es6: errors'); + expect(warnings).toMatchSnapshot('es6: warnings'); + + for (const file in stats.compilation.assets) { + if (Object.prototype.hasOwnProperty.call(stats.compilation.assets, file)) { + expect(stats.compilation.assets[file].source()).toMatchSnapshot(`es6: ${file}`); + } + } + }); + }); + + it('matches snapshot for ecma 7', () => { + const compiler = createCompiler({ + entry: `${__dirname}/stubs/es-entry.js`, + output: { + path: `${__dirname}/dist-es`, + filename: '[name].[chunkhash].js', + chunkFilename: '[id].[name].[chunkhash].js', + }, + }); + new UglifyJsPlugin({ + uglifyOptions: { + ecma: 7, + mangle: false, + warnings: true, + output: { + beautify: true, + comments: false, + }, + }, + }).apply(compiler); + + return compile(compiler).then((stats) => { + const errors = stats.compilation.errors.map(cleanErrorStack); + const warnings = stats.compilation.warnings.map(cleanErrorStack); + + expect(errors).toMatchSnapshot('es7: errors'); + expect(warnings).toMatchSnapshot('es7: warnings'); + + for (const file in stats.compilation.assets) { + if (Object.prototype.hasOwnProperty.call(stats.compilation.assets, file)) { + expect(stats.compilation.assets[file].source()).toMatchSnapshot(`es7: ${file}`); + } + } + }); + }); + + it('matches snapshot for ecma 8', () => { + const compiler = createCompiler({ + entry: `${__dirname}/stubs/es-entry.js`, + output: { + path: `${__dirname}/dist-es`, + filename: '[name].[chunkhash].js', + chunkFilename: '[id].[name].[chunkhash].js', + }, + }); + + new UglifyJsPlugin({ + uglifyOptions: { + ecma: 8, + mangle: false, + warnings: true, + output: { + beautify: true, + comments: false, + }, + }, + }).apply(compiler); + + return compile(compiler).then((stats) => { + const errors = stats.compilation.errors.map(cleanErrorStack); + const warnings = stats.compilation.warnings.map(cleanErrorStack); + + expect(errors).toMatchSnapshot('es8: errors'); + expect(warnings).toMatchSnapshot('es8: warnings'); + + for (const file in stats.compilation.assets) { + if (Object.prototype.hasOwnProperty.call(stats.compilation.assets, file)) { + expect(stats.compilation.assets[file].source()).toMatchSnapshot(`es8: ${file}`); + } + } + }); + }); +}); diff --git a/test/helpers.js b/test/helpers.js index 1c46a1a1..debb1b35 100644 --- a/test/helpers.js +++ b/test/helpers.js @@ -31,20 +31,30 @@ exports.compile = function compile(compiler) { }); }; -exports.createCompiler = function createCompiler(options) { - const compiler = webpack(options || { - bail: true, +exports.createCompiler = function createCompiler(options = {}) { + const compiler = webpack({ cache: false, entry: `${__dirname}/stubs/entry.js`, + resolve: { + unsafeCache: false, + }, + resolveLoader: { + unsafeCache: false, + }, + module: { + unsafeCache: false, + }, output: { path: `${__dirname}/dist`, - filename: '[name].js', + filename: '[name].[chunkhash].js', + chunkFilename: '[id].[name].[chunkhash].js', }, plugins: [ new webpack.optimize.CommonsChunkPlugin({ name: 'manifest', }), ], + ...options, }); compiler.outputFileSystem = new MemoryFileSystem(); return compiler; diff --git a/test/stubs/es-dep.js b/test/stubs/es-dep.js new file mode 100644 index 00000000..6d24cac9 --- /dev/null +++ b/test/stubs/es-dep.js @@ -0,0 +1,2 @@ +export const bar = 'bar'; +export default 'foo'; diff --git a/test/stubs/es-entry.js b/test/stubs/es-entry.js new file mode 100644 index 00000000..bd1d0407 --- /dev/null +++ b/test/stubs/es-entry.js @@ -0,0 +1,15 @@ +import foo, { bar } from './es-dep'; + +function Foo() { + const b = foo; + const baz = "baz" + Math.random(); + return () => { + return { + a: b + bar + baz, + b, + baz, + }; + }; +} + +export default Foo; From 1a99934dacab9305c91e8250fc0f470ddf6e541b Mon Sep 17 00:00:00 2001 From: Steven Hargrove Date: Fri, 30 Jun 2017 09:17:24 -0400 Subject: [PATCH 13/15] renamed stubs to fixtures, removed unsafeCache: false from test helpers, make a es2015 fixture --- .eslintignore | 2 +- test/__snapshots__/all-options.test.js.snap | 2 +- ...tions.test.js.snap => es2015.test.js.snap} | 48 +++++++++---------- ...-module-options.test.js => es2015.test.js} | 16 +++---- test/{stubs => fixtures}/entry.js | 0 .../es-dep.js => fixtures/es2015/dep.js} | 0 .../es-entry.js => fixtures/es2015/entry.js} | 4 +- test/helpers.js | 12 +---- 8 files changed, 38 insertions(+), 46 deletions(-) rename test/__snapshots__/{es2015-module-options.test.js.snap => es2015.test.js.snap} (91%) rename test/{es2015-module-options.test.js => es2015.test.js} (91%) rename test/{stubs => fixtures}/entry.js (100%) rename test/{stubs/es-dep.js => fixtures/es2015/dep.js} (100%) rename test/{stubs/es-entry.js => fixtures/es2015/entry.js} (66%) diff --git a/.eslintignore b/.eslintignore index 607ab064..14ffe8d7 100644 --- a/.eslintignore +++ b/.eslintignore @@ -3,4 +3,4 @@ /dist /examples/build /coverage/ -/test/stubs +/test/fixtures diff --git a/test/__snapshots__/all-options.test.js.snap b/test/__snapshots__/all-options.test.js.snap index 97d91c65..1cb10095 100644 --- a/test/__snapshots__/all-options.test.js.snap +++ b/test/__snapshots__/all-options.test.js.snap @@ -85,6 +85,6 @@ exports[`manifest.6afe1bc6685e9ab36c1c.js 1`] = ` exports[`warnings 1`] = ` Array [ "Error: main.0c220ec66316af2c1b24.js from UglifyJs -Dropping unused variable a [./test/stubs/entry.js:4,0]", +Dropping unused variable a [./test/fixtures/entry.js:4,0]", ] `; diff --git a/test/__snapshots__/es2015-module-options.test.js.snap b/test/__snapshots__/es2015.test.js.snap similarity index 91% rename from test/__snapshots__/es2015-module-options.test.js.snap rename to test/__snapshots__/es2015.test.js.snap index f497b147..87a7f562 100644 --- a/test/__snapshots__/es2015-module-options.test.js.snap +++ b/test/__snapshots__/es2015.test.js.snap @@ -2,17 +2,17 @@ exports[`es5: errors 1`] = `Array []`; -exports[`es5: main.6d1285604735ae61eff6.js 1`] = ` +exports[`es5: main.567c8482b5d4c641f322.js 1`] = ` "webpackJsonp([ 0 ], [ function(module, __webpack_exports__, __webpack_require__) { \\"use strict\\"; Object.defineProperty(__webpack_exports__, \\"__esModule\\", { value: !0 }); - var __WEBPACK_IMPORTED_MODULE_0__es_dep__ = __webpack_require__(1); + var __WEBPACK_IMPORTED_MODULE_0__dep__ = __webpack_require__(1); __webpack_exports__.default = function() { - const b = __WEBPACK_IMPORTED_MODULE_0__es_dep__.b, baz = \\"baz\\" + Math.random(); + const b = __WEBPACK_IMPORTED_MODULE_0__dep__.b, baz = \\"baz\\" + Math.random(); return () => ({ - a: b + __WEBPACK_IMPORTED_MODULE_0__es_dep__.a + baz, + a: b + __WEBPACK_IMPORTED_MODULE_0__dep__.a + baz, b: b, baz: baz }); @@ -23,7 +23,7 @@ exports[`es5: main.6d1285604735ae61eff6.js 1`] = ` } ], [ 0 ]);" `; -exports[`es5: manifest.c9894ec3f7740efa3954.js 1`] = ` +exports[`es5: manifest.67273d936e04f664080e.js 1`] = ` "!function(modules) { function __webpack_require__(moduleId) { if (installedModules[moduleId]) return installedModules[moduleId].exports; @@ -69,7 +69,7 @@ exports[`es5: manifest.c9894ec3f7740efa3954.js 1`] = ` script.src = __webpack_require__.p + \\"\\" + chunkId + \\".\\" + ({ \\"0\\": \\"main\\" }[chunkId] || chunkId) + \\".\\" + { - \\"0\\": \\"6d1285604735ae61eff6\\" + \\"0\\": \\"567c8482b5d4c641f322\\" }[chunkId] + \\".js\\"; var timeout = setTimeout(onScriptComplete, 12e4); return script.onerror = script.onload = onScriptComplete, head.appendChild(script), @@ -99,17 +99,17 @@ exports[`es5: warnings 1`] = `Array []`; exports[`es6: errors 1`] = `Array []`; -exports[`es6: main.6d1285604735ae61eff6.js 1`] = ` +exports[`es6: main.567c8482b5d4c641f322.js 1`] = ` "webpackJsonp([ 0 ], [ (module, __webpack_exports__, __webpack_require__) => { \\"use strict\\"; Object.defineProperty(__webpack_exports__, \\"__esModule\\", { value: !0 }); - var __WEBPACK_IMPORTED_MODULE_0__es_dep__ = __webpack_require__(1); + var __WEBPACK_IMPORTED_MODULE_0__dep__ = __webpack_require__(1); __webpack_exports__.default = function() { - const b = __WEBPACK_IMPORTED_MODULE_0__es_dep__.b, baz = \\"baz\\" + Math.random(); + const b = __WEBPACK_IMPORTED_MODULE_0__dep__.b, baz = \\"baz\\" + Math.random(); return () => ({ - a: b + __WEBPACK_IMPORTED_MODULE_0__es_dep__.a + baz, + a: b + __WEBPACK_IMPORTED_MODULE_0__dep__.a + baz, b, baz }); @@ -120,7 +120,7 @@ exports[`es6: main.6d1285604735ae61eff6.js 1`] = ` } ], [ 0 ]);" `; -exports[`es6: manifest.c9894ec3f7740efa3954.js 1`] = ` +exports[`es6: manifest.67273d936e04f664080e.js 1`] = ` "!(modules => { function __webpack_require__(moduleId) { if (installedModules[moduleId]) return installedModules[moduleId].exports; @@ -166,7 +166,7 @@ exports[`es6: manifest.c9894ec3f7740efa3954.js 1`] = ` script.src = __webpack_require__.p + \\"\\" + chunkId + \\".\\" + ({ \\"0\\": \\"main\\" }[chunkId] || chunkId) + \\".\\" + { - \\"0\\": \\"6d1285604735ae61eff6\\" + \\"0\\": \\"567c8482b5d4c641f322\\" }[chunkId] + \\".js\\"; var timeout = setTimeout(onScriptComplete, 12e4); return script.onerror = script.onload = onScriptComplete, head.appendChild(script), @@ -195,17 +195,17 @@ exports[`es6: warnings 1`] = `Array []`; exports[`es7: errors 1`] = `Array []`; -exports[`es7: main.6d1285604735ae61eff6.js 1`] = ` +exports[`es7: main.567c8482b5d4c641f322.js 1`] = ` "webpackJsonp([ 0 ], [ (module, __webpack_exports__, __webpack_require__) => { \\"use strict\\"; Object.defineProperty(__webpack_exports__, \\"__esModule\\", { value: !0 }); - var __WEBPACK_IMPORTED_MODULE_0__es_dep__ = __webpack_require__(1); + var __WEBPACK_IMPORTED_MODULE_0__dep__ = __webpack_require__(1); __webpack_exports__.default = function() { - const b = __WEBPACK_IMPORTED_MODULE_0__es_dep__.b, baz = \\"baz\\" + Math.random(); + const b = __WEBPACK_IMPORTED_MODULE_0__dep__.b, baz = \\"baz\\" + Math.random(); return () => ({ - a: b + __WEBPACK_IMPORTED_MODULE_0__es_dep__.a + baz, + a: b + __WEBPACK_IMPORTED_MODULE_0__dep__.a + baz, b, baz }); @@ -216,7 +216,7 @@ exports[`es7: main.6d1285604735ae61eff6.js 1`] = ` } ], [ 0 ]);" `; -exports[`es7: manifest.c9894ec3f7740efa3954.js 1`] = ` +exports[`es7: manifest.67273d936e04f664080e.js 1`] = ` "!(modules => { function __webpack_require__(moduleId) { if (installedModules[moduleId]) return installedModules[moduleId].exports; @@ -262,7 +262,7 @@ exports[`es7: manifest.c9894ec3f7740efa3954.js 1`] = ` script.src = __webpack_require__.p + \\"\\" + chunkId + \\".\\" + ({ \\"0\\": \\"main\\" }[chunkId] || chunkId) + \\".\\" + { - \\"0\\": \\"6d1285604735ae61eff6\\" + \\"0\\": \\"567c8482b5d4c641f322\\" }[chunkId] + \\".js\\"; var timeout = setTimeout(onScriptComplete, 12e4); return script.onerror = script.onload = onScriptComplete, head.appendChild(script), @@ -291,17 +291,17 @@ exports[`es7: warnings 1`] = `Array []`; exports[`es8: errors 1`] = `Array []`; -exports[`es8: main.6d1285604735ae61eff6.js 1`] = ` +exports[`es8: main.567c8482b5d4c641f322.js 1`] = ` "webpackJsonp([ 0 ], [ (module, __webpack_exports__, __webpack_require__) => { \\"use strict\\"; Object.defineProperty(__webpack_exports__, \\"__esModule\\", { value: !0 }); - var __WEBPACK_IMPORTED_MODULE_0__es_dep__ = __webpack_require__(1); + var __WEBPACK_IMPORTED_MODULE_0__dep__ = __webpack_require__(1); __webpack_exports__.default = function() { - const b = __WEBPACK_IMPORTED_MODULE_0__es_dep__.b, baz = \\"baz\\" + Math.random(); + const b = __WEBPACK_IMPORTED_MODULE_0__dep__.b, baz = \\"baz\\" + Math.random(); return () => ({ - a: b + __WEBPACK_IMPORTED_MODULE_0__es_dep__.a + baz, + a: b + __WEBPACK_IMPORTED_MODULE_0__dep__.a + baz, b, baz }); @@ -312,7 +312,7 @@ exports[`es8: main.6d1285604735ae61eff6.js 1`] = ` } ], [ 0 ]);" `; -exports[`es8: manifest.c9894ec3f7740efa3954.js 1`] = ` +exports[`es8: manifest.67273d936e04f664080e.js 1`] = ` "!(modules => { function __webpack_require__(moduleId) { if (installedModules[moduleId]) return installedModules[moduleId].exports; @@ -358,7 +358,7 @@ exports[`es8: manifest.c9894ec3f7740efa3954.js 1`] = ` script.src = __webpack_require__.p + \\"\\" + chunkId + \\".\\" + ({ \\"0\\": \\"main\\" }[chunkId] || chunkId) + \\".\\" + { - \\"0\\": \\"6d1285604735ae61eff6\\" + \\"0\\": \\"567c8482b5d4c641f322\\" }[chunkId] + \\".js\\"; var timeout = setTimeout(onScriptComplete, 12e4); return script.onerror = script.onload = onScriptComplete, head.appendChild(script), diff --git a/test/es2015-module-options.test.js b/test/es2015.test.js similarity index 91% rename from test/es2015-module-options.test.js rename to test/es2015.test.js index 64653b17..b84900a9 100644 --- a/test/es2015-module-options.test.js +++ b/test/es2015.test.js @@ -8,9 +8,9 @@ import { describe('when applied with uglifyOptions.ecma', () => { it('matches snapshot for ecma 5', () => { const compiler = createCompiler({ - entry: `${__dirname}/stubs/es-entry.js`, + entry: `${__dirname}/fixtures/es2015/entry.js`, output: { - path: `${__dirname}/dist-es`, + path: `${__dirname}/dist-2015`, filename: '[name].[chunkhash].js', chunkFilename: '[id].[name].[chunkhash].js', }, @@ -45,9 +45,9 @@ describe('when applied with uglifyOptions.ecma', () => { it('matches snapshot for ecma 6', () => { const compiler = createCompiler({ - entry: `${__dirname}/stubs/es-entry.js`, + entry: `${__dirname}/fixtures/es2015/entry.js`, output: { - path: `${__dirname}/dist-es`, + path: `${__dirname}/dist-2015`, filename: '[name].[chunkhash].js', chunkFilename: '[id].[name].[chunkhash].js', }, @@ -82,9 +82,9 @@ describe('when applied with uglifyOptions.ecma', () => { it('matches snapshot for ecma 7', () => { const compiler = createCompiler({ - entry: `${__dirname}/stubs/es-entry.js`, + entry: `${__dirname}/fixtures/es2015/entry.js`, output: { - path: `${__dirname}/dist-es`, + path: `${__dirname}/dist-2015`, filename: '[name].[chunkhash].js', chunkFilename: '[id].[name].[chunkhash].js', }, @@ -118,9 +118,9 @@ describe('when applied with uglifyOptions.ecma', () => { it('matches snapshot for ecma 8', () => { const compiler = createCompiler({ - entry: `${__dirname}/stubs/es-entry.js`, + entry: `${__dirname}/fixtures/es2015/entry.js`, output: { - path: `${__dirname}/dist-es`, + path: `${__dirname}/dist-2015`, filename: '[name].[chunkhash].js', chunkFilename: '[id].[name].[chunkhash].js', }, diff --git a/test/stubs/entry.js b/test/fixtures/entry.js similarity index 100% rename from test/stubs/entry.js rename to test/fixtures/entry.js diff --git a/test/stubs/es-dep.js b/test/fixtures/es2015/dep.js similarity index 100% rename from test/stubs/es-dep.js rename to test/fixtures/es2015/dep.js diff --git a/test/stubs/es-entry.js b/test/fixtures/es2015/entry.js similarity index 66% rename from test/stubs/es-entry.js rename to test/fixtures/es2015/entry.js index bd1d0407..a700e397 100644 --- a/test/stubs/es-entry.js +++ b/test/fixtures/es2015/entry.js @@ -1,8 +1,8 @@ -import foo, { bar } from './es-dep'; +import foo, { bar } from './dep'; function Foo() { const b = foo; - const baz = "baz" + Math.random(); + const baz = `baz${Math.random()}`; return () => { return { a: b + bar + baz, diff --git a/test/helpers.js b/test/helpers.js index debb1b35..5165011c 100644 --- a/test/helpers.js +++ b/test/helpers.js @@ -33,17 +33,9 @@ exports.compile = function compile(compiler) { exports.createCompiler = function createCompiler(options = {}) { const compiler = webpack({ + bail: true, cache: false, - entry: `${__dirname}/stubs/entry.js`, - resolve: { - unsafeCache: false, - }, - resolveLoader: { - unsafeCache: false, - }, - module: { - unsafeCache: false, - }, + entry: `${__dirname}/fixtures/entry.js`, output: { path: `${__dirname}/dist`, filename: '[name].[chunkhash].js', From c45d1637c692e499c2793278d28b84064ef5a9bc Mon Sep 17 00:00:00 2001 From: Steven Hargrove Date: Fri, 30 Jun 2017 09:20:11 -0400 Subject: [PATCH 14/15] updated snapshots --- test/__snapshots__/es2015.test.js.snap | 32 +++++++++++++------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/test/__snapshots__/es2015.test.js.snap b/test/__snapshots__/es2015.test.js.snap index 87a7f562..2972a568 100644 --- a/test/__snapshots__/es2015.test.js.snap +++ b/test/__snapshots__/es2015.test.js.snap @@ -2,7 +2,7 @@ exports[`es5: errors 1`] = `Array []`; -exports[`es5: main.567c8482b5d4c641f322.js 1`] = ` +exports[`es5: main.96c5ba3d7f23066ac123.js 1`] = ` "webpackJsonp([ 0 ], [ function(module, __webpack_exports__, __webpack_require__) { \\"use strict\\"; Object.defineProperty(__webpack_exports__, \\"__esModule\\", { @@ -10,7 +10,7 @@ exports[`es5: main.567c8482b5d4c641f322.js 1`] = ` }); var __WEBPACK_IMPORTED_MODULE_0__dep__ = __webpack_require__(1); __webpack_exports__.default = function() { - const b = __WEBPACK_IMPORTED_MODULE_0__dep__.b, baz = \\"baz\\" + Math.random(); + const b = __WEBPACK_IMPORTED_MODULE_0__dep__.b, baz = \`baz\${Math.random()}\`; return () => ({ a: b + __WEBPACK_IMPORTED_MODULE_0__dep__.a + baz, b: b, @@ -23,7 +23,7 @@ exports[`es5: main.567c8482b5d4c641f322.js 1`] = ` } ], [ 0 ]);" `; -exports[`es5: manifest.67273d936e04f664080e.js 1`] = ` +exports[`es5: manifest.a458e5044f91a97906ab.js 1`] = ` "!function(modules) { function __webpack_require__(moduleId) { if (installedModules[moduleId]) return installedModules[moduleId].exports; @@ -69,7 +69,7 @@ exports[`es5: manifest.67273d936e04f664080e.js 1`] = ` script.src = __webpack_require__.p + \\"\\" + chunkId + \\".\\" + ({ \\"0\\": \\"main\\" }[chunkId] || chunkId) + \\".\\" + { - \\"0\\": \\"567c8482b5d4c641f322\\" + \\"0\\": \\"96c5ba3d7f23066ac123\\" }[chunkId] + \\".js\\"; var timeout = setTimeout(onScriptComplete, 12e4); return script.onerror = script.onload = onScriptComplete, head.appendChild(script), @@ -99,7 +99,7 @@ exports[`es5: warnings 1`] = `Array []`; exports[`es6: errors 1`] = `Array []`; -exports[`es6: main.567c8482b5d4c641f322.js 1`] = ` +exports[`es6: main.96c5ba3d7f23066ac123.js 1`] = ` "webpackJsonp([ 0 ], [ (module, __webpack_exports__, __webpack_require__) => { \\"use strict\\"; Object.defineProperty(__webpack_exports__, \\"__esModule\\", { @@ -107,7 +107,7 @@ exports[`es6: main.567c8482b5d4c641f322.js 1`] = ` }); var __WEBPACK_IMPORTED_MODULE_0__dep__ = __webpack_require__(1); __webpack_exports__.default = function() { - const b = __WEBPACK_IMPORTED_MODULE_0__dep__.b, baz = \\"baz\\" + Math.random(); + const b = __WEBPACK_IMPORTED_MODULE_0__dep__.b, baz = \`baz\${Math.random()}\`; return () => ({ a: b + __WEBPACK_IMPORTED_MODULE_0__dep__.a + baz, b, @@ -120,7 +120,7 @@ exports[`es6: main.567c8482b5d4c641f322.js 1`] = ` } ], [ 0 ]);" `; -exports[`es6: manifest.67273d936e04f664080e.js 1`] = ` +exports[`es6: manifest.a458e5044f91a97906ab.js 1`] = ` "!(modules => { function __webpack_require__(moduleId) { if (installedModules[moduleId]) return installedModules[moduleId].exports; @@ -166,7 +166,7 @@ exports[`es6: manifest.67273d936e04f664080e.js 1`] = ` script.src = __webpack_require__.p + \\"\\" + chunkId + \\".\\" + ({ \\"0\\": \\"main\\" }[chunkId] || chunkId) + \\".\\" + { - \\"0\\": \\"567c8482b5d4c641f322\\" + \\"0\\": \\"96c5ba3d7f23066ac123\\" }[chunkId] + \\".js\\"; var timeout = setTimeout(onScriptComplete, 12e4); return script.onerror = script.onload = onScriptComplete, head.appendChild(script), @@ -195,7 +195,7 @@ exports[`es6: warnings 1`] = `Array []`; exports[`es7: errors 1`] = `Array []`; -exports[`es7: main.567c8482b5d4c641f322.js 1`] = ` +exports[`es7: main.96c5ba3d7f23066ac123.js 1`] = ` "webpackJsonp([ 0 ], [ (module, __webpack_exports__, __webpack_require__) => { \\"use strict\\"; Object.defineProperty(__webpack_exports__, \\"__esModule\\", { @@ -203,7 +203,7 @@ exports[`es7: main.567c8482b5d4c641f322.js 1`] = ` }); var __WEBPACK_IMPORTED_MODULE_0__dep__ = __webpack_require__(1); __webpack_exports__.default = function() { - const b = __WEBPACK_IMPORTED_MODULE_0__dep__.b, baz = \\"baz\\" + Math.random(); + const b = __WEBPACK_IMPORTED_MODULE_0__dep__.b, baz = \`baz\${Math.random()}\`; return () => ({ a: b + __WEBPACK_IMPORTED_MODULE_0__dep__.a + baz, b, @@ -216,7 +216,7 @@ exports[`es7: main.567c8482b5d4c641f322.js 1`] = ` } ], [ 0 ]);" `; -exports[`es7: manifest.67273d936e04f664080e.js 1`] = ` +exports[`es7: manifest.a458e5044f91a97906ab.js 1`] = ` "!(modules => { function __webpack_require__(moduleId) { if (installedModules[moduleId]) return installedModules[moduleId].exports; @@ -262,7 +262,7 @@ exports[`es7: manifest.67273d936e04f664080e.js 1`] = ` script.src = __webpack_require__.p + \\"\\" + chunkId + \\".\\" + ({ \\"0\\": \\"main\\" }[chunkId] || chunkId) + \\".\\" + { - \\"0\\": \\"567c8482b5d4c641f322\\" + \\"0\\": \\"96c5ba3d7f23066ac123\\" }[chunkId] + \\".js\\"; var timeout = setTimeout(onScriptComplete, 12e4); return script.onerror = script.onload = onScriptComplete, head.appendChild(script), @@ -291,7 +291,7 @@ exports[`es7: warnings 1`] = `Array []`; exports[`es8: errors 1`] = `Array []`; -exports[`es8: main.567c8482b5d4c641f322.js 1`] = ` +exports[`es8: main.96c5ba3d7f23066ac123.js 1`] = ` "webpackJsonp([ 0 ], [ (module, __webpack_exports__, __webpack_require__) => { \\"use strict\\"; Object.defineProperty(__webpack_exports__, \\"__esModule\\", { @@ -299,7 +299,7 @@ exports[`es8: main.567c8482b5d4c641f322.js 1`] = ` }); var __WEBPACK_IMPORTED_MODULE_0__dep__ = __webpack_require__(1); __webpack_exports__.default = function() { - const b = __WEBPACK_IMPORTED_MODULE_0__dep__.b, baz = \\"baz\\" + Math.random(); + const b = __WEBPACK_IMPORTED_MODULE_0__dep__.b, baz = \`baz\${Math.random()}\`; return () => ({ a: b + __WEBPACK_IMPORTED_MODULE_0__dep__.a + baz, b, @@ -312,7 +312,7 @@ exports[`es8: main.567c8482b5d4c641f322.js 1`] = ` } ], [ 0 ]);" `; -exports[`es8: manifest.67273d936e04f664080e.js 1`] = ` +exports[`es8: manifest.a458e5044f91a97906ab.js 1`] = ` "!(modules => { function __webpack_require__(moduleId) { if (installedModules[moduleId]) return installedModules[moduleId].exports; @@ -358,7 +358,7 @@ exports[`es8: manifest.67273d936e04f664080e.js 1`] = ` script.src = __webpack_require__.p + \\"\\" + chunkId + \\".\\" + ({ \\"0\\": \\"main\\" }[chunkId] || chunkId) + \\".\\" + { - \\"0\\": \\"567c8482b5d4c641f322\\" + \\"0\\": \\"96c5ba3d7f23066ac123\\" }[chunkId] + \\".js\\"; var timeout = setTimeout(onScriptComplete, 12e4); return script.onerror = script.onload = onScriptComplete, head.appendChild(script), From 8e798041fab47b16ca5c16d95fa33c4c1d148e81 Mon Sep 17 00:00:00 2001 From: Hartorn Date: Fri, 30 Jun 2017 21:55:23 +0200 Subject: [PATCH 15/15] Taking in account review * better use == null instead of === undefined || === null * hoisting one regex * using default params instead of || * do not throw exception if not needed * make less call to buildDefaultUglifyOptions and instead reset the least properties * ignore no-param-reassign rule --- src/index.js | 62 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/src/index.js b/src/index.js index eca5959b..1730f2b9 100644 --- a/src/index.js +++ b/src/index.js @@ -9,6 +9,12 @@ import RequestShortener from 'webpack/lib/RequestShortener'; import ModuleFilenameHelpers from 'webpack/lib/ModuleFilenameHelpers'; import uglify from 'uglify-es'; +/* eslint-disable + no-param-reassign +*/ + +const warningRegex = /\[.+:([0-9]+),([0-9]+)\]/; + const defaultUglifyOptions = { output: { comments: /^\**!|@preserve|@license|@cc_on/, @@ -32,14 +38,13 @@ class UglifyJsPlugin { this.uglifyOptions = this.options.uglifyOptions || {}; } - static buildDefaultUglifyOptions({ ecma, warnings, parse, compress, mangle, output, toplevel, ie8 }) { + static buildDefaultUglifyOptions({ ecma, warnings, parse = {}, compress = {}, mangle, output, toplevel, ie8 }) { return { ecma, warnings, - parse: parse || {}, - compress: compress || {}, - // eslint-disable-next-line no-undefined - mangle: mangle === undefined || mangle === null ? true : mangle, + parse, + compress, + mangle: mangle == null ? true : mangle, // Ignoring sourcemap from options sourceMap: null, output: { ...defaultUglifyOptions.output, ...output }, @@ -66,22 +71,22 @@ class UglifyJsPlugin { } static buildWarnings(warnings, file, sourceMap, warningsFilter, requestShortener) { + if (!sourceMap) { + return warnings; + } return warnings.reduce((accWarnings, warning) => { - if (!sourceMap) { - accWarnings.push(warning); - } else { - const match = /\[.+:([0-9]+),([0-9]+)\]/.exec(warning); - const line = +match[1]; - const column = +match[2]; - const original = sourceMap.originalPositionFor({ - line, - column, - }); + const match = warningRegex.exec(warning); + const line = +match[1]; + const column = +match[2]; + const original = sourceMap.originalPositionFor({ + line, + column, + }); - if (original && original.source && original.source !== file && warningsFilter(original.source)) { - accWarnings.push(`${warning.replace(/\[.+:([0-9]+),([0-9]+)\]/, '')}[${requestShortener.shorten(original.source)}:${original.line},${original.column}]`); - } + if (original && original.source && original.source !== file && warningsFilter(original.source)) { + accWarnings.push(`${warning.replace(warningRegex, '')}[${requestShortener.shorten(original.source)}:${original.line},${original.column}]`); } + return accWarnings; }, []); } @@ -145,14 +150,18 @@ class UglifyJsPlugin { apply(compiler) { const requestShortener = new RequestShortener(compiler.context); - compiler.plugin('compilation', (compilationArg) => { - const compilation = compilationArg; + // Copy uglify options + const uglifyOptions = UglifyJsPlugin.buildDefaultUglifyOptions(this.uglifyOptions); + // Making sure output options exists if there is an extractComments options + if (this.options.extractComments) { + uglifyOptions.output = uglifyOptions.output || {}; + } + compiler.plugin('compilation', (compilation) => { if (this.options.sourceMap) { compilation.plugin('build-module', (moduleArg) => { // to get detailed location info about errors - const moduleVar = moduleArg; - moduleVar.useSourceMap = true; + moduleArg.useSourceMap = true; }); } @@ -162,8 +171,8 @@ class UglifyJsPlugin { .concat(compilation.additionalChunkAssets || []) .filter(ModuleFilenameHelpers.matchObject.bind(null, this.options)) .forEach((file) => { - // Copy uglify options - const uglifyOptions = UglifyJsPlugin.buildDefaultUglifyOptions(this.uglifyOptions); + // Reseting sourcemap to null + uglifyOptions.sourceMap = null; let sourceMap; const asset = compilation.assets[file]; if (uglifiedAssets.has(asset)) { @@ -195,7 +204,6 @@ class UglifyJsPlugin { const extractedComments = []; let commentsFile = false; if (this.options.extractComments) { - uglifyOptions.output = uglifyOptions.output || {}; uglifyOptions.output.comments = UglifyJsPlugin.buildCommentsFunction(this.options, uglifyOptions, extractedComments); commentsFile = this.options.extractComments.filename || `${file}.LICENSE`; @@ -208,8 +216,10 @@ class UglifyJsPlugin { const { error, map, code, warnings } = uglify.minify({ [file]: input }, uglifyOptions); // Handling results + // Error case: add errors, and go to next file if (error) { - throw error; + compilation.errors.push(UglifyJsPlugin.buildError(error, file, sourceMap, compilation, requestShortener)); + return; } let outputSource;