From c740236e1bc30409805fdda76ee3e5d75c04859b Mon Sep 17 00:00:00 2001 From: Gary Date: Sun, 18 Oct 2020 23:34:42 -0700 Subject: [PATCH 1/7] Update documentation. --- CHANGELOG.md | 4 ++++ README.md | 17 +++++++++-------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index be83050..1197e63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0 + - Breaking: Replaced `uglify-es` with `terser` ([#66](https://github.com/gdborton/webpack-parallel-uglify-plugin/pull/66)) + - Chore: Updated dependencies to address identified vulnerabilities. ([#65](https://github.com/gdborton/webpack-parallel-uglify-plugin/pull/65)) + ## 1.1.2 - Enable source maps by default. ([#61](https://github.com/gdborton/webpack-parallel-uglify-plugin/pull/61)) diff --git a/README.md b/README.md index 76ba212..86a5d9f 100644 --- a/README.md +++ b/README.md @@ -22,16 +22,17 @@ module.exports = { sourceMap, // Optional Boolean. This slows down the compilation. Defaults to false. uglifyJS: { // These pass straight through to uglify-js@3. - // Cannot be used with uglifyES. - // Defaults to {} if not neither uglifyJS or uglifyES are provided. - // You should use this option if you need to ensure es5 support. uglify-js will produce an error message - // if it comes across any es6 code that it can't parse. + // Cannot be used with terser. + // Defaults to {} if not neither uglifyJS or terser are provided. + // You should use this option if you need to ensure es5 support. uglify-js will produce an + // error message if it comes across any es6 code that it can't parse. }, - uglifyES: { - // These pass straight through to uglify-es. + terser: { + // These pass straight through to terser. // Cannot be used with uglifyJS. - // uglify-es is a version of uglify that understands newer es6 syntax. You should use this option if the - // files that you're minifying do not need to run in older browsers/versions of node. + // terser is a fork of uglify-es, a version of uglify that supports ES6+ version of uglify + // that understands newer es6 syntax. You should use this option if the files that you're + // minifying do not need to run in older browsers/versions of node. } }), ], From 655f906bf3a759fe6d1d0e54c96151f015d00217 Mon Sep 17 00:00:00 2001 From: Gary Date: Sun, 18 Oct 2020 23:35:18 -0700 Subject: [PATCH 2/7] Replace uglifyes with terser in pkg.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b2d651e..2ab2898 100644 --- a/package.json +++ b/package.json @@ -42,8 +42,8 @@ "glob": "^7.0.5", "mkdirp": "^0.5.1", "pify": "^3.0.0", + "terser": "^5.3.5", "tmp": "0.0.29", - "uglify-es": "^3.3.9", "uglify-js": "^3.6.0", "webpack-sources": "^1.0.0", "worker-farm": "^1.3.1" From 207d7fa1c3501b884f6724bba1fa62264a8901d5 Mon Sep 17 00:00:00 2001 From: Gary Date: Sun, 18 Oct 2020 23:35:31 -0700 Subject: [PATCH 3/7] Hook up terser. --- index.js | 10 ++++---- lib/worker.js | 58 ++++++++++++++++++++++++++------------------- test/index.js | 4 ++-- test/lib/uglifer.js | 6 ++--- test/lib/worker.js | 14 ++++++----- 5 files changed, 51 insertions(+), 41 deletions(-) diff --git a/index.js b/index.js index 4c89f7c..bfb3396 100644 --- a/index.js +++ b/index.js @@ -5,20 +5,20 @@ function sourceMapError(lib) { } function FasterUglifyPlugin(options) { - if (options.uglifyJS && options.uglifyES) { - throw new TypeError('You cannot use both uglifyJS and uglifyES for the same plugin.'); + if (options.uglifyJS && options.terser) { + throw new TypeError('You cannot use both uglifyJS and terser for the same plugin.'); } if (options.uglifyJS && options.uglifyJS.sourceMap) { throw new TypeError(sourceMapError('uglifyJS')); } - if (options.uglifyES && options.uglifyES.sourceMap) { - throw new TypeError(sourceMapError('uglifyES')); + if (options.terser && options.terser.sourceMap) { + throw new TypeError(sourceMapError('terser')); } this.options = options; - if (!(this.options.uglifyJS || this.options.uglifyES)) { + if (!(this.options.uglifyJS || this.options.terser)) { this.options.uglifyJS = {}; } } diff --git a/lib/worker.js b/lib/worker.js index 491bc0b..c4d2e47 100644 --- a/lib/worker.js +++ b/lib/worker.js @@ -23,19 +23,22 @@ function minify(source, map, uglifyOptions, uglifier) { } const result = uglifier.minify(source, opts); - if (result.error) { - if (result.error.name === 'SyntaxError') { - const frame = codeFrame(source, result.error.line, result.error.col); - const errorMessage = `${result.error.name}: ${result.error.message}\n${frame}`; - throw new SyntaxError(errorMessage); + const prom = result.then ? result : Promise.resolve(result); + return prom.then(resolved => { + if (resolved.error) { + if (resolved.error.name === 'SyntaxError') { + const frame = codeFrame(source, resolved.error.line, resolved.error.col); + const errorMessage = `${resolved.error.name}: ${resolved.error.message}\n${frame}`; + throw new SyntaxError(errorMessage); + } + + throw resolved.error; } - throw result.error; - } - - result.code = result.code.replace(new RegExp(BOGUS_SOURCEMAP_URL), ''); - - return result; + resolved.code = resolved.code.replace(new RegExp(BOGUS_SOURCEMAP_URL), ''); + + return result; + }); } /** @@ -65,21 +68,26 @@ function processMessage(msgLocation, callback) { const cacheKey = cache.createCacheKey(source + !!map, message.options); // We do not check the cache here because we already determined that this asset yields a cache // miss in the parent process. - const { uglifyES } = message.options; + const { terser } = message.options; const { uglifyJS } = message.options; - const uglifier = uglifyES ? require('uglify-es') : require('uglify-js'); // eslint-disable-line global-require, max-len - const minifiedContent = minify(source, map, uglifyES || uglifyJS, uglifier); - cache.saveToCache(cacheKey, JSON.stringify({ - source: minifiedContent.code, - map: minifiedContent.map, - }), message.cacheDir); - - tmpFile.update(msgLocation, JSON.stringify({ - source: minifiedContent.code, - map: minifiedContent.map, - cacheKey, - })); - callback(null, msgLocation); + // eslint-disable-next-line global-require + const uglifier = terser ? require('terser') : require('uglify-js'); + minify(source, map, terser || uglifyJS, uglifier) + .then(minifiedContent => { + cache.saveToCache(cacheKey, JSON.stringify({ + source: minifiedContent.code, + map: minifiedContent.map, + }), message.cacheDir); + + tmpFile.update(msgLocation, JSON.stringify({ + source: minifiedContent.code, + map: minifiedContent.map, + cacheKey, + })); + callback(null, msgLocation); + }).catch(e => { + callback(e.message, msgLocation); + }); } catch (e) { callback(e.message, msgLocation); } diff --git a/test/index.js b/test/index.js index 3bc832c..25c71a6 100644 --- a/test/index.js +++ b/test/index.js @@ -19,7 +19,7 @@ test('creating a WebpackParallelUglifyPlugin instance w/ both uglify options thr t.throws(() => { new WebpackParallelUglifyPlugin({ uglifyJS: {}, - uglifyES: {}, + terser: {}, }); }); }); @@ -33,7 +33,7 @@ test('creating a WebpackParallelUglifyPlugin instance with uglify.sourceMap thro t.throws(() => { new WebpackParallelUglifyPlugin({ - uglifyES: { sourceMap: true }, + terser: { sourceMap: true }, }); }); }); diff --git a/test/lib/uglifer.js b/test/lib/uglifer.js index 698cdb8..09c03bd 100644 --- a/test/lib/uglifer.js +++ b/test/lib/uglifer.js @@ -63,7 +63,7 @@ function createFakeES6CompilationObject() { assets: { 'someFile.js': { source() { - return '() => {}'; + return 'const test = () => { function asdf(){console.log("a")} asdf()}; test();'; }, map() { return null; @@ -231,11 +231,11 @@ test('Passing uglifyJS options throws an error when minifying es6', (t) => { }); }); -test('Passing uglifyES options does not throw an error when minifying es6', (t) => { +test('Passing terser options does not throw an error when minifying es6', (t) => { const es6CompilationObject = createFakeES6CompilationObject(); return processAssets(es6CompilationObject, { sourceMap: false, - uglifyES: {}, + terser: {}, }).then(() => { assertNoError(es6CompilationObject, t); }); diff --git a/test/lib/worker.js b/test/lib/worker.js index 7febfac..6b01ae1 100644 --- a/test/lib/worker.js +++ b/test/lib/worker.js @@ -42,18 +42,20 @@ test.afterEach(() => { test.serial('minify should not return a map if called with a RawSource object', (t) => { const { map } = rawSource.sourceAndMap(); - const result = minify(codeSource, map, undefined, uglify); - t.is(result.map, undefined); - t.is(result.code, minifiedContent.code); // should produce the same minified content. + return minify(codeSource, map, undefined, uglify).then(result => { + t.is(result.map, undefined); + t.is(result.code, minifiedContent.code); // should produce the same minified content. + }); }); test.serial( 'minify should return a valid source map if called with an OriginalSource object', (t) => { const { map } = originalSource.sourceAndMap(); - const result = minify(codeSource, map, undefined, uglify); - t.truthy(result.map); - t.is(result.code, minifiedContent.code); // should produce the same minified content. + return minify(codeSource, map, undefined, uglify).then(result => { + t.truthy(result.map); + t.is(result.code, minifiedContent.code); // should produce the same minified content. + }); }, ); From a8693c1f3251408efa69f43f74fb3e895ec86425 Mon Sep 17 00:00:00 2001 From: Gary Date: Mon, 19 Oct 2020 00:22:46 -0700 Subject: [PATCH 4/7] Update keywords. --- package.json | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 2ab2898..a45a85c 100644 --- a/package.json +++ b/package.json @@ -12,9 +12,20 @@ "url": "git://github.com/gdborton/webpack-parallel-uglify-plugin.git" }, "keywords": [ + "compress", + "compressor", + "min", + "minification", + "minifier", + "minify", + "optimize", + "optimizer", + "terser", + "uglify", + "uglify-es", + "uglify-js", "webpack", - "uglifyjs", - "minimize" + "webpack-plugin" ], "ava": { "require": [ From c742de92aa5dbb9242ae1e6a976d3d939c8811c6 Mon Sep 17 00:00:00 2001 From: Gary Date: Sat, 5 Dec 2020 14:50:24 -0800 Subject: [PATCH 5/7] Update webpack plugin api to v5 --- CHANGELOG.md | 1 + index.js | 15 +++++++++------ package.json | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1197e63..1ecc774 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ## 2.0.0 - Breaking: Replaced `uglify-es` with `terser` ([#66](https://github.com/gdborton/webpack-parallel-uglify-plugin/pull/66)) + - Breaking: Update to webpack v5 api ([#68](https://github.com/gdborton/webpack-parallel-uglify-plugin/pull/68)) - Chore: Updated dependencies to address identified vulnerabilities. ([#65](https://github.com/gdborton/webpack-parallel-uglify-plugin/pull/65)) ## 1.1.2 diff --git a/index.js b/index.js index bfb3396..8be4cee 100644 --- a/index.js +++ b/index.js @@ -4,7 +4,7 @@ function sourceMapError(lib) { return `You should not pass options.${lib}.sourceMap, did you mean options.sourceMap?`; } -function FasterUglifyPlugin(options) { +function ParallelUglifyPlugin(options) { if (options.uglifyJS && options.terser) { throw new TypeError('You cannot use both uglifyJS and terser for the same plugin.'); } @@ -23,18 +23,21 @@ function FasterUglifyPlugin(options) { } } -FasterUglifyPlugin.prototype.apply = function apply(compiler) { - compiler.plugin('compilation', (compilation) => { - compilation.plugin('optimize-chunk-assets', (chunks, callback) => { +ParallelUglifyPlugin.prototype.apply = function apply(compiler) { + compiler.hooks.compilation.tap('ParallelUglifyPlugin', (compilation) => { + compilation.hooks.processAssets.tapAsync({ + name: 'ParallelUglifyPlugin', + stage: compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE, + }, (chunks, callback) => { uglifier.processAssets(compilation, this.options).then(() => { callback(); }); }); }); - compiler.plugin('done', () => { + compiler.hooks.done.tap('ParallelUglifyPlugin', () => { uglifier.pruneCache(this.options); }); }; -module.exports = FasterUglifyPlugin; +module.exports = ParallelUglifyPlugin; diff --git a/package.json b/package.json index a45a85c..24c3f55 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "webpack-parallel-uglify-plugin", - "version": "1.1.2", + "version": "2.0.0-alpha-3", "description": "A webpack plugin to run uglifyjs in parallel.", "main": "index.js", "scripts": { From dcdcabace1604e7b2ae1fcd6c234ec6947f5a23c Mon Sep 17 00:00:00 2001 From: Gary Date: Sat, 5 Dec 2020 15:09:57 -0800 Subject: [PATCH 6/7] Switch to appveyor, travis no longer free. --- .travis.yml | 10 ---------- README.md | 2 +- appveyor.yml | 26 ++++++++++++++++++++++++++ 3 files changed, 27 insertions(+), 11 deletions(-) delete mode 100644 .travis.yml create mode 100644 appveyor.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 6093591..0000000 --- a/.travis.yml +++ /dev/null @@ -1,10 +0,0 @@ -language: node_js -node_js: - - '10' - - '12' - - '14' -script: - - 'npm run lint' - - 'npm test' -after_success: - - './node_modules/.bin/nyc report --reporter=text-lcov | ./node_modules/.bin/coveralls' diff --git a/README.md b/README.md index 86a5d9f..f2943fb 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# webpack-parallel-uglify-plugin [![Build Status](https://travis-ci.org/gdborton/webpack-parallel-uglify-plugin.svg?branch=master)](https://travis-ci.org/gdborton/webpack-parallel-uglify-plugin) [![Coverage Status](https://coveralls.io/repos/github/gdborton/webpack-parallel-uglify-plugin/badge.svg?branch=master)](https://coveralls.io/github/gdborton/webpack-parallel-uglify-plugin?branch=master) +# webpack-parallel-uglify-plugin [![Build status](https://ci.appveyor.com/api/projects/status/v1xvpvx0xfumv9fh/branch/master?svg=true)](https://ci.appveyor.com/project/gdborton/webpack-parallel-uglify-plugin/branch/master) [![Coverage Status](https://coveralls.io/repos/github/gdborton/webpack-parallel-uglify-plugin/badge.svg?branch=master)](https://coveralls.io/github/gdborton/webpack-parallel-uglify-plugin?branch=master) This plugin serves to help projects with many entry points speed up their builds. The UglifyJS plugin provided with webpack runs sequentially on each of the output files. This plugin runs uglify in parallel with one thread for each of your available cpus. This can lead to significantly reduced build times as minification is very CPU intensive. diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..07c5ee0 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,26 @@ +image: + - Ubuntu + +environment: + # Test against these versions of Node.js and io.js + matrix: + # node.js + - nodejs_version: "10" + - nodejs_version: "12" + - nodejs_version: "14" + +# Install scripts. (runs after repo cloning) +install: + - nvm install $nodejs_version + - npm install + +# Post-install test scripts. +test_script: + # Output useful info for debugging. + - node --version + - npm --version + # run tests + - npm test + +after_test: + - './node_modules/.bin/nyc report --reporter=text-lcov | ./node_modules/.bin/coveralls' \ No newline at end of file From 4d95f852fd1ff8114cb7e1dcb72ffa3c71065698 Mon Sep 17 00:00:00 2001 From: Gary Date: Sat, 5 Dec 2020 15:48:14 -0800 Subject: [PATCH 7/7] fix build issues --- index.js | 33 +++++++++++++++++++-------------- test/index.js | 30 +++++++++++++++++++++++------- 2 files changed, 42 insertions(+), 21 deletions(-) diff --git a/index.js b/index.js index 8be4cee..62dd66d 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,4 @@ -const uglifier = require('./lib/uglifier'); +const uglifier = require("./lib/uglifier"); function sourceMapError(lib) { return `You should not pass options.${lib}.sourceMap, did you mean options.sourceMap?`; @@ -6,15 +6,17 @@ function sourceMapError(lib) { function ParallelUglifyPlugin(options) { if (options.uglifyJS && options.terser) { - throw new TypeError('You cannot use both uglifyJS and terser for the same plugin.'); + throw new TypeError( + "You cannot use both uglifyJS and terser for the same plugin." + ); } if (options.uglifyJS && options.uglifyJS.sourceMap) { - throw new TypeError(sourceMapError('uglifyJS')); + throw new TypeError(sourceMapError("uglifyJS")); } if (options.terser && options.terser.sourceMap) { - throw new TypeError(sourceMapError('terser')); + throw new TypeError(sourceMapError("terser")); } this.options = options; @@ -24,18 +26,21 @@ function ParallelUglifyPlugin(options) { } ParallelUglifyPlugin.prototype.apply = function apply(compiler) { - compiler.hooks.compilation.tap('ParallelUglifyPlugin', (compilation) => { - compilation.hooks.processAssets.tapAsync({ - name: 'ParallelUglifyPlugin', - stage: compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE, - }, (chunks, callback) => { - uglifier.processAssets(compilation, this.options).then(() => { - callback(); - }); - }); + compiler.hooks.compilation.tap("ParallelUglifyPlugin", (compilation) => { + compilation.hooks.processAssets.tapAsync( + { + name: "ParallelUglifyPlugin", + stage: compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE, + }, + (chunks, callback) => { + uglifier.processAssets(compilation, this.options).then(() => { + callback(); + }); + } + ); }); - compiler.hooks.done.tap('ParallelUglifyPlugin', () => { + compiler.hooks.done.tap("ParallelUglifyPlugin", () => { uglifier.pruneCache(this.options); }); }; diff --git a/test/index.js b/test/index.js index 25c71a6..8c7a2e7 100644 --- a/test/index.js +++ b/test/index.js @@ -43,13 +43,32 @@ test('providing no uglify options defaults to uglifyJS: {}', (t) => { t.deepEqual(plugin.options, { uglifyJS: {} }); }); +function FakeCompilation() { + this.hooks = { + processAssets: { + tapAsync: () => { + + } + } + } +} + function FakeCompiler() { const callbacks = {}; + const fakeCompilation = new FakeCompilation(); this.assets = []; - - this.plugin = (event, callback) => { - callbacks[event] = callback; - }; + this.hooks = { + compilation: { + tap: (pluginName, callback) => { + callbacks['compilation'] = () => callback(fakeCompilation); + } + }, + done: { + tap: (pluginName, callback) => { + callbacks['done'] = callback; + } + } + } this.fireEvent = (event, ...args) => { callbacks[event].apply(this, args); @@ -82,10 +101,7 @@ test('deleting unused cache files after all asset optimizations', (t) => { const compiler = new FakeCompiler(); uglifyPlugin.apply(compiler); compiler.fireEvent('compilation', compiler); - compiler.fireEvent('optimize-chunk-assets', null, () => {}); - compiler.fireEvent('optimize-chunk-assets', null, () => {}); t.is(fs.unlinkSync.callCount, 0, 'Cache should not be cleared by optimize-chunk-assets'); - compiler.fireEvent('done'); t.deepEqual( fs.unlinkSync.args,