@@ -24,6 +24,7 @@ import invariant from 'assert';
24
24
import nullthrows from 'nullthrows' ;
25
25
import { PromiseQueue } from '@parcel/utils' ;
26
26
import { hashString } from '@parcel/hash' ;
27
+ import logger from '@parcel/logger' ;
27
28
import ThrowableDiagnostic , { md } from '@parcel/diagnostic' ;
28
29
import { BundleBehavior , Priority } from '../types' ;
29
30
import AssetGraph from '../AssetGraph' ;
@@ -401,6 +402,26 @@ export class AssetGraphBuilder {
401
402
}
402
403
} ) ;
403
404
405
+ const logFallbackNamespaceInsertion = (
406
+ assetNode ,
407
+ symbol ,
408
+ depNode1 ,
409
+ depNode2 ,
410
+ ) => {
411
+ if ( this . options . logLevel === 'verbose' ) {
412
+ logger . warn ( {
413
+ message : `${ fromProjectPathRelative (
414
+ assetNode . value . filePath ,
415
+ ) } reexports "${ symbol } ", which could be resolved either to the dependency "${
416
+ depNode1 . value . specifier
417
+ } " or "${
418
+ depNode2 . value . specifier
419
+ } " at runtime. Adding a namespace object to fall back on.`,
420
+ origin : '@parcel/core' ,
421
+ } ) ;
422
+ }
423
+ } ;
424
+
404
425
// Because namespace reexports introduce ambiguity, go up the graph from the leaves to the
405
426
// root and remove requested symbols that aren't actually exported
406
427
this . propagateSymbolsUp ( ( assetNode , incomingDeps , outgoingDeps ) => {
@@ -424,7 +445,9 @@ export class AssetGraphBuilder {
424
445
}
425
446
}
426
447
427
- let reexportedSymbols = new Set < Symbol > ( ) ;
448
+ // the symbols that are reexport (not used in `asset`) -> the corresponding outgoingDep(s)
449
+ // There could be multiple dependencies with non-statically analyzable exports
450
+ let reexportedSymbols = new Map < Symbol , DependencyNode > ( ) ;
428
451
for ( let outgoingDep of outgoingDeps ) {
429
452
let outgoingDepSymbols = outgoingDep . value . symbols ;
430
453
if ( ! outgoingDepSymbols ) continue ;
@@ -441,7 +464,20 @@ export class AssetGraphBuilder {
441
464
}
442
465
443
466
if ( outgoingDepSymbols . get ( '*' ) ?. local === '*' ) {
444
- outgoingDep . usedSymbolsUp . forEach ( s => reexportedSymbols . add ( s ) ) ;
467
+ outgoingDep . usedSymbolsUp . forEach ( s => {
468
+ // If the symbol could come from multiple assets at runtime, assetNode's
469
+ // namespace will be needed at runtime to perform the lookup on.
470
+ if ( reexportedSymbols . has ( s ) && ! assetNode . usedSymbols . has ( '*' ) ) {
471
+ logFallbackNamespaceInsertion (
472
+ assetNode ,
473
+ s ,
474
+ nullthrows ( reexportedSymbols . get ( s ) ) ,
475
+ outgoingDep ,
476
+ ) ;
477
+ assetNode . usedSymbols . add ( '*' ) ;
478
+ }
479
+ reexportedSymbols . set ( s , outgoingDep ) ;
480
+ } ) ;
445
481
}
446
482
447
483
for ( let s of outgoingDep . usedSymbolsUp ) {
@@ -458,7 +494,19 @@ export class AssetGraphBuilder {
458
494
459
495
let reexported = assetSymbolsInverse ?. get ( local ) ;
460
496
if ( reexported != null ) {
461
- reexported . forEach ( s => reexportedSymbols . add ( s ) ) ;
497
+ reexported . forEach ( s => {
498
+ // see same code above
499
+ if ( reexportedSymbols . has ( s ) && ! assetNode . usedSymbols . has ( '*' ) ) {
500
+ logFallbackNamespaceInsertion (
501
+ assetNode ,
502
+ s ,
503
+ nullthrows ( reexportedSymbols . get ( s ) ) ,
504
+ outgoingDep ,
505
+ ) ;
506
+ assetNode . usedSymbols . add ( '*' ) ;
507
+ }
508
+ reexportedSymbols . set ( s , outgoingDep ) ;
509
+ } ) ;
462
510
}
463
511
}
464
512
}
0 commit comments