diff --git a/babel.config.js b/babel.config.js index 890f6c9a6e23..dc0216cda0f0 100644 --- a/babel.config.js +++ b/babel.config.js @@ -220,6 +220,15 @@ module.exports = function (api) { ], ], }, + convertESM && { + test: ["./packages/babel-core/src"].map(normalize), + plugins: [ + [ + pluginInjectNodeReexportsHints, + { names: ["types", "tokTypes", "traverse", "template"] }, + ], + ], + }, convertESM && { test: sources.map(normalize), exclude: lazyRequireSources.map(normalize), @@ -730,3 +739,43 @@ function pluginDynamicESLintVersionCheck({ template }) { }, }; } + +// Inject `0 && exports.foo = 0` hints for the specified exports, +// to help the Node.js CJS-ESM interop. This is only +// needed when compiling ESM re-exports to CJS in `lazy` mode. +function pluginInjectNodeReexportsHints({ types: t, template }, { names }) { + return { + visitor: { + Program: { + exit(path) { + const seen = []; + for (const stmt of path.get("body")) { + if (!stmt.isExpressionStatement()) continue; + const expr = stmt.get("expression"); + if ( + !expr.isCallExpression() || + !expr.get("callee").matchesPattern("Object.defineProperty") || + expr.node.arguments.length !== 3 || + !expr.get("arguments.0").isIdentifier({ name: "exports" }) || + !expr.get("arguments.1").isStringLiteral() || + !names.includes(expr.node.arguments[1].value) + ) { + continue; + } + + expr + .get("arguments.0") + .replaceWith(template.expression.ast`(0, exports)`); + seen.push(expr.node.arguments[1].value); + } + + const assign = seen.reduce( + (rhs, name) => template.expression.ast`exports.${name} = ${rhs}`, + t.numericLiteral(0) + ); + path.pushContainer("body", template.statement.ast`0 && (${assign})`); + }, + }, + }, + }; +} diff --git a/packages/babel-core/src/index.ts b/packages/babel-core/src/index.ts index 676662749ec5..3a05f67240ce 100644 --- a/packages/babel-core/src/index.ts +++ b/packages/babel-core/src/index.ts @@ -8,9 +8,11 @@ export { resolvePlugin, resolvePreset } from "./config/files"; export { getEnv } from "./config/helpers/environment"; +// NOTE: Lazy re-exports aren't detected by the Node.js CJS-ESM interop. +// These are handled by pluginInjectNodeReexportsHints in our babel.config.js +// so that they can work well. export * as types from "@babel/types"; export { tokTypes } from "@babel/parser"; - export { default as traverse } from "@babel/traverse"; export { default as template } from "@babel/template"; diff --git a/packages/babel-core/test/api.js b/packages/babel-core/test/api.js index 39ec12d2740e..6220f79258ac 100644 --- a/packages/babel-core/test/api.js +++ b/packages/babel-core/test/api.js @@ -1,4 +1,4 @@ -import babel from "../lib/index.js"; +import * as babel from "../lib/index.js"; import { TraceMap, originalPositionFor } from "@jridgewell/trace-mapping"; import path from "path"; import generator from "@babel/generator"; diff --git a/packages/babel-core/test/config-chain.js b/packages/babel-core/test/config-chain.js index 93872311b47d..fad83c08ad0b 100644 --- a/packages/babel-core/test/config-chain.js +++ b/packages/babel-core/test/config-chain.js @@ -2,7 +2,7 @@ import fs from "fs"; import os from "os"; import path from "path"; import { fileURLToPath } from "url"; -import babel from "../lib/index.js"; +import * as babel from "../lib/index.js"; import rimraf from "rimraf"; import _getTargets from "@babel/helper-compilation-targets"; diff --git a/packages/babel-core/test/fixtures/babel-compile-async.mjs b/packages/babel-core/test/fixtures/babel-compile-async.mjs index 4f67829a74d0..2fc84903a22b 100755 --- a/packages/babel-core/test/fixtures/babel-compile-async.mjs +++ b/packages/babel-core/test/fixtures/babel-compile-async.mjs @@ -2,10 +2,8 @@ // Usage: // babel-compile-async.js [filename] -import babel from "../../lib/index.js"; +import { transformAsync } from "../../lib/index.js"; (async () => { - process.stdout.write( - JSON.stringify(await babel.transformAsync("")) - ); + process.stdout.write(JSON.stringify(await transformAsync(""))); })(); diff --git a/packages/babel-core/test/fixtures/babel-compile-sync.mjs b/packages/babel-core/test/fixtures/babel-compile-sync.mjs index dd4152602f39..278aae3f46c3 100755 --- a/packages/babel-core/test/fixtures/babel-compile-sync.mjs +++ b/packages/babel-core/test/fixtures/babel-compile-sync.mjs @@ -2,8 +2,6 @@ // Usage: // babel-compile-async.js [filename] -import babel from "../../lib/index.js"; +import { transformSync } from "../../lib/index.js"; -process.stdout.write( - JSON.stringify(babel.transformSync("")) -); +process.stdout.write(JSON.stringify(transformSync(""))); diff --git a/packages/babel-core/test/fixtures/babel-load-options-async.mjs b/packages/babel-core/test/fixtures/babel-load-options-async.mjs index a932456329ae..311a0f9ac20d 100755 --- a/packages/babel-core/test/fixtures/babel-load-options-async.mjs +++ b/packages/babel-core/test/fixtures/babel-load-options-async.mjs @@ -2,12 +2,12 @@ // Usage: // babel-load-options-async.js [filename] -import babel from "../../lib/index.js"; +import { loadOptionsAsync } from "../../lib/index.js"; const [, , filename, cwd] = process.argv; (async () => { process.stdout.write( - JSON.stringify(await babel.loadOptionsAsync({ filename, cwd })) + JSON.stringify(await loadOptionsAsync({ filename, cwd })) ); })(); diff --git a/packages/babel-helper-check-duplicate-nodes/test/index.js b/packages/babel-helper-check-duplicate-nodes/test/index.js index 9f3158a8ebee..0e6117d80bb7 100644 --- a/packages/babel-helper-check-duplicate-nodes/test/index.js +++ b/packages/babel-helper-check-duplicate-nodes/test/index.js @@ -1,6 +1,5 @@ import _checkDuplicateNodes from "../lib/index.js"; -import babel from "@babel/core"; -const { parseSync, traverse, types: t } = babel; +import { parseSync, traverse, types as t } from "@babel/core"; const checkDuplicateNodes = _checkDuplicateNodes.default; describe("checkDuplicateNodes", () => { @@ -53,7 +52,7 @@ describe("checkDuplicateNodes", () => { }); it("should throw when more than one arguments are passed", () => { expect(() => { - checkDuplicateNodes(babel, {}); + checkDuplicateNodes({}, {}); }).toThrow("checkDuplicateNodes accepts only one argument: ast"); }); }); diff --git a/packages/babel-plugin-bugfix-safari-id-destructuring-collision-in-function-expression/test/util.skip-bundled.js b/packages/babel-plugin-bugfix-safari-id-destructuring-collision-in-function-expression/test/util.skip-bundled.js index 9ac730f74a06..db8eb52d0f8a 100644 --- a/packages/babel-plugin-bugfix-safari-id-destructuring-collision-in-function-expression/test/util.skip-bundled.js +++ b/packages/babel-plugin-bugfix-safari-id-destructuring-collision-in-function-expression/test/util.skip-bundled.js @@ -1,6 +1,5 @@ import { shouldTransform } from "../lib/util.js"; -import babel from "@babel/core"; -const { parseSync, traverse } = babel; +import { parseSync, traverse } from "@babel/core"; function getPath(input, parserOpts = {}) { let targetPath; diff --git a/packages/babel-plugin-bugfix-v8-spread-parameters-in-optional-chaining/test/util.skip-bundled.js b/packages/babel-plugin-bugfix-v8-spread-parameters-in-optional-chaining/test/util.skip-bundled.js index a1241cbf1f4b..d23528ba18b1 100644 --- a/packages/babel-plugin-bugfix-v8-spread-parameters-in-optional-chaining/test/util.skip-bundled.js +++ b/packages/babel-plugin-bugfix-v8-spread-parameters-in-optional-chaining/test/util.skip-bundled.js @@ -1,6 +1,5 @@ import { shouldTransform } from "../lib/util.js"; -import babel from "@babel/core"; -const { parseSync, traverse } = babel; +import { parseSync, traverse } from "@babel/core"; function getPath(input, parserOpts = {}) { let targetPath; diff --git a/packages/babel-plugin-proposal-destructuring-private/test/plugin-ordering.js b/packages/babel-plugin-proposal-destructuring-private/test/plugin-ordering.js index 64ace639375e..9879497c8ee9 100644 --- a/packages/babel-plugin-proposal-destructuring-private/test/plugin-ordering.js +++ b/packages/babel-plugin-proposal-destructuring-private/test/plugin-ordering.js @@ -1,4 +1,4 @@ -import babel from "@babel/core"; +import { transformSync } from "@babel/core"; import proposalDestructuringPrivate from "../lib/index.js"; describe("plugin ordering", () => { @@ -12,7 +12,7 @@ describe("plugin ordering", () => { `; expect( () => - babel.transformSync(source, { + transformSync(source, { filename: "example.js", highlightCode: false, configFile: false, diff --git a/packages/babel-plugin-proposal-destructuring-private/test/util.skip-bundled.js b/packages/babel-plugin-proposal-destructuring-private/test/util.skip-bundled.js index 5e50a88acb64..3c2d6e11d9df 100644 --- a/packages/babel-plugin-proposal-destructuring-private/test/util.skip-bundled.js +++ b/packages/babel-plugin-proposal-destructuring-private/test/util.skip-bundled.js @@ -1,8 +1,5 @@ -import babel from "@babel/core"; +import { parseSync, traverse, types as t } from "@babel/core"; import { traversePattern, privateKeyPathIterator } from "../lib/util.js"; -const { isObjectProperty, isPrivateName } = babel.types; - -const { parseSync, traverse } = babel; function wrapSourceInClassEnvironment(input) { const usedPrivateNames = new Set(); @@ -44,9 +41,9 @@ describe("traversePattern", () => { ); const keys = [ ...traversePattern(patternPath.node, function* (node) { - if (isObjectProperty(node)) { + if (t.isObjectProperty(node)) { const propertyKey = node.key; - if (isPrivateName(propertyKey)) { + if (t.isPrivateName(propertyKey)) { yield propertyKey.id.name; } } diff --git a/packages/babel-plugin-proposal-optional-chaining/test/util.skip-bundled.js b/packages/babel-plugin-proposal-optional-chaining/test/util.skip-bundled.js index 4fb30bcfbd0d..ee3289dcc530 100644 --- a/packages/babel-plugin-proposal-optional-chaining/test/util.skip-bundled.js +++ b/packages/babel-plugin-proposal-optional-chaining/test/util.skip-bundled.js @@ -1,6 +1,5 @@ import { willPathCastToBoolean } from "../lib/util.js"; -import babel from "@babel/core"; -const { parseSync, traverse } = babel; +import { parseSync, traverse } from "@babel/core"; function getPath(input, parserOpts) { let targetPath; diff --git a/packages/babel-plugin-transform-runtime/scripts/build-dist.js b/packages/babel-plugin-transform-runtime/scripts/build-dist.js index 61570a0ab7ff..1668717dd188 100644 --- a/packages/babel-plugin-transform-runtime/scripts/build-dist.js +++ b/packages/babel-plugin-transform-runtime/scripts/build-dist.js @@ -2,7 +2,7 @@ import path from "path"; import fs from "fs"; import { createRequire } from "module"; import helpers from "@babel/helpers"; -import babel from "@babel/core"; +import { transformFromAstSync, File } from "@babel/core"; import template from "@babel/template"; import t from "@babel/types"; import { fileURLToPath } from "url"; @@ -217,7 +217,7 @@ function buildHelper( if (!esm) { bindings = []; - helpers.ensure(helperName, babel.File); + helpers.ensure(helperName, File); for (const dep of helpers.getDependencies(helperName)) { const id = (dependencies[dep] = t.identifier(t.toIdentifier(dep))); tree.body.push(template.statement.ast` @@ -235,7 +235,7 @@ function buildHelper( ); tree.body.push(...helper.nodes); - return babel.transformFromAstSync(tree, null, { + return transformFromAstSync(tree, null, { filename: helperFilename, presets: [["@babel/preset-env", { modules: false }]], plugins: [