From aad13388c7ebd924680337a4198c3c6783ebbe41 Mon Sep 17 00:00:00 2001 From: Brian Ng Date: Wed, 26 Apr 2017 14:11:53 -0500 Subject: [PATCH] Add forceAllTransforms option and deprecate Uglify target (#264) --- experimental/babel-preset-env/README.md | 51 ++++++++++++++---- experimental/babel-preset-env/src/index.js | 36 ++++++++++--- .../babel-preset-env/src/normalize-options.js | 7 +++ .../babel-preset-env/src/targets-parser.js | 45 ++++++++-------- .../debug-fixtures/builtins-uglify/stdout.txt | 52 ++++++++++--------- .../force-all-transforms/options.json | 13 +++++ .../force-all-transforms/stdout.txt | 44 ++++++++++++++++ .../exclude-built-ins/expected.js | 0 .../actual.js | 0 .../expected.js | 0 .../options.json | 10 ++-- .../test/normalize-options.spec.js | 47 +++++++---------- 12 files changed, 209 insertions(+), 96 deletions(-) create mode 100644 experimental/babel-preset-env/test/debug-fixtures/force-all-transforms/options.json create mode 100644 experimental/babel-preset-env/test/debug-fixtures/force-all-transforms/stdout.txt create mode 100644 experimental/babel-preset-env/test/fixtures/preset-options/exclude-built-ins/expected.js rename experimental/babel-preset-env/test/fixtures/preset-options/{uglify => force-all-transforms}/actual.js (100%) rename experimental/babel-preset-env/test/fixtures/preset-options/{uglify => force-all-transforms}/expected.js (100%) rename experimental/babel-preset-env/test/fixtures/preset-options/{uglify => force-all-transforms}/options.json (56%) diff --git a/experimental/babel-preset-env/README.md b/experimental/babel-preset-env/README.md index 08c606cc7b..6e3e7e97f3 100644 --- a/experimental/babel-preset-env/README.md +++ b/experimental/babel-preset-env/README.md @@ -120,16 +120,6 @@ 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` - -UglifyJS does not currently support any ES6 syntax, so if you are using Uglify to minify your code, targeting later browsers may cause Uglify to throw syntax errors. - -To prevent these errors - specify the uglify option, which will enable all plugins and, as a result, fully compile your code to ES5. However, the `useBuiltIns` option will still work as before, and only include the polyfills that your target(s) need. - -> NOTE: Uglify has a work-in-progress "Harmony" branch to address the lack of ES6 support, but it is not yet stable. You can follow its progress in [UglifyJS2 issue #448](https://github.com/mishoo/UglifyJS2/issues/448). If you require an alternative minifier which _does_ support ES6 syntax, we recommend using [Babili](https://github.com/babel/babili). - ### `spec` `boolean`, defaults to `false`. @@ -259,6 +249,47 @@ import "babel-polyfill/core-js/modules/es7.string.pad-end"; Don't add polyfills automatically per file, or transform `import "babel-polyfill"` to individual polyfills. +### `forceAllTransforms` + +`boolean`, defaults to `false`. + +

+ Example + + With Babel 7's .babelrc.js support, you can force all transforms to be run if env is set to `production`. + + ```js + module.exports = { + presets: [ + ["env", { + targets: { + chrome: 59, + edge: 13, + firefox: 50, + }, + // for uglifyjs... + forceAllTransforms: process.env === "production" + }], + ], + }; + ``` +

+ + +> NOTE: `targets.uglify` is deprecated and will be removed in the next major in +favor of this. + +By default, this preset will run all the transforms needed for the targeted +environment(s). Enable this option if you want to force running _all_ +transforms, which is useful if the output will be run through UglifyJS or an +environment that only supports ES5. + +> NOTE: Uglify has a work-in-progress "Harmony" branch to address the lack of +ES6 support, but it is not yet stable. You can follow its progress in +[UglifyJS2 issue #448](https://github.com/mishoo/UglifyJS2/issues/448). If you +require an alternative minifier which _does_ support ES6 syntax, we recommend +using [Babili](https://github.com/babel/babili). + --- ## Examples diff --git a/experimental/babel-preset-env/src/index.js b/experimental/babel-preset-env/src/index.js index b48aa77704..5ee2049171 100644 --- a/experimental/babel-preset-env/src/index.js +++ b/experimental/babel-preset-env/src/index.js @@ -107,18 +107,42 @@ const filterItems = (list, includes, excludes, targets, defaultItems) => { }; export default function buildPreset(context, opts = {}) { - const validatedOptions = normalizeOptions(opts); - const { debug, loose, moduleType, spec, useBuiltIns } = validatedOptions; + const { + debug, + exclude: optionsExclude, + forceAllTransforms, + include: optionsInclude, + loose, + moduleType, + spec, + targets: optionsTargets, + useBuiltIns, + } = normalizeOptions(opts); - const targets = getTargets(validatedOptions.targets); - const include = transformIncludesAndExcludes(validatedOptions.include); - const exclude = transformIncludesAndExcludes(validatedOptions.exclude); + // TODO: remove this in next major + let hasUglifyTarget = false; + + if (optionsTargets && optionsTargets.uglify) { + hasUglifyTarget = true; + delete optionsTargets.uglify; + + console.log(""); + console.log("The uglify target has been deprecated. Set the top level"); + console.log("option `forceAllTransforms: true` instead."); + console.log(""); + } + + const targets = getTargets(optionsTargets); + const include = transformIncludesAndExcludes(optionsInclude); + const exclude = transformIncludesAndExcludes(optionsExclude); + + const transformTargets = forceAllTransforms || hasUglifyTarget ? {} : targets; const transformations = filterItems( pluginList, include.plugins, exclude.plugins, - targets, + transformTargets, ); let polyfills; diff --git a/experimental/babel-preset-env/src/normalize-options.js b/experimental/babel-preset-env/src/normalize-options.js index 8a409525cf..51d19e1e43 100644 --- a/experimental/babel-preset-env/src/normalize-options.js +++ b/experimental/babel-preset-env/src/normalize-options.js @@ -57,9 +57,13 @@ export const validateBoolOption = (name, value, defaultValue) => { export const validateLooseOption = looseOpt => validateBoolOption("loose", looseOpt, false); + export const validateSpecOption = specOpt => validateBoolOption("spec", specOpt, false); +export const validateForceAllTransformsOption = forceAllTransforms => + validateBoolOption("forceAllTransforms", forceAllTransforms, false); + export const validateModulesOption = (modulesOpt = "commonjs") => { invariant( modulesOpt === false || @@ -97,6 +101,9 @@ export default function normalizeOptions(opts) { return { debug: opts.debug, exclude: validateIncludesAndExcludes(opts.exclude, "exclude"), + forceAllTransforms: validateForceAllTransformsOption( + opts.forceAllTransforms, + ), include: validateIncludesAndExcludes(opts.include, "include"), loose: validateLooseOption(opts.loose), moduleType: validateModulesOption(opts.modules), diff --git a/experimental/babel-preset-env/src/targets-parser.js b/experimental/babel-preset-env/src/targets-parser.js index 504c8cc76b..637106f429 100644 --- a/experimental/babel-preset-env/src/targets-parser.js +++ b/experimental/babel-preset-env/src/targets-parser.js @@ -26,30 +26,27 @@ const semverMin = (first: ?string, second: string): string => { }; const getLowestVersions = browsers => { - return browsers.reduce( - (all, browser) => { - const [browserName, browserVersion] = browser.split(" "); - const normalizedBrowserName = browserNameMap[browserName]; - - if (!normalizedBrowserName) { - return all; - } - - try { - // Browser version can return as "10.0-10.2" - const splitVersion = browserVersion.split("-")[0]; - const parsedBrowserVersion = semverify(splitVersion); - - all[normalizedBrowserName] = semverMin( - all[normalizedBrowserName], - parsedBrowserVersion, - ); - } catch (e) {} + return browsers.reduce((all, browser) => { + const [browserName, browserVersion] = browser.split(" "); + const normalizedBrowserName = browserNameMap[browserName]; + if (!normalizedBrowserName) { return all; - }, - {}, - ); + } + + try { + // Browser version can return as "10.0-10.2" + const splitVersion = browserVersion.split("-")[0]; + const parsedBrowserVersion = semverify(splitVersion); + + all[normalizedBrowserName] = semverMin( + all[normalizedBrowserName], + parsedBrowserVersion, + ); + } catch (e) {} + + return all; + }, {}); }; const outputDecimalWarning = (decimalTargets: Array): void => { @@ -60,7 +57,8 @@ const outputDecimalWarning = (decimalTargets: Array): void => { console.log("Warning, the following targets are using a decimal version:"); console.log(""); decimalTargets.forEach(({ target, value }) => - console.log(` ${target}: ${value}`)); + console.log(` ${target}: ${value}`), + ); console.log(""); console.log( "We recommend using a string for minor/patch versions to avoid numbers like 6.10", @@ -81,6 +79,7 @@ const targetParserMap = { return [target, parsed]; }, + // TODO: Remove in next version. // Only valid value for Uglify is `true` uglify: (target, value) => [target, value === true], }; diff --git a/experimental/babel-preset-env/test/debug-fixtures/builtins-uglify/stdout.txt b/experimental/babel-preset-env/test/debug-fixtures/builtins-uglify/stdout.txt index 11a543c81c..010c944536 100644 --- a/experimental/babel-preset-env/test/debug-fixtures/builtins-uglify/stdout.txt +++ b/experimental/babel-preset-env/test/debug-fixtures/builtins-uglify/stdout.txt @@ -1,37 +1,39 @@ +The uglify target has been deprecated. Set the top level +option `forceAllTransforms: true` instead. + babel-preset-env: `DEBUG` option Using targets: { - "chrome": "55", - "uglify": true + "chrome": "55" } Modules transform: false Using plugins: - check-es2015-constants {"uglify":true} - 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} - transform-es2015-destructuring {"uglify":true} - transform-es2015-duplicate-keys {"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} + check-es2015-constants {} + transform-es2015-arrow-functions {} + transform-es2015-block-scoped-functions {} + transform-es2015-block-scoping {} + transform-es2015-classes {} + transform-es2015-computed-properties {} + transform-es2015-destructuring {} + transform-es2015-duplicate-keys {} + transform-es2015-for-of {} + transform-es2015-function-name {} + transform-es2015-literals {} + transform-es2015-object-super {} + transform-es2015-parameters {} + transform-es2015-shorthand-properties {} + transform-es2015-spread {} + transform-es2015-sticky-regex {} + transform-es2015-template-literals {} + transform-es2015-typeof-symbol {} + transform-es2015-unicode-regex {} + transform-regenerator {} + transform-exponentiation-operator {} + transform-async-to-generator {} + syntax-trailing-function-commas {"chrome":"55"} Polyfills ========= diff --git a/experimental/babel-preset-env/test/debug-fixtures/force-all-transforms/options.json b/experimental/babel-preset-env/test/debug-fixtures/force-all-transforms/options.json new file mode 100644 index 0000000000..f598e9a286 --- /dev/null +++ b/experimental/babel-preset-env/test/debug-fixtures/force-all-transforms/options.json @@ -0,0 +1,13 @@ +{ + "presets": [ + ["../../lib", { + "debug": true, + "modules": false, + "targets": { + "chrome": 55 + }, + "useBuiltIns": "entry", + "forceAllTransforms": true + }] + ] +} diff --git a/experimental/babel-preset-env/test/debug-fixtures/force-all-transforms/stdout.txt b/experimental/babel-preset-env/test/debug-fixtures/force-all-transforms/stdout.txt new file mode 100644 index 0000000000..df56474239 --- /dev/null +++ b/experimental/babel-preset-env/test/debug-fixtures/force-all-transforms/stdout.txt @@ -0,0 +1,44 @@ +babel-preset-env: `DEBUG` option + +Using targets: +{ + "chrome": "55" +} + +Modules transform: false + +Using plugins: + check-es2015-constants {} + transform-es2015-arrow-functions {} + transform-es2015-block-scoped-functions {} + transform-es2015-block-scoping {} + transform-es2015-classes {} + transform-es2015-computed-properties {} + transform-es2015-destructuring {} + transform-es2015-duplicate-keys {} + transform-es2015-for-of {} + transform-es2015-function-name {} + transform-es2015-literals {} + transform-es2015-object-super {} + transform-es2015-parameters {} + transform-es2015-shorthand-properties {} + transform-es2015-spread {} + transform-es2015-sticky-regex {} + transform-es2015-template-literals {} + transform-es2015-typeof-symbol {} + transform-es2015-unicode-regex {} + transform-regenerator {} + transform-exponentiation-operator {} + transform-async-to-generator {} + syntax-trailing-function-commas {"chrome":"55"} + +Polyfills +========= + +Replaced `babel-polyfill` with the following 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/experimental/babel-preset-env/test/fixtures/preset-options/exclude-built-ins/expected.js b/experimental/babel-preset-env/test/fixtures/preset-options/exclude-built-ins/expected.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/experimental/babel-preset-env/test/fixtures/preset-options/uglify/actual.js b/experimental/babel-preset-env/test/fixtures/preset-options/force-all-transforms/actual.js similarity index 100% rename from experimental/babel-preset-env/test/fixtures/preset-options/uglify/actual.js rename to experimental/babel-preset-env/test/fixtures/preset-options/force-all-transforms/actual.js diff --git a/experimental/babel-preset-env/test/fixtures/preset-options/uglify/expected.js b/experimental/babel-preset-env/test/fixtures/preset-options/force-all-transforms/expected.js similarity index 100% rename from experimental/babel-preset-env/test/fixtures/preset-options/uglify/expected.js rename to experimental/babel-preset-env/test/fixtures/preset-options/force-all-transforms/expected.js diff --git a/experimental/babel-preset-env/test/fixtures/preset-options/uglify/options.json b/experimental/babel-preset-env/test/fixtures/preset-options/force-all-transforms/options.json similarity index 56% rename from experimental/babel-preset-env/test/fixtures/preset-options/uglify/options.json rename to experimental/babel-preset-env/test/fixtures/preset-options/force-all-transforms/options.json index 63bd00a05c..3bb272b808 100644 --- a/experimental/babel-preset-env/test/fixtures/preset-options/uglify/options.json +++ b/experimental/babel-preset-env/test/fixtures/preset-options/force-all-transforms/options.json @@ -1,12 +1,12 @@ { "presets": [ ["../../../../lib", { - "targets": { - "chrome": 55, - "uglify": true - }, "modules": false, - "useBuiltIns": "entry" + "targets": { + "chrome": 55 + }, + "useBuiltIns": "entry", + "forceAllTransforms": true }] ] } diff --git a/experimental/babel-preset-env/test/normalize-options.spec.js b/experimental/babel-preset-env/test/normalize-options.spec.js index 4399a6488d..3e330d0e88 100644 --- a/experimental/babel-preset-env/test/normalize-options.spec.js +++ b/experimental/babel-preset-env/test/normalize-options.spec.js @@ -6,6 +6,7 @@ const assert = require("assert"); const { checkDuplicateIncludeExcludes, normalizePluginNames, + validateForceAllTransformsOption, validateIncludesAndExcludes, validateLooseOption, validateModulesOption, @@ -38,39 +39,31 @@ describe("normalize-options", () => { }); }); - describe("validateLooseOption", () => { - it("`undefined` option returns false", () => { - assert(validateLooseOption() === false); - }); + const testBoolOption = validator => { + describe(validator.name, () => { + it("`undefined` option returns false", () => { + assert(validator() === false); + }); - it("`false` option returns false", () => { - assert(validateLooseOption(false) === false); - }); + it("`false` option returns false", () => { + assert(validator(false) === false); + }); - it("`true` option returns true", () => { - assert(validateLooseOption(true) === true); - }); + it("`true` option returns true", () => { + assert(validator(true) === true); + }); - it("array option is invalid", () => { - assert.throws(() => { - validateLooseOption([]); + it("array option is invalid", () => { + assert.throws(() => { + validateLooseOption([]); + }); }); }); - }); + }; - describe("validateSpecOption", () => { - it("`undefined` option returns false", () => { - assert(validateSpecOption() === false); - }); - - it("`false` option returns false", () => { - assert(validateSpecOption(false) === false); - }); - - it("`true` option returns true", () => { - assert(validateSpecOption(true) === true); - }); - }); + testBoolOption(validateLooseOption); + testBoolOption(validateSpecOption); + testBoolOption(validateForceAllTransformsOption); describe("checkDuplicateIncludeExcludes", function() { it("should throw if duplicate names in both", function() {