Pass URLs to import() rather than paths (#11193)

* Pass URLs to import() rather than paths

* Make tests pass

* (╯°□°)╯︵ ┻━┻

* (╯°□°)╯︵ ┻━┻           (╯°□°)╯︵ ┻━┻             (╯°□°)╯︵ ┻━┻
This commit is contained in:
Nicolò Ribaudo 2020-03-03 19:54:01 +01:00 committed by GitHub
parent 2603c2e227
commit 114f6726a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 54 additions and 6 deletions

View File

@ -12,6 +12,8 @@ module.exports = function(api) {
};
const envOpts = Object.assign({}, envOptsNoTargets);
const compileDynamicImport = env === "test" || env === "development";
let convertESM = true;
let ignoreLib = true;
let includeRegeneratorRuntime = false;
@ -106,11 +108,10 @@ module.exports = function(api) {
["@babel/plugin-proposal-optional-chaining", { loose: true }],
["@babel/plugin-proposal-nullish-coalescing-operator", { loose: true }],
compileDynamicImport ? dynamicImportUrlToPath : null,
compileDynamicImport ? "@babel/plugin-proposal-dynamic-import" : null,
convertESM ? "@babel/transform-modules-commonjs" : null,
// Until Jest supports native mjs, we must simulate it 🤷
env === "test" || env === "development"
? "@babel/plugin-proposal-dynamic-import"
: null,
].filter(Boolean),
overrides: [
{
@ -152,3 +153,45 @@ 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 }) {
const currentNodeSupportsURL = !!require("url").pathToFileURL;
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"));
}
},
},
};
}
}

View File

@ -1,4 +1,5 @@
import path from "path";
import { pathToFileURL } from "url";
import escope from "eslint-scope";
import unpad from "dedent";
import { parseForESLint } from "../src";
@ -71,7 +72,8 @@ describe("Babel and Espree", () => {
const espreePath = require.resolve("espree", {
paths: [path.dirname(require.resolve("eslint"))],
});
espree = await import(espreePath);
espree = await import(pathToFileURL(espreePath));
});
describe("compatibility", () => {

View File

@ -1,6 +1,7 @@
import { isAsync, waitFor } from "../../gensync-utils/async";
import type { Handler } from "gensync";
import path from "path";
import { pathToFileURL } from "url";
let import_;
try {
@ -55,6 +56,8 @@ async function loadMjsDefault(filepath: string) {
);
}
const module = await import_(filepath);
// import() expects URLs, not file paths.
// https://github.com/nodejs/node/issues/31710
const module = await import_(pathToFileURL(filepath));
return module.default;
}