diff --git a/experimental/babel-preset-env/src/index.js b/experimental/babel-preset-env/src/index.js index 1025753f9d..a171f6d412 100644 --- a/experimental/babel-preset-env/src/index.js +++ b/experimental/babel-preset-env/src/index.js @@ -69,15 +69,6 @@ const logPlugin = (plugin, targets, list) => { console.log(logStr); }; -const filterItem = (targets, exclusions, list, item) => { - const isDefault = defaultWebIncludes.indexOf(item) >= 0; - const notExcluded = exclusions.indexOf(item) === -1; - - if (isDefault) return notExcluded; - const isRequired = isPluginRequired(targets, list[item]); - return isRequired && notExcluded; -}; - const getBuiltInTargets = targets => { const builtInTargets = Object.assign({}, targets); if (builtInTargets.uglify != null) { @@ -86,19 +77,48 @@ const getBuiltInTargets = targets => { return builtInTargets; }; -export const transformIncludesAndExcludes = opts => ({ - all: opts, - plugins: opts.filter(opt => !opt.match(/^(es\d+|web)\./)), - builtIns: opts.filter(opt => opt.match(/^(es\d+|web)\./)), -}); +export const transformIncludesAndExcludes = opts => { + return opts.reduce( + (result, opt) => { + const target = opt.match(/^(es\d+|web)\./) ? "builtIns" : "plugins"; + result[target].add(opt); + return result; + }, + { + all: opts, + plugins: new Set(), + builtIns: new Set(), + }, + ); +}; -function getPlatformSpecificDefaultFor(targets) { +const getPlatformSpecificDefaultFor = targets => { const targetNames = Object.keys(targets); const isAnyTarget = !targetNames.length; const isWebTarget = targetNames.some(name => name !== "node"); - return isAnyTarget || isWebTarget ? defaultWebIncludes : []; -} + return isAnyTarget || isWebTarget ? defaultWebIncludes : null; +}; + +const filterItems = (list, includes, excludes, targets, defaultItems) => { + const result = new Set(); + + for (const item in list) { + const excluded = excludes.has(item); + + if (!excluded && isPluginRequired(targets, list[item])) { + result.add(item); + } + } + + if (defaultItems) { + defaultItems.forEach(item => !excludes.has(item) && result.add(item)); + } + + includes.forEach(item => result.add(item)); + + return result; +}; export default function buildPreset(context, opts = {}) { const validatedOptions = normalizeOptions(opts); @@ -108,30 +128,26 @@ export default function buildPreset(context, opts = {}) { const include = transformIncludesAndExcludes(validatedOptions.include); const exclude = transformIncludesAndExcludes(validatedOptions.exclude); - const filterPlugins = filterItem.bind( - null, - targets, - exclude.plugins, + const transformations = filterItems( pluginList, + include.plugins, + exclude.plugins, + targets, ); - const transformations = Object.keys(pluginList) - .filter(filterPlugins) - .concat(include.plugins); let polyfills; let polyfillTargets; + if (useBuiltIns) { polyfillTargets = getBuiltInTargets(targets); - const filterBuiltIns = filterItem.bind( - null, - polyfillTargets, - exclude.builtIns, + + polyfills = filterItems( builtInsList, + include.builtIns, + exclude.builtIns, + polyfillTargets, + getPlatformSpecificDefaultFor(polyfillTargets), ); - polyfills = Object.keys(builtInsList) - .concat(getPlatformSpecificDefaultFor(polyfillTargets)) - .filter(filterBuiltIns) - .concat(include.builtIns); } if (debug && !hasBeenLogged) { @@ -146,20 +162,19 @@ export default function buildPreset(context, opts = {}) { }); } - const regenerator = transformations.indexOf("transform-regenerator") >= 0; - const modulePlugin = moduleType !== false && - moduleTransformations[moduleType]; const plugins = []; - modulePlugin && - plugins.push([require(`babel-plugin-${modulePlugin}`), { loose }]); - - plugins.push( - ...transformations.map(pluginName => [ - require(`babel-plugin-${pluginName}`), + if (moduleType !== false && moduleTransformations[moduleType]) { + plugins.push([ + require(`babel-plugin-${moduleTransformations[moduleType]}`), { loose }, - ]), - ); + ]); + } + + transformations.forEach(pluginName => + plugins.push([require(`babel-plugin-${pluginName}`), { loose }])); + + const regenerator = transformations.has("transform-regenerator"); if (debug) { console.log(""); @@ -171,7 +186,11 @@ export default function buildPreset(context, opts = {}) { if (useBuiltIns === "usage") { plugins.push([ addUsedBuiltInsPlugin, - { polyfills: new Set(polyfills), regenerator, debug }, + { + debug, + polyfills, + regenerator, + }, ]); } else if (useBuiltIns === "entry") { plugins.push([ diff --git a/experimental/babel-preset-env/src/normalize-options.js b/experimental/babel-preset-env/src/normalize-options.js index 6463e49d2f..56af88a092 100644 --- a/experimental/babel-preset-env/src/normalize-options.js +++ b/experimental/babel-preset-env/src/normalize-options.js @@ -4,12 +4,12 @@ import { defaultWebIncludes } from "./default-includes"; import moduleTransformations from "./module-transformations"; import pluginFeatures from "../data/plugin-features"; -const validIncludesAndExcludes = [ +const validIncludesAndExcludes = new Set([ ...Object.keys(pluginFeatures), ...Object.keys(moduleTransformations).map(m => moduleTransformations[m]), ...Object.keys(builtInsList), ...defaultWebIncludes, -]; +]); export const validateIncludesAndExcludes = (opts = [], type) => { invariant( @@ -17,12 +17,7 @@ export const validateIncludesAndExcludes = (opts = [], type) => { `Invalid Option: The '${type}' option must be an Array of plugins/built-ins`, ); - const unknownOpts = []; - opts.forEach(opt => { - if (validIncludesAndExcludes.indexOf(opt) === -1) { - unknownOpts.push(opt); - } - }); + const unknownOpts = opts.filter(opt => !validIncludesAndExcludes.has(opt)); invariant( unknownOpts.length === 0, diff --git a/experimental/babel-preset-env/src/use-built-ins-entry-plugin.js b/experimental/babel-preset-env/src/use-built-ins-entry-plugin.js index e3f5505fa0..ea98503a4b 100644 --- a/experimental/babel-preset-env/src/use-built-ins-entry-plugin.js +++ b/experimental/babel-preset-env/src/use-built-ins-entry-plugin.js @@ -38,18 +38,21 @@ export default function({ types: t }) { } function createImports(polyfills, requireType, regenerator) { - const imports = polyfills - .filter((el, i, arr) => arr.indexOf(el) === i) - .map(polyfill => createImport(polyfill, requireType, true)); + const items = Array.isArray(polyfills) ? new Set(polyfills) : polyfills; + const imports = []; - return [ - ...imports, - regenerator && + items.forEach(p => imports.push(createImport(p, requireType, true))); + + if (regenerator) { + imports.push( createImport( "babel-polyfill/lib/regenerator-runtime/runtime", requireType, ), - ].filter(Boolean); + ); + } + + return imports; } const isPolyfillImport = { @@ -88,7 +91,7 @@ export default function({ types: t }) { const { debug, onDebug, polyfills } = this.opts; if (debug) { - if (!polyfills.length) { + if (!polyfills.size) { console.log("Based on your targets, none were added."); return; } diff --git a/experimental/babel-preset-env/test/index.spec.js b/experimental/babel-preset-env/test/index.spec.js index d6bd903014..0fb2c335b2 100644 --- a/experimental/babel-preset-env/test/index.spec.js +++ b/experimental/babel-preset-env/test/index.spec.js @@ -123,8 +123,8 @@ describe("babel-preset-env", () => { ]), { all: ["transform-es2015-arrow-functions"], - plugins: ["transform-es2015-arrow-functions"], - builtIns: [], + plugins: new Set(["transform-es2015-arrow-functions"]), + builtIns: new Set(), }, ); }); @@ -134,8 +134,8 @@ describe("babel-preset-env", () => { babelPresetEnv.transformIncludesAndExcludes(["es6.map"]), { all: ["es6.map"], - plugins: [], - builtIns: ["es6.map"], + plugins: new Set(), + builtIns: new Set(["es6.map"]), }, ); });