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/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 54b30298..890680a0 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ }, "dependencies": { "source-map": "^0.5.6", - "uglify-js": "^2.8.29", + "uglify-es": "^3.0.21", "webpack-sources": "^1.0.1" }, "devDependencies": { @@ -51,7 +51,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..1730f2b9 100644 --- a/src/index.js +++ b/src/index.js @@ -3,247 +3,277 @@ Author Tobias Koppers @sokra */ -// TODO: temporarily disabled rules -/* eslint-disable - no-undefined, - no-param-reassign, - no-underscore-dangle, - import/order -*/ import { SourceMapConsumer } from 'source-map'; -import { ConcatSource, RawSource, SourceMapSource } from 'webpack-sources'; - +import { SourceMapSource, RawSource, ConcatSource } from 'webpack-sources'; import RequestShortener from 'webpack/lib/RequestShortener'; import ModuleFilenameHelpers from 'webpack/lib/ModuleFilenameHelpers'; +import uglify from 'uglify-es'; -import uglify from 'uglify-js'; +/* eslint-disable + no-param-reassign +*/ + +const warningRegex = /\[.+:([0-9]+),([0-9]+)\]/; + +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)) { - options = {}; + this.options = {}; + } else { + this.options = options || {}; } - if (typeof options.compressor !== 'undefined') { - options.compress = options.compressor; + + this.options.test = this.options.test || /\.js($|\?)/i; + this.options.warningsFilter = this.options.warningsFilter || (() => true); + + this.uglifyOptions = this.options.uglifyOptions || {}; + } + + static buildDefaultUglifyOptions({ ecma, warnings, parse = {}, compress = {}, mangle, output, toplevel, ie8 }) { + return { + ecma, + warnings, + parse, + compress, + mangle: mangle == null ? true : mangle, + // Ignoring sourcemap from options + sourceMap: null, + output: { ...defaultUglifyOptions.output, ...output }, + toplevel, + ie8, + }; + } + + 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}`); } + return new Error(`${file} from UglifyJs\n${err.stack}`); + } - this.options = options; + static buildWarnings(warnings, file, sourceMap, warningsFilter, requestShortener) { + if (!sourceMap) { + return warnings; + } + return warnings.reduce((accWarnings, warning) => { + 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(warningRegex, '')}[${requestShortener.shorten(original.source)}:${original.line},${original.column}]`); + } + + return accWarnings; + }, []); } - apply(compiler) { - const { options } = this; - options.test = options.test || /\.js($|\?)/i; - const warningsFilter = options.warningsFilter || (() => true); + static buildCommentsFunction(options, uglifyOptions, extractedComments) { + const condition = {}; + 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; + 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) => { + let regexStr; + let regex; + 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); + break; + } + regexStr = condition[key]; + condition[key] = (astNode, comment) => new RegExp(regexStr).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); + }; + } + apply(compiler) { const requestShortener = new RequestShortener(compiler.context); + // 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 (options.sourceMap) { - compilation.plugin('build-module', (module) => { + if (this.options.sourceMap) { + compilation.plugin('build-module', (moduleArg) => { // to get detailed location info about errors - module.useSourceMap = true; + moduleArg.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 { + chunks.reduce((acc, chunk) => acc.concat(chunk.files || []), []) + .concat(compilation.additionalChunkAssets || []) + .filter(ModuleFilenameHelpers.matchObject.bind(null, this.options)) + .forEach((file) => { + // Reseting sourcemap to null + uglifyOptions.sourceMap = null; + let sourceMap; 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; + + 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); - 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); + + // Handling comment extraction + const extractedComments = []; + let commentsFile = false; + if (this.options.extractComments) { + uglifyOptions.output.comments = UglifyJsPlugin.buildCommentsFunction(this.options, uglifyOptions, extractedComments); + + commentsFile = this.options.extractComments.filename || `${file}.LICENSE`; + if (typeof commentsFile === 'function') { + commentsFile = commentsFile(file); + } } - } - 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; + + // Calling uglify + const { error, map, code, warnings } = uglify.minify({ [file]: input }, uglifyOptions); + + // Handling results + // Error case: add errors, and go to next file + if (error) { + compilation.errors.push(UglifyJsPlugin.buildError(error, file, sourceMap, compilation, requestShortener)); + return; + } + + let outputSource; + if (map) { + outputSource = new SourceMapSource(code, file, JSON.parse(map), input, inputSourceMap); } else { - // No extract condition is given. Extract comments that match output.comments instead of preserving them - condition.preserve = false; - condition.extract = output.comments; + outputSource = new RawSource(code); } - // 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; + // Write extracted comments to 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); } - default: { - const defaultRegex = condition[key]; - condition[key] = (astNode, comment) => defaultRegex.test(comment.value); + if (banner) { + outputSource = new ConcatSource( + `/*! ${banner} */\n`, outputSource, + ); } } - }); - - // 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); + 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; } - // 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, - ); + // 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)); } - 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(); }); }); diff --git a/test/__snapshots__/all-options.test.js.snap b/test/__snapshots__/all-options.test.js.snap index e881fa7c..1cb10095 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 -Dropping unused variable a [./test/stubs/entry.js:4,0]", + "Error: main.0c220ec66316af2c1b24.js from UglifyJs +Dropping unused variable a [./test/fixtures/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__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.a458e5044f91a97906ab.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\\": \\"96c5ba3d7f23066ac123\\" + }[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.96c5ba3d7f23066ac123.js 1`] = ` +"webpackJsonp([ 0 ], [ (module, __webpack_exports__, __webpack_require__) => { + \\"use strict\\"; + Object.defineProperty(__webpack_exports__, \\"__esModule\\", { + value: !0 + }); + 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()}\`; + return () => ({ + a: b + __WEBPACK_IMPORTED_MODULE_0__dep__.a + baz, + b, + baz + }); + }; +}, (module, __webpack_exports__, __webpack_require__) => { + \\"use strict\\"; + __webpack_exports__.a = \\"bar\\", __webpack_exports__.b = \\"foo\\"; +} ], [ 0 ]);" +`; + +exports[`es6: manifest.a458e5044f91a97906ab.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\\": \\"96c5ba3d7f23066ac123\\" + }[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.96c5ba3d7f23066ac123.js 1`] = ` +"webpackJsonp([ 0 ], [ (module, __webpack_exports__, __webpack_require__) => { + \\"use strict\\"; + Object.defineProperty(__webpack_exports__, \\"__esModule\\", { + value: !0 + }); + 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()}\`; + return () => ({ + a: b + __WEBPACK_IMPORTED_MODULE_0__dep__.a + baz, + b, + baz + }); + }; +}, (module, __webpack_exports__, __webpack_require__) => { + \\"use strict\\"; + __webpack_exports__.a = \\"bar\\", __webpack_exports__.b = \\"foo\\"; +} ], [ 0 ]);" +`; + +exports[`es7: manifest.a458e5044f91a97906ab.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\\": \\"96c5ba3d7f23066ac123\\" + }[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.96c5ba3d7f23066ac123.js 1`] = ` +"webpackJsonp([ 0 ], [ (module, __webpack_exports__, __webpack_require__) => { + \\"use strict\\"; + Object.defineProperty(__webpack_exports__, \\"__esModule\\", { + value: !0 + }); + 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()}\`; + return () => ({ + a: b + __WEBPACK_IMPORTED_MODULE_0__dep__.a + baz, + b, + baz + }); + }; +}, (module, __webpack_exports__, __webpack_require__) => { + \\"use strict\\"; + __webpack_exports__.a = \\"bar\\", __webpack_exports__.b = \\"foo\\"; +} ], [ 0 ]);" +`; + +exports[`es8: manifest.a458e5044f91a97906ab.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\\": \\"96c5ba3d7f23066ac123\\" + }[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/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/es2015.test.js b/test/es2015.test.js new file mode 100644 index 00000000..b84900a9 --- /dev/null +++ b/test/es2015.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}/fixtures/es2015/entry.js`, + output: { + path: `${__dirname}/dist-2015`, + 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}/fixtures/es2015/entry.js`, + output: { + path: `${__dirname}/dist-2015`, + 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}/fixtures/es2015/entry.js`, + output: { + path: `${__dirname}/dist-2015`, + 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}/fixtures/es2015/entry.js`, + output: { + path: `${__dirname}/dist-2015`, + 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/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/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/fixtures/es2015/dep.js b/test/fixtures/es2015/dep.js new file mode 100644 index 00000000..6d24cac9 --- /dev/null +++ b/test/fixtures/es2015/dep.js @@ -0,0 +1,2 @@ +export const bar = 'bar'; +export default 'foo'; diff --git a/test/fixtures/es2015/entry.js b/test/fixtures/es2015/entry.js new file mode 100644 index 00000000..a700e397 --- /dev/null +++ b/test/fixtures/es2015/entry.js @@ -0,0 +1,15 @@ +import foo, { bar } from './dep'; + +function Foo() { + const b = foo; + const baz = `baz${Math.random()}`; + return () => { + return { + a: b + bar + baz, + b, + baz, + }; + }; +} + +export default Foo; diff --git a/test/helpers.js b/test/helpers.js index 1c46a1a1..5165011c 100644 --- a/test/helpers.js +++ b/test/helpers.js @@ -31,20 +31,22 @@ exports.compile = function compile(compiler) { }); }; -exports.createCompiler = function createCompiler(options) { - const compiler = webpack(options || { +exports.createCompiler = function createCompiler(options = {}) { + const compiler = webpack({ bail: true, cache: false, - entry: `${__dirname}/stubs/entry.js`, + entry: `${__dirname}/fixtures/entry.js`, 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/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);