Don't compile import() in development (#12288)
This commit is contained in:
parent
94d116052f
commit
6a0e909c13
@ -14,12 +14,10 @@ module.exports = function (api) {
|
||||
const envOptsNoTargets = {
|
||||
loose: true,
|
||||
shippedProposals: true,
|
||||
modules: false,
|
||||
};
|
||||
const envOpts = Object.assign({}, envOptsNoTargets);
|
||||
|
||||
const compileDynamicImport =
|
||||
env === "test" || env === "development" || env === "test-legacy";
|
||||
|
||||
let convertESM = true;
|
||||
let ignoreLib = true;
|
||||
let includeRegeneratorRuntime = false;
|
||||
@ -115,9 +113,8 @@ module.exports = function (api) {
|
||||
"@babel/proposal-object-rest-spread",
|
||||
{ useBuiltIns: true, loose: true },
|
||||
],
|
||||
compileDynamicImport ? dynamicImportUrlToPath : null,
|
||||
compileDynamicImport ? "@babel/plugin-proposal-dynamic-import" : null,
|
||||
|
||||
convertESM ? "@babel/proposal-export-namespace-from" : null,
|
||||
convertESM ? "@babel/transform-modules-commonjs" : null,
|
||||
].filter(Boolean),
|
||||
overrides: [
|
||||
@ -163,45 +160,3 @@ module.exports = function (api) {
|
||||
|
||||
return config;
|
||||
};
|
||||
|
||||
// !!! WARNING !!! Hacks are coming
|
||||
|
||||
// import() uses file:// URLs for absolute imports, while require() uses
|
||||
// file paths.
|
||||
// Since this isn't handled by @babel/plugin-transform-modules-commonjs,
|
||||
// we must handle it here.
|
||||
// However, fileURLToPath is only supported starting from Node.js 10.
|
||||
// In older versions, we can remove the pathToFileURL call so that it keeps
|
||||
// the original absolute path.
|
||||
// NOTE: This plugin must run before @babel/plugin-transform-modules-commonjs,
|
||||
// and assumes that the target is the current node version.
|
||||
function dynamicImportUrlToPath({ template, env }) {
|
||||
const currentNodeSupportsURL =
|
||||
!!require("url").pathToFileURL && env() !== "test-legacy"; // test-legacy is run on legacy node versions without pathToFileURL support
|
||||
if (currentNodeSupportsURL) {
|
||||
return {
|
||||
visitor: {
|
||||
CallExpression(path) {
|
||||
if (path.get("callee").isImport()) {
|
||||
path.get("arguments.0").replaceWith(
|
||||
template.expression.ast`
|
||||
require("url").fileURLToPath(${path.node.arguments[0]})
|
||||
`
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
} else {
|
||||
// TODO: Remove in Babel 8 (it's not needed when using Node 10)
|
||||
return {
|
||||
visitor: {
|
||||
CallExpression(path) {
|
||||
if (path.get("callee").isIdentifier({ name: "pathToFileURL" })) {
|
||||
path.replaceWith(path.get("arguments.0"));
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import path from "path";
|
||||
import { pathToFileURL } from "url";
|
||||
import escope from "eslint-scope";
|
||||
import unpad from "dedent";
|
||||
import { parseForESLint } from "../src";
|
||||
@ -80,7 +79,7 @@ describe("Babel and Espree", () => {
|
||||
paths: [path.dirname(require.resolve("eslint"))],
|
||||
});
|
||||
|
||||
espree = await import(pathToFileURL(espreePath));
|
||||
espree = require(espreePath);
|
||||
});
|
||||
|
||||
describe("compatibility", () => {
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
"@babel/eslint-parser": "workspace:*",
|
||||
"@babel/eslint-plugin-development": "workspace:*",
|
||||
"@babel/eslint-plugin-development-internal": "workspace:*",
|
||||
"@babel/plugin-proposal-dynamic-import": "^7.10.4",
|
||||
"@babel/plugin-proposal-export-namespace-from": "^7.12.1",
|
||||
"@babel/plugin-proposal-object-rest-spread": "^7.11.0",
|
||||
"@babel/plugin-transform-for-of": "^7.10.4",
|
||||
"@babel/plugin-transform-modules-commonjs": "^7.10.4",
|
||||
|
||||
@ -6,6 +6,28 @@ import util from "util";
|
||||
import escapeRegExp from "lodash/escapeRegExp";
|
||||
import * as babel from "../lib";
|
||||
|
||||
// "minNodeVersion": "10.0.0" <-- For Ctrl+F when dropping node 10
|
||||
const supportsESM = parseInt(process.versions.node) >= 12;
|
||||
|
||||
const isMJS = file => path.extname(file) === ".mjs";
|
||||
|
||||
const skipUnsupportedESM = (esm, name) => {
|
||||
if (esm && !supportsESM) {
|
||||
console.warn(
|
||||
`Skipping "${name}" because native ECMAScript modules are not supported.`,
|
||||
);
|
||||
return true;
|
||||
}
|
||||
// This can be removed when loadOptionsAsyncInSpawedProcess is removed.
|
||||
if (esm && process.platform === "win32") {
|
||||
console.warn(
|
||||
`Skipping "${name}" because the ESM runner cannot be spawned on Windows.`,
|
||||
);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// TODO: In Babel 8, we can directly uses fs.promises which is supported by
|
||||
// node 8+
|
||||
const pfs =
|
||||
@ -49,15 +71,19 @@ function loadOptions(opts) {
|
||||
return babel.loadOptions({ cwd: __dirname, ...opts });
|
||||
}
|
||||
|
||||
function loadOptionsAsync(opts) {
|
||||
return babel.loadOptionsAsync({ cwd: __dirname, ...opts });
|
||||
function loadOptionsAsync({ filename, cwd = __dirname }, mjs) {
|
||||
if (mjs) {
|
||||
// import() crashes with jest
|
||||
return loadOptionsAsyncInSpawedProcess({ filename, cwd });
|
||||
}
|
||||
|
||||
return babel.loadOptionsAsync({ filename, cwd });
|
||||
}
|
||||
|
||||
// !!!! hack is coming !!!!
|
||||
// Remove this function when https://github.com/nodejs/node/issues/35889 is resolved.
|
||||
// Jest supports dynamic import(), but Node.js segfaults when using it in our tests.
|
||||
async function loadOptionsAsyncInSpawedProcess({ filename, cwd }) {
|
||||
// !!!! hack is coming !!!!
|
||||
// todo(Babel 8): remove this section when https://github.com/facebook/jest/issues/9430 is resolved
|
||||
// We don't check process.versions.node here, it will fail if node does not support esm
|
||||
// please publish Babel on a modernized node :)
|
||||
const { stdout, stderr } = await util.promisify(cp.execFile)(
|
||||
require.resolve("./fixtures/babel-load-options-async.mjs"),
|
||||
// pass `cwd` as params as `process.cwd()` will normalize `cwd` on macOS
|
||||
@ -67,7 +93,10 @@ async function loadOptionsAsyncInSpawedProcess({ filename, cwd }) {
|
||||
env: process.env,
|
||||
},
|
||||
);
|
||||
if (stderr) {
|
||||
|
||||
const EXPERIMENTAL_WARNING = /\(node:\d+\) ExperimentalWarning: The ESM module loader is experimental\./;
|
||||
|
||||
if (stderr.replace(EXPERIMENTAL_WARNING, "").trim()) {
|
||||
throw new Error(
|
||||
"error is thrown in babel-load-options-async.mjs: stdout\n" +
|
||||
stdout +
|
||||
@ -88,10 +117,11 @@ function pairs(items) {
|
||||
return pairs;
|
||||
}
|
||||
|
||||
async function getTemp(name, fixtureFolder = "config-files-templates") {
|
||||
async function getTemp(name) {
|
||||
const cwd = await pfs.mkdtemp(os.tmpdir() + path.sep + name);
|
||||
const tmp = name => path.join(cwd, name);
|
||||
const config = name => pfs.copyFile(fixture(fixtureFolder, name), tmp(name));
|
||||
const config = name =>
|
||||
pfs.copyFile(fixture("config-files-templates", name), tmp(name));
|
||||
return { cwd, tmp, config };
|
||||
}
|
||||
|
||||
@ -1060,16 +1090,17 @@ describe("buildConfigChain", function () {
|
||||
);
|
||||
});
|
||||
|
||||
test.each(
|
||||
[
|
||||
"babel.config.json",
|
||||
"babel.config.js",
|
||||
"babel.config.cjs",
|
||||
// We can't transpile import() while publishing, and it isn't supported
|
||||
// by jest.
|
||||
process.env.IS_PUBLISH ? "" : "babel.config.mjs",
|
||||
].filter(Boolean),
|
||||
)("should load %s asynchronously", async name => {
|
||||
test.each([
|
||||
"babel.config.json",
|
||||
"babel.config.js",
|
||||
"babel.config.cjs",
|
||||
"babel.config.mjs",
|
||||
])("should load %s asynchronously", async name => {
|
||||
const esm = isMJS(name);
|
||||
if (skipUnsupportedESM(esm, `should load ${name} asynchronously`)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { cwd, tmp, config } = await getTemp(
|
||||
`babel-test-load-config-async-${name}`,
|
||||
);
|
||||
@ -1077,13 +1108,15 @@ describe("buildConfigChain", function () {
|
||||
|
||||
await config(name);
|
||||
|
||||
expect(await loadOptionsAsync({ filename, cwd })).toEqual({
|
||||
...getDefaults(),
|
||||
filename,
|
||||
cwd,
|
||||
root: cwd,
|
||||
comments: true,
|
||||
});
|
||||
await expect(loadOptionsAsync({ filename, cwd }, esm)).resolves.toEqual(
|
||||
{
|
||||
...getDefaults(),
|
||||
filename,
|
||||
cwd,
|
||||
root: cwd,
|
||||
comments: true,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
test.each(
|
||||
@ -1094,48 +1127,26 @@ describe("buildConfigChain", function () {
|
||||
"babel.config.mjs",
|
||||
]),
|
||||
)("should throw if both %s and %s are used", async (name1, name2) => {
|
||||
const { cwd, tmp, config } = await getTemp(
|
||||
`babel-test-dup-config-${name1}-${name2}`,
|
||||
);
|
||||
|
||||
// We can't transpile import() while publishing, and it isn't supported
|
||||
// by jest.
|
||||
const esm = isMJS(name1) || isMJS(name2);
|
||||
if (
|
||||
process.env.IS_PUBLISH &&
|
||||
(name1 === "babel.config.mjs" || name2 === "babel.config.mjs")
|
||||
skipUnsupportedESM(
|
||||
esm,
|
||||
`should throw if both ${name1} and ${name2} are used`,
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { cwd, tmp, config } = await getTemp(
|
||||
`babel-test-dup-config-${name1}-${name2}`,
|
||||
);
|
||||
|
||||
await Promise.all([config(name1), config(name2)]);
|
||||
|
||||
await expect(
|
||||
loadOptionsAsync({ filename: tmp("src.js"), cwd }),
|
||||
loadOptionsAsync({ filename: tmp("src.js"), cwd }, esm),
|
||||
).rejects.toThrow(/Multiple configuration files found/);
|
||||
});
|
||||
|
||||
if (process.env.IS_PUBLISH) {
|
||||
test.each(["babel.config.mjs", ".babelrc.mjs"])(
|
||||
"should load %s asynchronously",
|
||||
async name => {
|
||||
const { cwd, tmp, config } = await getTemp(
|
||||
`babel-test-load-config-async-prepublish-${name}`,
|
||||
"config-files-templates-prepublish",
|
||||
);
|
||||
const filename = tmp("src.js");
|
||||
await config(name);
|
||||
expect(
|
||||
await loadOptionsAsyncInSpawedProcess({ filename, cwd }),
|
||||
).toEqual({
|
||||
...getDefaults(),
|
||||
filename,
|
||||
cwd,
|
||||
root: cwd,
|
||||
comments: true,
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
describe("relative", () => {
|
||||
@ -1181,11 +1192,14 @@ describe("buildConfigChain", function () {
|
||||
".babelrc",
|
||||
".babelrc.js",
|
||||
".babelrc.cjs",
|
||||
// We can't transpile import() while publishing, and it isn't supported
|
||||
// by jest.
|
||||
process.env.IS_PUBLISH ? "" : "babel.config.mjs",
|
||||
".babelrc.mjs",
|
||||
].filter(Boolean),
|
||||
)("should load %s asynchronously", async name => {
|
||||
const esm = isMJS(name);
|
||||
if (skipUnsupportedESM(esm, `should load ${name} asynchronously`)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { cwd, tmp, config } = await getTemp(
|
||||
`babel-test-load-config-${name}`,
|
||||
);
|
||||
@ -1193,13 +1207,15 @@ describe("buildConfigChain", function () {
|
||||
|
||||
await config(name);
|
||||
|
||||
expect(await loadOptionsAsync({ filename, cwd })).toEqual({
|
||||
...getDefaults(),
|
||||
filename,
|
||||
cwd,
|
||||
root: cwd,
|
||||
comments: true,
|
||||
});
|
||||
await expect(loadOptionsAsync({ filename, cwd }, esm)).resolves.toEqual(
|
||||
{
|
||||
...getDefaults(),
|
||||
filename,
|
||||
cwd,
|
||||
root: cwd,
|
||||
comments: true,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it("should load .babelignore", () => {
|
||||
@ -1220,23 +1236,24 @@ describe("buildConfigChain", function () {
|
||||
".babelrc.json",
|
||||
]),
|
||||
)("should throw if both %s and %s are used", async (name1, name2) => {
|
||||
const { cwd, tmp, config } = await getTemp(
|
||||
`babel-test-dup-config-${name1}-${name2}`,
|
||||
);
|
||||
|
||||
// We can't transpile import() while publishing, and it isn't supported
|
||||
// by jest.
|
||||
const esm = isMJS(name1) || isMJS(name2);
|
||||
if (
|
||||
process.env.IS_PUBLISH &&
|
||||
(name1 === ".babelrc.mjs" || name2 === ".babelrc.mjs")
|
||||
skipUnsupportedESM(
|
||||
esm,
|
||||
`should throw if both ${name1} and ${name2} are used`,
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { cwd, tmp, config } = await getTemp(
|
||||
`babel-test-dup-config-${name1}-${name2}`,
|
||||
);
|
||||
|
||||
await Promise.all([config(name1), config(name2)]);
|
||||
|
||||
await expect(
|
||||
loadOptionsAsync({ filename: tmp("src.js"), cwd }),
|
||||
loadOptionsAsync({ filename: tmp("src.js"), cwd }, esm),
|
||||
).rejects.toThrow(/Multiple configuration files found/);
|
||||
});
|
||||
|
||||
@ -1260,17 +1277,23 @@ describe("buildConfigChain", function () {
|
||||
${".babelrc.cjs"} | ${"babelrc-cjs-error"} | ${/Babelrc threw an error/}
|
||||
${".babelrc.mjs"} | ${"babelrc-mjs-error"} | ${/Babelrc threw an error/}
|
||||
${"package.json"} | ${"pkg-error"} | ${/Error while parsing JSON - /}
|
||||
`("should show helpful errors for $config", async ({ dir, error }) => {
|
||||
const filename = fixture("config-files", dir, "src.js");
|
||||
`(
|
||||
"should show helpful errors for $config",
|
||||
async ({ config, dir, error }) => {
|
||||
const esm = isMJS(config);
|
||||
if (
|
||||
skipUnsupportedESM(esm, `should show helpful errors for ${config}`)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We can't transpile import() while publishing, and it isn't supported
|
||||
// by jest.
|
||||
if (process.env.IS_PUBLISH && dir === "babelrc-mjs-error") return;
|
||||
const filename = fixture("config-files", dir, "src.js");
|
||||
|
||||
await expect(
|
||||
loadOptionsAsync({ filename, cwd: path.dirname(filename) }),
|
||||
).rejects.toThrow(error);
|
||||
});
|
||||
await expect(
|
||||
loadOptionsAsync({ filename, cwd: path.dirname(filename) }, esm),
|
||||
).rejects.toThrow(error);
|
||||
},
|
||||
);
|
||||
|
||||
it("loadPartialConfig should return a list of files that were extended", () => {
|
||||
const filename = fixture("config-files", "babelrc-extended", "src.js");
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
export default {
|
||||
comments: true,
|
||||
};
|
||||
@ -1,3 +0,0 @@
|
||||
export default {
|
||||
comments: true,
|
||||
};
|
||||
@ -1,8 +1,3 @@
|
||||
// Until Jest supports native mjs, we must simulate it 🤷
|
||||
|
||||
module.exports = new Promise(resolve => resolve({
|
||||
default: {
|
||||
comments: true
|
||||
}
|
||||
}));
|
||||
module.exports.__esModule = true;
|
||||
export default {
|
||||
comments: true,
|
||||
};
|
||||
|
||||
@ -1,8 +1,3 @@
|
||||
// Until Jest supports native mjs, we must simulate it 🤷
|
||||
|
||||
module.exports = new Promise(resolve => resolve({
|
||||
default: {
|
||||
comments: true
|
||||
}
|
||||
}));
|
||||
module.exports.__esModule = true;
|
||||
export default {
|
||||
comments: true,
|
||||
};
|
||||
|
||||
@ -1,8 +1 @@
|
||||
// Until Jest supports native mjs, we must simulate it 🤷
|
||||
|
||||
module.exports = new Promise(resolve => resolve({
|
||||
default: function () {
|
||||
throw new Error("Babelrc threw an error");
|
||||
}
|
||||
}));
|
||||
module.exports.__esModule = true;
|
||||
throw new Error("Babelrc threw an error");
|
||||
|
||||
10
yarn.lock
10
yarn.lock
@ -1078,15 +1078,15 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@babel/plugin-proposal-export-namespace-from@npm:^7.12.0":
|
||||
version: 7.12.0
|
||||
resolution: "@babel/plugin-proposal-export-namespace-from@npm:7.12.0"
|
||||
"@babel/plugin-proposal-export-namespace-from@npm:^7.12.0, @babel/plugin-proposal-export-namespace-from@npm:^7.12.1":
|
||||
version: 7.12.1
|
||||
resolution: "@babel/plugin-proposal-export-namespace-from@npm:7.12.1"
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils": ^7.10.4
|
||||
"@babel/plugin-syntax-export-namespace-from": ^7.8.3
|
||||
peerDependencies:
|
||||
"@babel/core": ^7.0.0-0
|
||||
checksum: 371d59486a28445f51352b498d22c372de6b8ae59f44a0d62de626498f162372b596430bedbc869e1ea6c0397aa1cb33dc806e7872da6d67625316fb8a019023
|
||||
checksum: ae5317ca008cc9eb2890b1f238156fbb990e5030fd1b7f123a5d11d89f8617a867b11db129aeafe51ef3bb4dddc4059e8172ddf99e8cdc42cbfa2a45dce1a16b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -4814,7 +4814,7 @@ __metadata:
|
||||
"@babel/eslint-parser": "workspace:*"
|
||||
"@babel/eslint-plugin-development": "workspace:*"
|
||||
"@babel/eslint-plugin-development-internal": "workspace:*"
|
||||
"@babel/plugin-proposal-dynamic-import": ^7.10.4
|
||||
"@babel/plugin-proposal-export-namespace-from": ^7.12.1
|
||||
"@babel/plugin-proposal-object-rest-spread": ^7.11.0
|
||||
"@babel/plugin-transform-for-of": ^7.10.4
|
||||
"@babel/plugin-transform-modules-commonjs": ^7.10.4
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user