Skip to content

Commit

Permalink
Pass URLs to import() rather than paths (#11193)
Browse files Browse the repository at this point in the history
* Pass URLs to import() rather than paths

* Make tests pass

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

* (╯°□°)╯︵ ┻━┻           (╯°□°)╯︵ ┻━┻             (╯°□°)╯︵ ┻━┻
  • Loading branch information
nicolo-ribaudo committed Mar 3, 2020
1 parent 2603c2e commit 114f672
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 6 deletions.
51 changes: 47 additions & 4 deletions babel.config.js
Expand Up @@ -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;
Expand Down Expand Up @@ -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: [
{
Expand Down Expand Up @@ -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"));
}
},
},
};
}
}
4 changes: 3 additions & 1 deletion eslint/babel-eslint-parser/test/index.js
@@ -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";
Expand Down Expand Up @@ -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", () => {
Expand Down
5 changes: 4 additions & 1 deletion packages/babel-core/src/config/files/module-types.js
@@ -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 {
Expand Down Expand Up @@ -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;
}

0 comments on commit 114f672

Please sign in to comment.