@@ -524,6 +524,18 @@ func validateJSXExpr(log logger.Log, text string, name string) config.DefineExpr
524
524
return config.DefineExpr {}
525
525
}
526
526
527
+ // This returns an arbitrary but unique key for each unique array of strings
528
+ func mapKeyForDefine (parts []string ) string {
529
+ var sb strings.Builder
530
+ var n [4 ]byte
531
+ for _ , part := range parts {
532
+ binary .LittleEndian .PutUint32 (n [:], uint32 (len (part )))
533
+ sb .Write (n [:])
534
+ sb .WriteString (part )
535
+ }
536
+ return sb .String ()
537
+ }
538
+
527
539
func validateDefines (
528
540
log logger.Log ,
529
541
defines map [string ]string ,
@@ -533,13 +545,26 @@ func validateDefines(
533
545
minify bool ,
534
546
drop Drop ,
535
547
) (* config.ProcessedDefines , []config.InjectedDefine ) {
548
+ // Sort injected defines for determinism, since the imports will be injected
549
+ // into every file in the order that we return them from this function
550
+ sortedKeys := make ([]string , 0 , len (defines ))
551
+ for key := range defines {
552
+ sortedKeys = append (sortedKeys , key )
553
+ }
554
+ sort .Strings (sortedKeys )
555
+
536
556
rawDefines := make (map [string ]config.DefineData )
537
- var valueToInject map [string ]config.InjectedDefine
538
- var definesToInject []string
557
+ nodeEnvParts := []string {"process" , "env" , "NODE_ENV" }
558
+ nodeEnvMapKey := mapKeyForDefine (nodeEnvParts )
559
+ var injectedDefines []config.InjectedDefine
560
+
561
+ for _ , key := range sortedKeys {
562
+ value := defines [key ]
563
+ keyParts := strings .Split (key , "." )
564
+ mapKey := mapKeyForDefine (keyParts )
539
565
540
- for key , value := range defines {
541
566
// The key must be a dot-separated identifier list
542
- for _ , part := range strings . Split ( key , "." ) {
567
+ for _ , part := range keyParts {
543
568
if ! js_ast .IsIdentifier (part ) {
544
569
if part == key {
545
570
log .AddError (nil , logger.Range {}, fmt .Sprintf ("The define key %q must be a valid identifier" , key ))
@@ -555,10 +580,10 @@ func validateDefines(
555
580
556
581
// Define simple expressions
557
582
if defineExpr .Constant != nil || len (defineExpr .Parts ) > 0 {
558
- rawDefines [key ] = config.DefineData {DefineExpr : & defineExpr }
583
+ rawDefines [mapKey ] = config.DefineData {KeyParts : keyParts , DefineExpr : & defineExpr }
559
584
560
585
// Try to be helpful for common mistakes
561
- if len (defineExpr .Parts ) == 1 && key == "process.env.NODE_ENV" {
586
+ if len (defineExpr .Parts ) == 1 && mapKey == nodeEnvMapKey {
562
587
data := logger.MsgData {
563
588
Text : fmt .Sprintf ("%q is defined as an identifier instead of a string (surround %q with quotes to get a string)" , key , value ),
564
589
}
@@ -606,83 +631,75 @@ func validateDefines(
606
631
607
632
// Inject complex expressions
608
633
if injectExpr != nil {
609
- definesToInject = append (definesToInject , key )
610
- if valueToInject == nil {
611
- valueToInject = make (map [string ]config.InjectedDefine )
612
- }
613
- valueToInject [key ] = config.InjectedDefine {
634
+ index := ast .MakeIndex32 (uint32 (len (injectedDefines )))
635
+ injectedDefines = append (injectedDefines , config.InjectedDefine {
614
636
Source : logger.Source {Contents : value },
615
637
Data : injectExpr ,
616
638
Name : key ,
617
- }
639
+ })
640
+ rawDefines [mapKey ] = config.DefineData {KeyParts : keyParts , DefineExpr : & config.DefineExpr {InjectedDefineIndex : index }}
618
641
continue
619
642
}
620
643
621
644
// Anything else is unsupported
622
645
log .AddError (nil , logger.Range {}, fmt .Sprintf ("Invalid define value (must be an entity name or valid JSON syntax): %s" , value ))
623
646
}
624
647
625
- // Sort injected defines for determinism, since the imports will be injected
626
- // into every file in the order that we return them from this function
627
- var injectedDefines []config.InjectedDefine
628
- if len (definesToInject ) > 0 {
629
- injectedDefines = make ([]config.InjectedDefine , len (definesToInject ))
630
- sort .Strings (definesToInject )
631
- for i , key := range definesToInject {
632
- injectedDefines [i ] = valueToInject [key ]
633
- rawDefines [key ] = config.DefineData {DefineExpr : & config.DefineExpr {InjectedDefineIndex : ast .MakeIndex32 (uint32 (i ))}}
634
- }
635
- }
636
-
637
648
// If we're bundling for the browser, add a special-cased define for
638
649
// "process.env.NODE_ENV" that is "development" when not minifying and
639
650
// "production" when minifying. This is a convention from the React world
640
651
// that must be handled to avoid all React code crashing instantly. This
641
652
// is only done if it's not already defined so that you can override it if
642
653
// necessary.
643
654
if isBuildAPI && platform == config .PlatformBrowser {
644
- if _ , process := rawDefines ["process" ]; ! process {
645
- if _ , processEnv := rawDefines ["process.env" ]; ! processEnv {
646
- if _ , processEnvNodeEnv := rawDefines ["process.env.NODE_ENV" ]; ! processEnvNodeEnv {
655
+ if _ , process := rawDefines [mapKeyForDefine ([] string { "process" }) ]; ! process {
656
+ if _ , processEnv := rawDefines [mapKeyForDefine ([] string { "process.env" }) ]; ! processEnv {
657
+ if _ , processEnvNodeEnv := rawDefines [nodeEnvMapKey ]; ! processEnvNodeEnv {
647
658
var value []uint16
648
659
if minify {
649
660
value = helpers .StringToUTF16 ("production" )
650
661
} else {
651
662
value = helpers .StringToUTF16 ("development" )
652
663
}
653
- rawDefines ["process.env.NODE_ENV" ] = config.DefineData {DefineExpr : & config.DefineExpr {Constant : & js_ast.EString {Value : value }}}
664
+ rawDefines [nodeEnvMapKey ] = config.DefineData {KeyParts : nodeEnvParts , DefineExpr : & config.DefineExpr {Constant : & js_ast.EString {Value : value }}}
654
665
}
655
666
}
656
667
}
657
668
}
658
669
659
670
// If we're dropping all console API calls, replace each one with undefined
660
671
if (drop & DropConsole ) != 0 {
661
- define := rawDefines ["console" ]
672
+ consoleParts := []string {"console" }
673
+ consoleMapKey := mapKeyForDefine (consoleParts )
674
+ define := rawDefines [consoleMapKey ]
675
+ define .KeyParts = consoleParts
662
676
define .Flags |= config .MethodCallsMustBeReplacedWithUndefined
663
- rawDefines ["console" ] = define
677
+ rawDefines [consoleMapKey ] = define
664
678
}
665
679
666
680
for _ , key := range pureFns {
681
+ keyParts := strings .Split (key , "." )
682
+ mapKey := mapKeyForDefine (keyParts )
683
+
667
684
// The key must be a dot-separated identifier list
668
- for _ , part := range strings . Split ( key , "." ) {
685
+ for _ , part := range keyParts {
669
686
if ! js_ast .IsIdentifier (part ) {
670
687
log .AddError (nil , logger.Range {}, fmt .Sprintf ("Invalid pure function: %q" , key ))
671
688
continue
672
689
}
673
690
}
674
691
675
692
// Merge with any previously-specified defines
676
- define := rawDefines [key ]
693
+ define := rawDefines [mapKey ]
694
+ define .KeyParts = keyParts
677
695
define .Flags |= config .CallCanBeUnwrappedIfUnused
678
- rawDefines [key ] = define
696
+ rawDefines [mapKey ] = define
679
697
}
680
698
681
699
// Processing defines is expensive. Process them once here so the same object
682
700
// can be shared between all parsers we create using these arguments.
683
701
definesArray := make ([]config.DefineData , 0 , len (rawDefines ))
684
- for key , define := range rawDefines {
685
- define .KeyParts = strings .Split (key , "." )
702
+ for _ , define := range rawDefines {
686
703
definesArray = append (definesArray , define )
687
704
}
688
705
processed := config .ProcessDefines (definesArray )
0 commit comments