@@ -338,20 +338,37 @@ class ModuleLoader {
338338 // TODO(joyeecheung): ensure that imported synchronous graphs are evaluated
339339 // synchronously so that any previously imported synchronous graph is already
340340 // evaluated at this point.
341+ // TODO(joyeecheung): add something similar to CJS loader's requireStack to help
342+ // debugging the the problematic links in the graph for import.
341343 if ( job !== undefined ) {
342344 mod [ kRequiredModuleSymbol ] = job . module ;
345+ const parentFilename = urlToFilename ( parent ?. filename ) ;
346+ // TODO(node:55782): this race may stop to happen when the ESM resolution and loading become synchronous.
347+ if ( ! job . module ) {
348+ let message = `Cannot require() ES Module ${ filename } because it is not yet fully loaded. ` ;
349+ message += 'This may be caused by a race condition if the module is simultaneously dynamically ' ;
350+ message += 'import()-ed via Promise.all(). Try await-ing the import() sequentially in a loop instead.' ;
351+ if ( parentFilename ) {
352+ message += ` (from ${ parentFilename } )` ;
353+ }
354+ assert ( job . module , message ) ;
355+ }
343356 if ( job . module . async ) {
344- throw new ERR_REQUIRE_ASYNC_MODULE ( ) ;
357+ throw new ERR_REQUIRE_ASYNC_MODULE ( filename , parentFilename ) ;
345358 }
359+ // job.module may be undefined if it's asynchronously loaded. Which means
360+ // there is likely a cycle.
346361 if ( job . module . getStatus ( ) !== kEvaluated ) {
347- const parentFilename = urlToFilename ( parent ?. filename ) ;
348362 let message = `Cannot require() ES Module ${ filename } in a cycle.` ;
349363 if ( parentFilename ) {
350364 message += ` (from ${ parentFilename } )` ;
351365 }
366+ message += 'A cycle involving require(esm) is disallowed to maintain ' ;
367+ message += 'invariants madated by the ECMAScript specification' ;
368+ message += 'Try making at least part of the dependency in the graph lazily loaded.' ;
352369 throw new ERR_REQUIRE_CYCLE_MODULE ( message ) ;
353370 }
354- return { wrap : job . module , namespace : job . module . getNamespaceSync ( ) } ;
371+ return { wrap : job . module , namespace : job . module . getNamespaceSync ( filename , parentFilename ) } ;
355372 }
356373 // TODO(joyeecheung): refactor this so that we pre-parse in C++ and hit the
357374 // cache here, or use a carrier object to carry the compiled module script
@@ -363,7 +380,7 @@ class ModuleLoader {
363380 job = new ModuleJobSync ( this , url , kEmptyObject , wrap , isMain , inspectBrk ) ;
364381 this . loadCache . set ( url , kImplicitTypeAttribute , job ) ;
365382 mod [ kRequiredModuleSymbol ] = job . module ;
366- return { wrap : job . module , namespace : job . runSync ( ) . namespace } ;
383+ return { wrap : job . module , namespace : job . runSync ( parent ) . namespace } ;
367384 }
368385
369386 /**
0 commit comments