@@ -295,20 +295,37 @@ class ModuleLoader {
295295 // TODO(joyeecheung): ensure that imported synchronous graphs are evaluated
296296 // synchronously so that any previously imported synchronous graph is already
297297 // evaluated at this point.
298+ // TODO(joyeecheung): add something similar to CJS loader's requireStack to help
299+ // debugging the the problematic links in the graph for import.
298300 if ( job !== undefined ) {
299301 mod [ kRequiredModuleSymbol ] = job . module ;
302+ const parentFilename = urlToFilename ( parent ?. filename ) ;
303+ // TODO(node:55782): this race may stop to happen when the ESM resolution and loading become synchronous.
304+ if ( ! job . module ) {
305+ let message = `Cannot require() ES Module ${ filename } because it is not yet fully loaded. ` ;
306+ message += 'This may be caused by a race condition if the module is simultaneously dynamically ' ;
307+ message += 'import()-ed via Promise.all(). Try await-ing the import() sequentially in a loop instead.' ;
308+ if ( parentFilename ) {
309+ message += ` (from ${ parentFilename } )` ;
310+ }
311+ assert ( job . module , message ) ;
312+ }
300313 if ( job . module . async ) {
301- throw new ERR_REQUIRE_ASYNC_MODULE ( ) ;
314+ throw new ERR_REQUIRE_ASYNC_MODULE ( filename , parentFilename ) ;
302315 }
316+ // job.module may be undefined if it's asynchronously loaded. Which means
317+ // there is likely a cycle.
303318 if ( job . module . getStatus ( ) !== kEvaluated ) {
304- const parentFilename = urlToFilename ( parent ?. filename ) ;
305319 let message = `Cannot require() ES Module ${ filename } in a cycle.` ;
306320 if ( parentFilename ) {
307321 message += ` (from ${ parentFilename } )` ;
308322 }
323+ message += 'A cycle involving require(esm) is disallowed to maintain ' ;
324+ message += 'invariants madated by the ECMAScript specification' ;
325+ message += 'Try making at least part of the dependency in the graph lazily loaded.' ;
309326 throw new ERR_REQUIRE_CYCLE_MODULE ( message ) ;
310327 }
311- return { wrap : job . module , namespace : job . module . getNamespaceSync ( ) } ;
328+ return { wrap : job . module , namespace : job . module . getNamespaceSync ( filename , parentFilename ) } ;
312329 }
313330 // TODO(joyeecheung): refactor this so that we pre-parse in C++ and hit the
314331 // cache here, or use a carrier object to carry the compiled module script
@@ -320,7 +337,7 @@ class ModuleLoader {
320337 job = new ModuleJobSync ( this , url , kEmptyObject , wrap , isMain , inspectBrk ) ;
321338 this . loadCache . set ( url , kImplicitAssertType , job ) ;
322339 mod [ kRequiredModuleSymbol ] = job . module ;
323- return { wrap : job . module , namespace : job . runSync ( ) . namespace } ;
340+ return { wrap : job . module , namespace : job . runSync ( parent ) . namespace } ;
324341 }
325342
326343 /**
0 commit comments