diff --git a/README.md b/README.md index bea0910d..743ce450 100644 --- a/README.md +++ b/README.md @@ -122,6 +122,14 @@ A query to select browsers (ex: last 2 versions, > 5%) using [browserslist](http Note, browsers' results are overridden by explicit items from `targets`. +### `targets.uglify` + +`number | true` + +If you are using UglifyJS to minify your code, then targeting later browsers will throw a syntax error. + +To prevent this - specify the uglify option, which will enable all plugins and, as a result, fully compile your code to ES5. Note, that useBuiltIns will work as before, and only include the polyfills that your target(s) need. + ### `loose` `boolean`, defaults to `false`. diff --git a/src/index.js b/src/index.js index da606295..634435fc 100644 --- a/src/index.js +++ b/src/index.js @@ -94,29 +94,33 @@ const _extends = Object.assign || function (target) { export const getTargets = (targets = {}) => { - const targetOps = _extends({}, targets); + const targetOpts = _extends({}, targets); - if (targetOps.node === true || targetOps.node === "current") { - targetOps.node = getCurrentNodeVersion(); + if (targetOpts.node === true || targetOpts.node === "current") { + targetOpts.node = getCurrentNodeVersion(); + } + + if (targetOpts.hasOwnProperty("uglify") && !targetOpts.uglify) { + delete targetOpts.uglify; } // Replace Electron target with its Chrome equivalent - if (targetOps.electron) { - const electronChromeVersion = getElectronChromeVersion(targetOps.electron); + if (targetOpts.electron) { + const electronChromeVersion = getElectronChromeVersion(targetOpts.electron); - targetOps.chrome = targetOps.chrome - ? Math.min(targetOps.chrome, electronChromeVersion) + targetOpts.chrome = targetOpts.chrome + ? Math.min(targetOpts.chrome, electronChromeVersion) : electronChromeVersion; - delete targetOps.electron; + delete targetOpts.electron; } - const browserOpts = targetOps.browsers; + const browserOpts = targetOpts.browsers; if (isBrowsersQueryValid(browserOpts)) { const queryBrowsers = getLowestVersions(browserslist(browserOpts)); - return mergeBrowsers(queryBrowsers, targetOps); + return mergeBrowsers(queryBrowsers, targetOpts); } - return targetOps; + return targetOpts; }; let hasBeenLogged = false; @@ -143,6 +147,14 @@ const filterItem = (targets, exclusions, list, item) => { return isRequired && notExcluded; }; +const getBuiltInTargets = (targets) => { + const builtInTargets = _extends({}, targets); + if (builtInTargets.uglify != null) { + delete builtInTargets.uglify; + } + return builtInTargets; +}; + export const transformIncludesAndExcludes = (opts) => ({ all: opts, plugins: opts.filter((opt) => !opt.match(/^(es\d+|web)\./)), @@ -157,15 +169,17 @@ export default function buildPreset(context, opts = {}) { const include = transformIncludesAndExcludes(validatedOptions.include); const exclude = transformIncludesAndExcludes(validatedOptions.exclude); + const filterPlugins = filterItem.bind(null, targets, exclude.plugins, pluginList); const transformations = Object.keys(pluginList) .filter(filterPlugins) .concat(include.plugins); let polyfills; + let polyfillTargets; if (useBuiltIns) { - const filterBuiltIns = filterItem.bind(null, targets, exclude.builtIns, builtInsList); - + polyfillTargets = getBuiltInTargets(targets); + const filterBuiltIns = filterItem.bind(null, polyfillTargets, exclude.builtIns, builtInsList); polyfills = Object.keys(builtInsList) .concat(defaultInclude) .filter(filterBuiltIns) @@ -185,7 +199,7 @@ export default function buildPreset(context, opts = {}) { if (useBuiltIns && polyfills.length) { console.log("\nUsing polyfills:"); polyfills.forEach((polyfill) => { - logPlugin(polyfill, targets, builtInsList); + logPlugin(polyfill, polyfillTargets, builtInsList); }); } } diff --git a/test/debug-fixtures/builtins-uglify/options.json b/test/debug-fixtures/builtins-uglify/options.json new file mode 100644 index 00000000..9a5b6d27 --- /dev/null +++ b/test/debug-fixtures/builtins-uglify/options.json @@ -0,0 +1,13 @@ +{ + "presets": [ + ["../../lib", { + "debug": true, + "targets": { + "chrome": 55, + "uglify": true + }, + "useBuiltIns": true, + "modules": false + }] + ] +} diff --git a/test/debug-fixtures/builtins-uglify/stdout.txt b/test/debug-fixtures/builtins-uglify/stdout.txt new file mode 100644 index 00000000..0cfe3cc4 --- /dev/null +++ b/test/debug-fixtures/builtins-uglify/stdout.txt @@ -0,0 +1,41 @@ +babel-preset-env: `DEBUG` option + +Using targets: +{ + "chrome": 55, + "uglify": true +} + +Modules transform: false + +Using plugins: + transform-es2015-arrow-functions {"uglify":true} + transform-es2015-block-scoped-functions {"uglify":true} + transform-es2015-block-scoping {"uglify":true} + transform-es2015-classes {"uglify":true} + transform-es2015-computed-properties {"uglify":true} + check-es2015-constants {"uglify":true} + transform-es2015-destructuring {"uglify":true} + transform-es2015-for-of {"uglify":true} + transform-es2015-function-name {"uglify":true} + transform-es2015-literals {"uglify":true} + transform-es2015-object-super {"uglify":true} + transform-es2015-parameters {"uglify":true} + transform-es2015-shorthand-properties {"uglify":true} + transform-es2015-spread {"uglify":true} + transform-es2015-sticky-regex {"uglify":true} + transform-es2015-template-literals {"uglify":true} + transform-es2015-typeof-symbol {"uglify":true} + transform-es2015-unicode-regex {"uglify":true} + transform-regenerator {"uglify":true} + transform-exponentiation-operator {"uglify":true} + transform-async-to-generator {"uglify":true} + syntax-trailing-function-commas {"chrome":55,"uglify":true} + +Using polyfills: + es7.string.pad-start {"chrome":55} + es7.string.pad-end {"chrome":55} + web.timers {"chrome":55} + web.immediate {"chrome":55} + web.dom.iterable {"chrome":55} +src/in.js -> lib/in.js \ No newline at end of file diff --git a/test/debug-fixtures/built-ins/options.json b/test/debug-fixtures/builtins/options.json similarity index 100% rename from test/debug-fixtures/built-ins/options.json rename to test/debug-fixtures/builtins/options.json diff --git a/test/debug-fixtures/built-ins/stdout.txt b/test/debug-fixtures/builtins/stdout.txt similarity index 100% rename from test/debug-fixtures/built-ins/stdout.txt rename to test/debug-fixtures/builtins/stdout.txt diff --git a/test/fixtures/preset-options/uglify/actual.js b/test/fixtures/preset-options/uglify/actual.js new file mode 100644 index 00000000..6ce39f10 --- /dev/null +++ b/test/fixtures/preset-options/uglify/actual.js @@ -0,0 +1,3 @@ +import "babel-polyfill"; + +const a = 1; diff --git a/test/fixtures/preset-options/uglify/expected.js b/test/fixtures/preset-options/uglify/expected.js new file mode 100644 index 00000000..1b6f9666 --- /dev/null +++ b/test/fixtures/preset-options/uglify/expected.js @@ -0,0 +1,9 @@ +import "core-js/modules/es7.string.pad-start"; +import "core-js/modules/es7.string.pad-end"; +import "core-js/modules/web.timers"; +import "core-js/modules/web.immediate"; +import "core-js/modules/web.dom.iterable"; +import "regenerator-runtime/runtime"; + + +var a = 1; diff --git a/test/fixtures/preset-options/uglify/options.json b/test/fixtures/preset-options/uglify/options.json new file mode 100644 index 00000000..dd788b3d --- /dev/null +++ b/test/fixtures/preset-options/uglify/options.json @@ -0,0 +1,12 @@ +{ + "presets": [ + ["../../../../lib", { + "targets": { + "chrome": 55, + "uglify": true + }, + "modules": false, + "useBuiltIns": true + }] + ] +} diff --git a/test/index.spec.js b/test/index.spec.js index 997d8ed5..f3b82ddc 100644 --- a/test/index.spec.js +++ b/test/index.spec.js @@ -85,6 +85,28 @@ describe("babel-preset-env", () => { }); }); + describe("getTargets + uglify", () => { + it("should work with `true`", function() { + assert.deepEqual(babelPresetEnv.getTargets({ + uglify: true + }), { + uglify: true + }); + }); + + it("should ignore `false`", function() { + assert.deepEqual(babelPresetEnv.getTargets({ + uglify: false + }), {}); + }); + + it("should ignore `null`", function() { + assert.deepEqual(babelPresetEnv.getTargets({ + uglify: null + }), {}); + }); + }); + describe("isPluginRequired", () => { it("returns true if no targets are specified", () => { const isRequired = babelPresetEnv.isPluginRequired({}, {}); @@ -173,6 +195,18 @@ describe("babel-preset-env", () => { assert(babelPresetEnv.isPluginRequired(targets, plugin) === true); }); + it("returns true if uglify is specified as a target", () => { + const plugin = { + chrome: 50 + }; + const targets = { + chrome: 55, + uglify: true + }; + + assert(babelPresetEnv.isPluginRequired(targets, plugin) === true); + }); + it("doesn't throw when specifying a decimal for node", () => { const plugin = { node: 6