Merge pull request #7588 from loganfsmyth/register-cycle-fixes

Have @babel/core lazy-load all dependencies and make @babel/register not explode because of that
This commit is contained in:
Logan Smyth 2018-03-25 15:24:00 -07:00 committed by GitHub
commit a10c91790f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 73 additions and 21 deletions

View File

@ -46,7 +46,9 @@ module.exports = function(api) {
"@babel/proposal-export-namespace-from",
"@babel/proposal-numeric-separator",
["@babel/proposal-object-rest-spread", { useBuiltIns: true }],
convertESM ? "@babel/transform-modules-commonjs" : null,
// Explicitly use the lazy version of CommonJS modules.
convertESM ? ["@babel/transform-modules-commonjs", { lazy: true }] : null,
].filter(Boolean),
overrides: [
{
@ -56,6 +58,15 @@ module.exports = function(api) {
["@babel/transform-for-of", { assumeArray: true }],
],
},
{
test: "./packages/babel-register",
plugins: [
// Override the root options to disable lazy imports for babel-register
// because otherwise the require hook will try to lazy-import things
// leading to dependency cycles.
convertESM ? "@babel/transform-modules-commonjs" : null,
].filter(Boolean),
},
],
};

View File

@ -64,7 +64,7 @@ const assertTest = function(stdout, stderr, opts) {
chai.expect(stderr).to.equal(expectStderr, "stderr didn't match");
}
} else if (stderr) {
throw new Error("stderr:\n" + stderr);
throw new Error("stderr:\n" + stderr + "\n\nstdout:\n" + stdout);
}
const expectStdout = opts.stdout.trim();

View File

@ -100,3 +100,34 @@ Disable the cache.
```sh
BABEL_DISABLE_CACHE=1 babel-node script.js
```
## Compiling plugins and presets on the fly
`@babel/register` uses Node's `require()` hook system to compile files
on the fly when they are loaded. While this is quite helpful overall, it means
that there can be confusing cases where code within a `require()` hook causes
_more_ calls to `require`, causing a dependency cycle. In Babel's case for
instance, this could mean that in the process of Babel trying to compile a
user's file, Babel could end up trying to compile itself _as it is loading_.
To avoid this problem, this module explicitly disallows re-entrant compilation,
e.g. Babel's own compilation logic explicitly cannot trigger further compilation
of any other files on the fly. The downside of this is that if you want to
define a plugin or preset that is itself live-compiled, the process is
complicated.
The crux of it is that your own code needs to load the plugin/preset first.
Assuming the plugin/preset loads all of its dependencies up front, what you'll
want to do is:
```
require("@babel/register")({
// ...
});
require("./my-plugin");
```
Because it is your own code that triggered the load, and not the logic within
`@babel/register` itself, this should successfully compile any plugin/preset
that that loads synchronously.

View File

@ -55,37 +55,47 @@ function compile(code, filename) {
if (env) cacheKey += `:${env}`;
if (cache) {
const cached = cache[cacheKey];
if (cached && cached.mtime === mtime(filename)) {
return cached.code;
let cached = cache && cache[cacheKey];
if (!cached || cached.mtime !== mtime(filename)) {
cached = babel.transform(code, {
...opts,
sourceMaps: opts.sourceMaps === undefined ? "both" : opts.sourceMaps,
ast: false,
});
if (cache) {
cache[cacheKey] = cached;
cached.mtime = mtime(filename);
}
}
const result = babel.transform(code, {
...opts,
sourceMaps: opts.sourceMaps === undefined ? "both" : opts.sourceMaps,
ast: false,
});
if (cache) {
cache[cacheKey] = result;
result.mtime = mtime(filename);
}
if (result.map) {
if (cached.map) {
if (Object.keys(maps).length === 0) {
installSourceMapSupport();
}
maps[filename] = result.map;
maps[filename] = cached.map;
}
return result.code;
return cached.code;
}
let compiling = false;
function compileHook(code, filename) {
if (compiling) return code;
try {
compiling = true;
return compile(code, filename);
} finally {
compiling = false;
}
}
function hookExtensions(exts) {
if (piratesRevert) piratesRevert();
piratesRevert = addHook(compile, { exts, ignoreNodeModules: false });
piratesRevert = addHook(compileHook, { exts, ignoreNodeModules: false });
}
export function revert() {