Skip to content

Commit 4859b5d

Browse files
joyeecheungaduh95
authored andcommitted
module: allow cycles in require() in the CJS handling in ESM loader
When --import is used, the ESM loader is used to handle even pure CJS entry points, and it can run into CJS module facades in the evaluating state when the parent CJS module is being evaluated. In this case it should be allowed, since the ESM <-> CJS cycles that are meant to be disallowed (for the time being) should already be detected before evaluation and wouldn't get here, and CJS <-> CJS cycles are fine. PR-URL: #58598 Fixes: #58515 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Ethan Arrowood <[email protected]>
1 parent 611dadc commit 4859b5d

File tree

7 files changed

+42
-4
lines changed

7 files changed

+42
-4
lines changed

lib/internal/modules/esm/module_job.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ const {
2626
ModuleWrap,
2727
kErrored,
2828
kEvaluated,
29+
kEvaluating,
2930
kEvaluationPhase,
3031
kInstantiated,
3132
kUninstantiated,
@@ -310,8 +311,14 @@ class ModuleJob extends ModuleJobBase {
310311
return { __proto__: null, module: this.module, namespace };
311312
}
312313
throw this.module.getError();
313-
314-
} else if (status === kEvaluated) {
314+
} else if (status === kEvaluating || status === kEvaluated) {
315+
// kEvaluating can show up when this is being used to deal with CJS <-> CJS cycles.
316+
// Allow it for now, since we only need to ban ESM <-> CJS cycles which would be
317+
// detected earlier during the linking phase, though the CJS handling in the ESM
318+
// loader won't be able to emit warnings on pending circular exports like what
319+
// the CJS loader does.
320+
// TODO(joyeecheung): remove the re-invented require() in the ESM loader and
321+
// always handle CJS using the CJS loader to eliminate the quirks.
315322
return { __proto__: null, module: this.module, namespace: this.module.getNamespaceSync() };
316323
}
317324
assert.fail(`Unexpected module status ${status}.`);

src/module_wrap.cc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -765,11 +765,10 @@ void ModuleWrap::GetNamespaceSync(const FunctionCallbackInfo<Value>& args) {
765765
return realm->env()->ThrowError(
766766
"Cannot get namespace, module has not been instantiated");
767767
case Module::Status::kInstantiated:
768+
case Module::Status::kEvaluating:
768769
case Module::Status::kEvaluated:
769770
case Module::Status::kErrored:
770771
break;
771-
case Module::Status::kEvaluating:
772-
UNREACHABLE();
773772
}
774773

775774
if (module->IsGraphAsync()) {
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
'use strict';
2+
3+
// This tests that --import preload does not break CJS entry points that contains
4+
// require cycles.
5+
6+
require('../common');
7+
const fixtures = require('../common/fixtures');
8+
const { spawnSyncAndAssert } = require('../common/child_process');
9+
10+
spawnSyncAndAssert(
11+
process.execPath,
12+
[
13+
'--import',
14+
fixtures.fileURL('import-require-cycle/preload.mjs'),
15+
fixtures.path('import-require-cycle/c.js'),
16+
],
17+
{
18+
stdout: /cycle equality true/,
19+
}
20+
);
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports.b = require('./b.js');
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports.a = require('./a.js');
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
const obj = require('./b.js');
2+
3+
console.log('cycle equality', obj.a.b === obj);
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import * as mod from "module";
2+
3+
mod.registerHooks({
4+
load(url, context, nextLoad) {
5+
return nextLoad(url, context);
6+
},
7+
});

0 commit comments

Comments
 (0)