From d8c37fd9fcb5b2c01f738bd508e3183e148fdf2e Mon Sep 17 00:00:00 2001 From: Frankie Dintino Date: Thu, 23 Aug 2018 02:56:01 -0400 Subject: [PATCH] Use terser to support minification of more permissive babel presets Currently, only ES5 javascript can be minified, due to the reliance on uglify-js. With terser (a maintained fork of the harmony branch of UglifyJS2) it is possible to support a broader range of javascript syntax. The API changed between uglify-js@2 and uglify-js@3 / terser, but the translation to the new API was fairly straightforward. It hews more closely to the original code than #815, and consequently I think it avoids regressing any features (for instance, the ability to include sourceContents in source maps or to control the comment stripping is retained). As browsers continue to support more features beyond ES5, and because babel recommends use of the 'env' preset, it will become increasingly likely that users' babel transpilation settings will cause errors when trying to minify with jspm and friends as long as it uses uglify-js. refs #815, #726 --- lib/output.js | 39 ++++++++++++++++++++++----------------- package.json | 4 ++-- test/test-sfx.html | 3 +-- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/lib/output.js b/lib/output.js index 777ee3e..e45d050 100644 --- a/lib/output.js +++ b/lib/output.js @@ -8,6 +8,17 @@ var extend = require('./utils').extend; var fromFileURL = require('./utils').fromFileURL; var toFileURL = require('./utils').toFileURL; +// Ugly hack to get around terser's strange code loading and export system +// (inherited from uglify-js), and the fact that their SourceMap wrapper is +// not exported +var TerserSourceMap = new Function('MOZ_SourceMap', function() { + var code = ['terser/lib/utils.js', 'terser/lib/sourcemap.js'].map(function(file) { + return fs.readFileSync(require.resolve(file), 'utf8'); + }); + code.push('return SourceMap;'); + return code.join('\n'); +}())(require('source-map')); + function countLines(str) { return str.split(/\r\n|\r|\n/).length; } @@ -72,36 +83,30 @@ function createOutput(outFile, outputs, basePath, sourceMaps, sourceMapContents) } function minify(output, fileName, mangle, uglifyOpts) { - var uglify = require('uglify-js'); + var terser = require('terser'); + var files = {}; + files[fileName] = output.source; var ast; try{ - ast = uglify.parse(output.source, { filename: fileName }); + ast = terser.minify(files, { + parse: {}, + compress: false, + mangle: mangle, + output: { ast: true, code: false } + }).ast; } catch(e){ throw new Error(e); } - ast.figure_out_scope(); - - ast = ast.transform(uglify.Compressor(uglifyOpts.compress)); - ast.figure_out_scope(); - if (mangle !== false) - ast.mangle_names(); var sourceMap; if (output.sourceMap) { if (typeof output.sourceMap === 'string') output.sourceMap = JSON.parse(output.sourceMap); - var sourceMapIn = output.sourceMap; - sourceMap = uglify.SourceMap({ + sourceMap = TerserSourceMap({ file: fileName, - orig: sourceMapIn + orig: output.sourceMap }); - - if (uglifyOpts.sourceMapIncludeSources && sourceMapIn && Array.isArray(sourceMapIn.sourcesContent)) { - sourceMapIn.sourcesContent.forEach(function(content, idx) { - sourceMap.get().setSourceContent(sourceMapIn.sources[idx], content); - }); - } } var outputOptions = uglifyOpts.beautify; diff --git a/package.json b/package.json index 14e7360..78142a4 100644 --- a/package.json +++ b/package.json @@ -19,8 +19,8 @@ "rollup": "^0.58.2", "source-map": "^0.5.3", "systemjs": "^0.19.46", - "traceur": "0.0.105", - "uglify-js": "^2.6.1" + "terser": "^3.8.1", + "traceur": "0.0.105" }, "devDependencies": { "babel": "^5.8.38", diff --git a/test/test-sfx.html b/test/test-sfx.html index 36f4f84..2374570 100644 --- a/test/test-sfx.html +++ b/test/test-sfx.html @@ -6,13 +6,12 @@