diff --git a/packages/babel-plugin-transform-runtime/src/index.js b/packages/babel-plugin-transform-runtime/src/index.js index 98976b52af..c9737af8a4 100644 --- a/packages/babel-plugin-transform-runtime/src/index.js +++ b/packages/babel-plugin-transform-runtime/src/index.js @@ -16,13 +16,19 @@ export default function ({ types: t }) { const moduleName = getRuntimeModuleName(this.opts); if (this.opts.helpers !== false) { + const baseHelpersDir = this.opts.useBuiltIns ? "helpers/builtin" : "helpers"; + const helpersDir = this.opts.useESModules ? `${baseHelpersDir}/es6` : baseHelpersDir; file.set("helperGenerator", function (name) { if (HELPER_BLACKLIST.indexOf(name) < 0) { - return file.addImport(`${moduleName}/helpers/${name}`, "default", name); + return file.addImport(`${moduleName}/${helpersDir}/${name}`, "default", name); } }); } + if (this.opts.polyfill && this.opts.useBuiltIns) { + throw new Error("The polyfill option conflicts with useBuiltIns; use one or the other"); + } + this.setDynamic("regeneratorIdentifier", function () { return file.addImport(`${moduleName}/regenerator`, "default", "regeneratorRuntime"); }); @@ -37,7 +43,7 @@ export default function ({ types: t }) { return; } - if (state.opts.polyfill === false) return; + if (state.opts.polyfill === false || state.opts.useBuiltIns) return; if (t.isMemberExpression(parent)) return; if (!has(definitions.builtins, node.name)) return; @@ -54,7 +60,7 @@ export default function ({ types: t }) { // arr[Symbol.iterator]() -> _core.$for.getIterator(arr) CallExpression(path, state) { - if (state.opts.polyfill === false) return; + if (state.opts.polyfill === false || state.opts.useBuiltIns) return; // we can't compile this if (path.node.arguments.length) return; @@ -77,7 +83,7 @@ export default function ({ types: t }) { // Symbol.iterator in arr -> core.$for.isIterable(arr) BinaryExpression(path, state) { - if (state.opts.polyfill === false) return; + if (state.opts.polyfill === false || state.opts.useBuiltIns) return; if (path.node.operator !== "in") return; if (!path.get("left").matchesPattern("Symbol.iterator")) return; @@ -96,7 +102,7 @@ export default function ({ types: t }) { // Array.from -> _core.Array.from MemberExpression: { enter(path, state) { - if (state.opts.polyfill === false) return; + if (state.opts.polyfill === false || state.opts.useBuiltIns) return; if (!path.isReferenced()) return; const { node } = path; @@ -128,7 +134,7 @@ export default function ({ types: t }) { }, exit(path, state) { - if (state.opts.polyfill === false) return; + if (state.opts.polyfill === false || state.opts.useBuiltIns) return; if (!path.isReferenced()) return; const { node } = path; diff --git a/packages/babel-runtime/scripts/build-dist.js b/packages/babel-runtime/scripts/build-dist.js index 050aa73b21..f6775563b5 100644 --- a/packages/babel-runtime/scripts/build-dist.js +++ b/packages/babel-runtime/scripts/build-dist.js @@ -46,16 +46,23 @@ function writeFile(filename, content) { return writeRootFile(filename, content); } -var transformOpts = { - presets: [ - require("../../babel-preset-es2015") - ], +function makeTransformOpts(modules = "commonjs", useBuiltIns = false) { + const opts = { + presets: [ + [require("../../babel-preset-es2015"), { modules: false }] + ], - plugins: [ - require("../../babel-plugin-transform-runtime"), - [require("../../babel-plugin-transform-es2015-modules-commonjs"), { loose: true, strict: false }] - ] -}; + plugins: [ + [require("../../babel-plugin-transform-runtime"), { useBuiltIns: useBuiltIns, useESModules: modules === false }] + ] + } + if (modules === 'commonjs') { + opts.plugins.push([require("../../babel-plugin-transform-es2015-modules-commonjs"), { loose: true, strict: false }]) + } else if (modules !== false) { + throw new Error('Unsupported module type') + } + return opts +} function buildRuntimeRewritePlugin(relativePath, helperName) { return { @@ -63,12 +70,16 @@ function buildRuntimeRewritePlugin(relativePath, helperName) { var original = file.get("helperGenerator"); file.set("helperGenerator", function(name) { // make sure that helpers won't insert circular references to themselves - if (name === helperName) return; + if (name === helperName) return false; return original(name); }); }, visitor: { + ImportDeclaration: function(path){ + path.get("source").node.value = path.get("source").node.value + .replace(/^babel-runtime/, relativePath); + }, CallExpression: function(path){ if (!path.get("callee").isIdentifier({name: "require"}) || path.get("arguments").length !== 1 || @@ -82,23 +93,40 @@ function buildRuntimeRewritePlugin(relativePath, helperName) { }; } -function buildHelper(helperName) { +function buildHelper(helperName, modules = "commonjs", useBuiltIns = false) { + const helper = helpers.get(helperName) + // avoid an unneccessary TDZ in the easy case + if (helper.type === "FunctionExpression") { + helper.type = "FunctionDeclaration" + } var tree = t.program([ - t.exportDefaultDeclaration(helpers.get(helperName)) + t.exportDefaultDeclaration(helper) ]); + const transformOpts = makeTransformOpts(modules, useBuiltIns) + + const relative = useBuiltIns ? "../.." : ".." + return babel.transformFromAst(tree, null, { presets: transformOpts.presets, - plugins: transformOpts.plugins.concat([buildRuntimeRewritePlugin("..", helperName)]) + plugins: transformOpts.plugins.concat([buildRuntimeRewritePlugin(modules === false ? `../${relative}` : relative, helperName)]) }).code; } -helpers.list.forEach(function (helperName) { - writeFile("helpers/" + helperName + ".js", buildHelper(helperName)); +for (const modules of ["commonjs", false]) { + for (const builtin of [false, true]) { + const dirname = `helpers/${builtin ? 'builtin/' : ''}${!modules ? 'es6/' : ''}` - // compat - var helperAlias = kebabCase(helperName); - var content = "module.exports = require(\"./" + helperName + ".js\");"; - writeFile("helpers/_" + helperAlias + ".js", content); - if (helperAlias !== helperName) writeFile("helpers/" + helperAlias + ".js", content); -}); + for (const helperName of helpers.list) { + writeFile(`${dirname}${helperName}.js`, buildHelper(helperName, modules, builtin)); + + // compat + var helperAlias = kebabCase(helperName); + var content = !modules + ? `export { default } from \"./${helperName}.js\";` + : "module.exports = require(\"./" + helperName + ".js\");"; + writeFile(`${dirname}_${helperAlias}.js`, content); + if (helperAlias !== helperName) writeFile(`${dirname}${helperAlias}.js`, content); + } + } +}