Use conditional exports in @babel/runtime for CJS/ESM (#12632)

This commit is contained in:
Nicolò Ribaudo
2021-02-21 17:41:10 +01:00
committed by GitHub
parent 143ee801e6
commit c10825ab05
60 changed files with 1559 additions and 623 deletions

View File

@@ -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;
`
);
},
},
},
};
}

View File

@@ -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,
});

View File

@@ -0,0 +1,7 @@
{
"plugins": [
["transform-runtime", { "version": "7.100.0" }],
"transform-classes",
"transform-modules-commonjs"
]
}

View File

@@ -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);
};

View File

@@ -0,0 +1,7 @@
{
"plugins": [
"transform-runtime",
"transform-classes",
"transform-modules-commonjs"
]
}

View File

@@ -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);
};

View File

@@ -0,0 +1,6 @@
{
"plugins": [
["transform-runtime", { "version": "7.100.0" }],
"transform-classes"
]
}

View File

@@ -0,0 +1,5 @@
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
let A = function A() {
_classCallCheck(this, A);
};

View File

@@ -0,0 +1,3 @@
{
"plugins": ["transform-runtime", "transform-classes"]
}

View File

@@ -0,0 +1,5 @@
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
let A = function A() {
_classCallCheck(this, A);
};

View File

@@ -0,0 +1,3 @@
{
"validateLogs": true
}

View File

@@ -0,0 +1,6 @@
{
"plugins": [
["transform-runtime", { "version": "7.100.0" }],
"transform-classes"
]
}

View File

@@ -0,0 +1,7 @@
var _classCallCheck = require("@babel/runtime/helpers/classCallCheck").default;
let A = function A() {
"use strict";
_classCallCheck(this, A);
};

View File

@@ -0,0 +1,3 @@
{
"plugins": ["transform-runtime", "transform-classes"]
}

View File

@@ -0,0 +1,7 @@
var _classCallCheck = require("@babel/runtime/helpers/classCallCheck");
let A = function A() {
"use strict";
_classCallCheck(this, A);
};

View File

@@ -0,0 +1,6 @@
{
"plugins": [
["transform-runtime", { "version": "7.100.0", "useESModules": true }],
"transform-classes"
]
}

View File

@@ -0,0 +1,5 @@
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
let A = function A() {
_classCallCheck(this, A);
};

View File

@@ -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.

View File

@@ -0,0 +1,6 @@
{
"plugins": [
["transform-runtime", { "useESModules": true }],
"transform-classes"
]
}

View File

@@ -0,0 +1,5 @@
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
let A = function A() {
_classCallCheck(this, A);
};

View File

@@ -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;

View File

@@ -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;

View File

@@ -1,4 +1,4 @@
var _createForOfIteratorHelper = require("@babel/runtime/helpers/createForOfIteratorHelper");
var _createForOfIteratorHelper = require("@babel/runtime/helpers/createForOfIteratorHelper").default;
var _iterator = _createForOfIteratorHelper(arr),
_step;