Use conditional exports in @babel/runtime for CJS/ESM (#12632)
This commit is contained in:
@@ -112,24 +112,67 @@ function writeCorejsExports(pkgDirname, runtimeRoot, paths) {
|
||||
outputFile(pkgJsonPath, JSON.stringify(pkgJson, undefined, 2) + "\n");
|
||||
}
|
||||
|
||||
function writeHelpers(runtimeName, { corejs } = {}) {
|
||||
const helperPaths = writeHelperFiles(runtimeName, { corejs, esm: false });
|
||||
const helperESMPaths = writeHelperFiles(runtimeName, { corejs, esm: true });
|
||||
writeHelperExports(runtimeName, helperPaths.concat(helperESMPaths));
|
||||
function writeHelperFile(
|
||||
runtimeName,
|
||||
pkgDirname,
|
||||
helperPath,
|
||||
helperName,
|
||||
{ esm, corejs }
|
||||
) {
|
||||
const filePath = path.join(helperPath, esm ? "index.mjs" : "index.js");
|
||||
const fullPath = path.join(pkgDirname, filePath);
|
||||
|
||||
outputFile(
|
||||
fullPath,
|
||||
buildHelper(runtimeName, pkgDirname, fullPath, helperName, { esm, corejs })
|
||||
);
|
||||
|
||||
return `./${filePath}`;
|
||||
}
|
||||
|
||||
function writeHelperExports(runtimeName, helperPaths) {
|
||||
function writeHelperLegacyESMFile(pkgDirname, helperName) {
|
||||
const fullPath = path.join(pkgDirname, "helpers", "esm", `${helperName}.js`);
|
||||
|
||||
outputFile(fullPath, `export { default } from "../${helperName}/index.mjs"`);
|
||||
}
|
||||
|
||||
function writeHelpers(runtimeName, { corejs } = {}) {
|
||||
const pkgDirname = getRuntimeRoot(runtimeName);
|
||||
const helperSubExports = {};
|
||||
for (const helperPath of helperPaths) {
|
||||
helperSubExports[helperPath.replace(".js", "")] = helperPath;
|
||||
for (const helperName of helpers.list) {
|
||||
const helperPath = path.join("helpers", helperName);
|
||||
helperSubExports[`./${helperPath}`] = {
|
||||
module: writeHelperFile(runtimeName, pkgDirname, helperPath, helperName, {
|
||||
esm: true,
|
||||
corejs,
|
||||
}),
|
||||
node: writeHelperFile(runtimeName, pkgDirname, helperPath, helperName, {
|
||||
esm: false,
|
||||
corejs,
|
||||
}),
|
||||
get default() {
|
||||
return this.module;
|
||||
},
|
||||
};
|
||||
writeHelperLegacyESMFile(pkgDirname, helperName);
|
||||
}
|
||||
|
||||
writeHelperExports(runtimeName, helperSubExports);
|
||||
}
|
||||
|
||||
function writeHelperExports(runtimeName, helperSubExports) {
|
||||
const exports = {
|
||||
"./helpers/": "./helpers/",
|
||||
...helperSubExports,
|
||||
"./package": "./package.json",
|
||||
"./package.json": "./package.json",
|
||||
"./regenerator": "./regenerator/index.js",
|
||||
"./regenerator/*.js": "./regenerator/*.js",
|
||||
"./helpers/esm/*": "./helpers/esm/*.js",
|
||||
// These patterns are deprecated, but since patterns
|
||||
// containing * are not supported in every Node.js
|
||||
// version we keep them for better compatibility.
|
||||
"./regenerator/": "./regenerator/",
|
||||
"./helpers/esm/": "./helpers/esm/",
|
||||
};
|
||||
const pkgDirname = getRuntimeRoot(runtimeName);
|
||||
const pkgJsonPath = require.resolve(`${pkgDirname}/package.json`);
|
||||
@@ -137,26 +180,6 @@ function writeHelperExports(runtimeName, helperPaths) {
|
||||
pkgJson.exports = exports;
|
||||
outputFile(pkgJsonPath, JSON.stringify(pkgJson, undefined, 2) + "\n");
|
||||
}
|
||||
function writeHelperFiles(runtimeName, { esm, corejs }) {
|
||||
const pkgDirname = getRuntimeRoot(runtimeName);
|
||||
const helperPaths = [];
|
||||
for (const helperName of helpers.list) {
|
||||
const helperPath =
|
||||
"./" + path.join("helpers", esm ? "esm" : "", `${helperName}.js`);
|
||||
const helperFilename = path.join(pkgDirname, helperPath);
|
||||
outputFile(
|
||||
helperFilename,
|
||||
buildHelper(runtimeName, pkgDirname, helperFilename, helperName, {
|
||||
esm,
|
||||
corejs,
|
||||
})
|
||||
);
|
||||
|
||||
helperPaths.push(helperPath);
|
||||
}
|
||||
|
||||
return helperPaths;
|
||||
}
|
||||
|
||||
function getRuntimeRoot(runtimeName) {
|
||||
return path.resolve(
|
||||
@@ -184,7 +207,7 @@ function buildHelper(
|
||||
for (const dep of helpers.getDependencies(helperName)) {
|
||||
const id = (dependencies[dep] = t.identifier(t.toIdentifier(dep)));
|
||||
tree.body.push(template.statement.ast`
|
||||
var ${id} = require("${`./${dep}`}");
|
||||
var ${id} = require("${dep}");
|
||||
`);
|
||||
bindings.push(id.name);
|
||||
}
|
||||
@@ -211,8 +234,9 @@ function buildHelper(
|
||||
transformRuntime,
|
||||
{ corejs, useESModules: esm, version: runtimeVersion },
|
||||
],
|
||||
buildRuntimeRewritePlugin(runtimeName, helperName, esm),
|
||||
],
|
||||
buildRuntimeRewritePlugin(runtimeName, helperName),
|
||||
esm ? null : addDefaultCJSExport,
|
||||
].filter(Boolean),
|
||||
overrides: [
|
||||
{
|
||||
exclude: /typeof/,
|
||||
@@ -222,8 +246,7 @@ function buildHelper(
|
||||
}).code;
|
||||
}
|
||||
|
||||
function buildRuntimeRewritePlugin(runtimeName, helperName, esm) {
|
||||
const helperPath = esm ? "helpers/esm" : "helpers";
|
||||
function buildRuntimeRewritePlugin(runtimeName, helperName) {
|
||||
/**
|
||||
* rewrite helpers imports to runtime imports
|
||||
* @example
|
||||
@@ -233,7 +256,7 @@ function buildRuntimeRewritePlugin(runtimeName, helperName, esm) {
|
||||
*/
|
||||
function adjustImportPath(node) {
|
||||
if (helpers.list.includes(node.value)) {
|
||||
node.value = `${runtimeName}/${helperPath}/${node.value}`;
|
||||
node.value = `${runtimeName}/helpers/${node.value}`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,3 +289,21 @@ function buildRuntimeRewritePlugin(runtimeName, helperName, esm) {
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function addDefaultCJSExport({ template }) {
|
||||
return {
|
||||
visitor: {
|
||||
Program: {
|
||||
exit(path) {
|
||||
path.pushContainer(
|
||||
"body",
|
||||
template.statements.ast`
|
||||
module.exports.default = module.exports;
|
||||
module.exports.__esModule = true;
|
||||
`
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { types as t } from "@babel/core";
|
||||
|
||||
import getCoreJS2Definitions from "./runtime-corejs2-definitions";
|
||||
import getCoreJS3Definitions from "./runtime-corejs3-definitions";
|
||||
import { typeAnnotationToString } from "./helpers";
|
||||
import { typeAnnotationToString, hasMinVersion } from "./helpers";
|
||||
import getRuntimePath from "./get-runtime-path";
|
||||
|
||||
function supportsStaticESM(caller) {
|
||||
@@ -78,6 +78,20 @@ export default declare((api, options, dirname) => {
|
||||
throw new Error(`The 'version' option must be a version string.`);
|
||||
}
|
||||
|
||||
// In recent @babel/runtime versions, we can use require("helper").default
|
||||
// instead of require("helper") so that it has the same interface as the
|
||||
// ESM helper, and bundlers can better exchange one format for the other.
|
||||
// TODO(Babel 8): Remove this check, it's always true
|
||||
const DUAL_MODE_RUNTIME = "7.12.12";
|
||||
const supportsCJSDefault = hasMinVersion(DUAL_MODE_RUNTIME, runtimeVersion);
|
||||
if (supportsCJSDefault && useESModules && !absoluteRuntime) {
|
||||
console.warn(
|
||||
`[@babel/plugin-transform-runtime] The 'useESModules' option is not necessary when using` +
|
||||
` a @babel/runtime version >= ${DUAL_MODE_RUNTIME} and not using the 'absoluteRuntime'` +
|
||||
` option, because it automatically detects the necessary module format.`,
|
||||
);
|
||||
}
|
||||
|
||||
function has(obj, key) {
|
||||
return Object.prototype.hasOwnProperty.call(obj, key);
|
||||
}
|
||||
@@ -211,13 +225,19 @@ export default declare((api, options, dirname) => {
|
||||
`${modulePath}/${helpersDir}/${name}`,
|
||||
name,
|
||||
blockHoist,
|
||||
true,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
const cache = new Map();
|
||||
|
||||
this.addDefaultImport = (source, nameHint, blockHoist) => {
|
||||
this.addDefaultImport = (
|
||||
source,
|
||||
nameHint,
|
||||
blockHoist,
|
||||
isHelper = false,
|
||||
) => {
|
||||
// If something on the page adds a helper when the file is an ES6
|
||||
// file, we can't reused the cached helper name after things have been
|
||||
// transformed because it has almost certainly been renamed.
|
||||
@@ -229,7 +249,8 @@ export default declare((api, options, dirname) => {
|
||||
cached = t.cloneNode(cached);
|
||||
} else {
|
||||
cached = addDefault(file.path, source, {
|
||||
importedInterop: "uncompiled",
|
||||
importedInterop:
|
||||
isHelper && supportsCJSDefault ? "compiled" : "uncompiled",
|
||||
nameHint,
|
||||
blockHoist,
|
||||
});
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
class A {}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"plugins": [
|
||||
["transform-runtime", { "version": "7.100.0" }],
|
||||
"transform-classes",
|
||||
"transform-modules-commonjs"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
"use strict";
|
||||
|
||||
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
|
||||
|
||||
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
|
||||
|
||||
let A = function A() {
|
||||
(0, _classCallCheck2.default)(this, A);
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
class A {}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"plugins": [
|
||||
"transform-runtime",
|
||||
"transform-classes",
|
||||
"transform-modules-commonjs"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
"use strict";
|
||||
|
||||
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
||||
|
||||
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
|
||||
|
||||
let A = function A() {
|
||||
(0, _classCallCheck2.default)(this, A);
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
class A {}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"plugins": [
|
||||
["transform-runtime", { "version": "7.100.0" }],
|
||||
"transform-classes"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
|
||||
|
||||
let A = function A() {
|
||||
_classCallCheck(this, A);
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
class A {}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"plugins": ["transform-runtime", "transform-classes"]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
|
||||
|
||||
let A = function A() {
|
||||
_classCallCheck(this, A);
|
||||
};
|
||||
3
packages/babel-plugin-transform-runtime/test/fixtures/dual-babel-runtime/options.json
vendored
Normal file
3
packages/babel-plugin-transform-runtime/test/fixtures/dual-babel-runtime/options.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"validateLogs": true
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
class A {}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"plugins": [
|
||||
["transform-runtime", { "version": "7.100.0" }],
|
||||
"transform-classes"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
var _classCallCheck = require("@babel/runtime/helpers/classCallCheck").default;
|
||||
|
||||
let A = function A() {
|
||||
"use strict";
|
||||
|
||||
_classCallCheck(this, A);
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
class A {}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"plugins": ["transform-runtime", "transform-classes"]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
var _classCallCheck = require("@babel/runtime/helpers/classCallCheck");
|
||||
|
||||
let A = function A() {
|
||||
"use strict";
|
||||
|
||||
_classCallCheck(this, A);
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
class A {}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"plugins": [
|
||||
["transform-runtime", { "version": "7.100.0", "useESModules": true }],
|
||||
"transform-classes"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
|
||||
|
||||
let A = function A() {
|
||||
_classCallCheck(this, A);
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
[@babel/plugin-transform-runtime] The 'useESModules' option is not necessary when using a @babel/runtime version >= 7.12.12 and not using the 'absoluteRuntime' option, because it automatically detects the necessary module format.
|
||||
@@ -0,0 +1 @@
|
||||
class A {}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"plugins": [
|
||||
["transform-runtime", { "useESModules": true }],
|
||||
"transform-classes"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
|
||||
|
||||
let A = function A() {
|
||||
_classCallCheck(this, A);
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
var _createForOfIteratorHelper = require("@babel/runtime-corejs2/helpers/createForOfIteratorHelper");
|
||||
var _createForOfIteratorHelper = require("@babel/runtime-corejs2/helpers/createForOfIteratorHelper").default;
|
||||
|
||||
var _iterator = _createForOfIteratorHelper(arr),
|
||||
_step;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
var _createForOfIteratorHelper = require("@babel/runtime-corejs3/helpers/createForOfIteratorHelper");
|
||||
var _createForOfIteratorHelper = require("@babel/runtime-corejs3/helpers/createForOfIteratorHelper").default;
|
||||
|
||||
var _iterator = _createForOfIteratorHelper(arr),
|
||||
_step;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
var _createForOfIteratorHelper = require("@babel/runtime/helpers/createForOfIteratorHelper");
|
||||
var _createForOfIteratorHelper = require("@babel/runtime/helpers/createForOfIteratorHelper").default;
|
||||
|
||||
var _iterator = _createForOfIteratorHelper(arr),
|
||||
_step;
|
||||
|
||||
Reference in New Issue
Block a user