Skip to content

Commit 4acf7cd

Browse files
joyeecheungaduh95
authored andcommitted
module: throw error when re-runing errored module jobs
Re-evaluating an errored ESM should lead to rejecting the rejection again - this is also the case when importing it twice. In the case of retrying with require after import, just throw the cached error. Drive-by: add some debug logs. PR-URL: #58957 Fixes: #58945 Reviewed-By: Marco Ippolito <[email protected]> Reviewed-By: Luigi Pinca <[email protected]> Reviewed-By: Antoine du Hamel <[email protected]>
1 parent bace73a commit 4acf7cd

File tree

4 files changed

+47
-2
lines changed

4 files changed

+47
-2
lines changed

lib/internal/modules/esm/loader.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ const {
4242
kEvaluated,
4343
kEvaluating,
4444
kInstantiated,
45+
kErrored,
4546
throwIfPromiseRejected,
4647
} = internalBinding('module_wrap');
4748
const {
@@ -394,6 +395,9 @@ class ModuleLoader {
394395
mod[kRequiredModuleSymbol] = job.module;
395396
const { namespace } = job.runSync(parent);
396397
return { wrap: job.module, namespace: namespace || job.module.getNamespace() };
398+
} else if (status === kErrored) {
399+
// If the module was previously imported and errored, throw the error.
400+
throw job.module.getError();
397401
}
398402
// When the cached async job have already encountered a linking
399403
// error that gets wrapped into a rejection, but is still later

lib/internal/modules/esm/module_job.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ class ModuleJob extends ModuleJobBase {
297297
assert(this.module instanceof ModuleWrap);
298298
let status = this.module.getStatus();
299299

300-
debug('ModuleJob.runSync', this.module);
300+
debug('ModuleJob.runSync()', status, this.module);
301301
// FIXME(joyeecheung): this cannot fully handle < kInstantiated. Make the linking
302302
// fully synchronous instead.
303303
if (status === kUninstantiated) {
@@ -332,6 +332,8 @@ class ModuleJob extends ModuleJobBase {
332332
}
333333

334334
async run(isEntryPoint = false) {
335+
debug('ModuleJob.run()', this.module);
336+
assert(this.phase === kEvaluationPhase);
335337
await this.instantiate();
336338
if (isEntryPoint) {
337339
globalThis[entry_point_module_private_symbol] = this.module;
@@ -411,7 +413,11 @@ class ModuleJobSync extends ModuleJobBase {
411413
async run() {
412414
// This path is hit by a require'd module that is imported again.
413415
const status = this.module.getStatus();
414-
if (status > kInstantiated) {
416+
debug('ModuleJobSync.run()', status, this.module);
417+
// If the module was previously required and errored, reject from import() again.
418+
if (status === kErrored) {
419+
throw this.module.getError();
420+
} else if (status > kInstantiated) {
415421
if (this.evaluationPromise) {
416422
await this.evaluationPromise;
417423
}
@@ -432,6 +438,8 @@ class ModuleJobSync extends ModuleJobBase {
432438
}
433439

434440
runSync(parent) {
441+
debug('ModuleJobSync.runSync()', this.module);
442+
assert(this.phase === kEvaluationPhase);
435443
// TODO(joyeecheung): add the error decoration logic from the async instantiate.
436444
this.module.async = this.module.instantiateSync();
437445
// If --experimental-print-required-tla is true, proceeds to evaluation even
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// This tests that after failing to import an ESM that rejects,
2+
// retrying with require() still throws.
3+
4+
'use strict';
5+
const common = require('../common');
6+
const assert = require('assert');
7+
8+
(async () => {
9+
await assert.rejects(import('../fixtures/es-modules/throw-error.mjs'), {
10+
message: 'test',
11+
});
12+
assert.throws(() => {
13+
require('../fixtures/es-modules/throw-error.mjs');
14+
}, {
15+
message: 'test',
16+
});
17+
})().then(common.mustCall());
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// This tests that after failing to require an ESM that throws,
2+
// retrying with import() still rejects.
3+
4+
'use strict';
5+
const common = require('../common');
6+
const assert = require('assert');
7+
8+
assert.throws(() => {
9+
require('../fixtures/es-modules/throw-error.mjs');
10+
}, {
11+
message: 'test',
12+
});
13+
14+
assert.rejects(import('../fixtures/es-modules/throw-error.mjs'), {
15+
message: 'test',
16+
}).then(common.mustCall());

0 commit comments

Comments
 (0)