9
9
OriginRequestDefaultHandlerManifest ,
10
10
OriginRequestApiHandlerManifest ,
11
11
RoutesManifest ,
12
- OriginRequestImageHandlerManifest
12
+ OriginRequestImageHandlerManifest ,
13
+ DynamicPageKeyValue
13
14
} from "./types" ;
14
15
import { isDynamicRoute , isOptionalCatchAllRoute } from "./lib/isDynamicRoute" ;
15
16
import pathToPosix from "./lib/pathToPosix" ;
@@ -23,7 +24,7 @@ import createServerlessConfig from "./lib/createServerlessConfig";
23
24
import { isTrailingSlashRedirect } from "./routing/redirector" ;
24
25
import readDirectoryFiles from "./lib/readDirectoryFiles" ;
25
26
import filterOutDirectories from "./lib/filterOutDirectories" ;
26
- import { PrerenderManifest } from "next/dist/build" ;
27
+ import { DynamicSsgRoute , PrerenderManifest , SsgRoute } from "next/dist/build" ;
27
28
import { Item } from "klaw" ;
28
29
import { Job } from "@vercel/nft/out/node-file-trace" ;
29
30
@@ -456,7 +457,10 @@ class Builder {
456
457
] ) ;
457
458
}
458
459
459
- async prepareBuildManifests ( ) : Promise < {
460
+ async prepareBuildManifests (
461
+ routesManifest : RoutesManifest ,
462
+ prerenderManifest : PrerenderManifest
463
+ ) : Promise < {
460
464
defaultBuildManifest : OriginRequestDefaultHandlerManifest ;
461
465
apiBuildManifest : OriginRequestApiHandlerManifest ;
462
466
imageBuildManifest : OriginRequestImageHandlerManifest ;
@@ -487,6 +491,10 @@ class Builder {
487
491
html : {
488
492
dynamic : { } ,
489
493
nonDynamic : { }
494
+ } ,
495
+ ssg : {
496
+ dynamic : { } ,
497
+ nonDynamic : { }
490
498
}
491
499
} ,
492
500
publicFiles : { } ,
@@ -506,6 +514,7 @@ class Builder {
506
514
enableHTTPCompression
507
515
} ;
508
516
517
+ const ssgPages = defaultBuildManifest . pages . ssg ;
509
518
const ssrPages = defaultBuildManifest . pages . ssr ;
510
519
const htmlPages = defaultBuildManifest . pages . html ;
511
520
const apiPages = apiBuildManifest . apis ;
@@ -582,6 +591,136 @@ class Builder {
582
591
}
583
592
} ) ;
584
593
594
+ // Add non-dynamic SSG routes
595
+ Object . entries ( prerenderManifest . routes ) . forEach ( ( [ route , ssgRoute ] ) => {
596
+ // Somehow Next.js generates prerender manifest with default locale prefixed, normalize it
597
+ const defaultLocale = routesManifest . i18n ?. defaultLocale ;
598
+ if ( defaultLocale ) {
599
+ const normalizedRoute = route . replace ( `/${ defaultLocale } /` , "/" ) ;
600
+ ssgRoute . dataRoute = ssgRoute . dataRoute . replace (
601
+ `/${ defaultLocale } /` ,
602
+ "/"
603
+ ) ;
604
+ ssgPages . nonDynamic [ normalizedRoute ] = ssgRoute ;
605
+ } else {
606
+ ssgPages . nonDynamic [ route ] = ssgRoute ;
607
+ }
608
+ } ) ;
609
+
610
+ // Add dynamic SSG routes
611
+ Object . entries ( prerenderManifest . dynamicRoutes ?? { } ) . forEach (
612
+ ( [ route , dynamicSsgRoute ] ) => {
613
+ ssgPages . dynamic [ route ] = dynamicSsgRoute ;
614
+ }
615
+ ) ;
616
+
617
+ // Copy routes for all specified locales
618
+ if ( routesManifest . i18n ) {
619
+ const defaultLocale = routesManifest . i18n . defaultLocale ;
620
+ for ( const locale of routesManifest . i18n . locales ) {
621
+ if ( locale !== defaultLocale ) {
622
+ const localeSsrPages : {
623
+ nonDynamic : {
624
+ [ key : string ] : string ;
625
+ } ;
626
+ dynamic : DynamicPageKeyValue ;
627
+ } = {
628
+ nonDynamic : { } ,
629
+ dynamic : { }
630
+ } ;
631
+
632
+ for ( const key in ssrPages . nonDynamic ) {
633
+ const newKey = key === "/" ? `/${ locale } ` : `/${ locale } ${ key } ` ;
634
+ localeSsrPages . nonDynamic [ newKey ] = ssrPages . nonDynamic [ key ] ;
635
+ }
636
+
637
+ ssrPages . nonDynamic = {
638
+ ...ssrPages . nonDynamic ,
639
+ ...localeSsrPages . nonDynamic
640
+ } ;
641
+
642
+ for ( const key in ssrPages . dynamic ) {
643
+ const newKey = key === "/" ? `/${ locale } ` : `/${ locale } ${ key } ` ;
644
+ localeSsrPages . dynamic [ newKey ] = { } ;
645
+ const newDynamicSsr = Object . assign (
646
+ localeSsrPages . dynamic [ newKey ] ,
647
+ ssrPages . dynamic [ key ]
648
+ ) ;
649
+
650
+ // Need to update the regex
651
+ newDynamicSsr . regex = pathToRegexStr ( newKey ) ;
652
+ }
653
+
654
+ ssrPages . dynamic = {
655
+ ...ssrPages . dynamic ,
656
+ ...localeSsrPages . dynamic
657
+ } ;
658
+
659
+ const localeSsgPages : {
660
+ dynamic : {
661
+ [ key : string ] : DynamicSsgRoute ;
662
+ } ;
663
+ nonDynamic : {
664
+ [ key : string ] : SsgRoute ;
665
+ } ;
666
+ } = {
667
+ dynamic : { } ,
668
+ nonDynamic : { }
669
+ } ;
670
+
671
+ for ( const key in ssgPages . nonDynamic ) {
672
+ const newKey = key === "/" ? `/${ locale } ` : `/${ locale } ${ key } ` ;
673
+ localeSsgPages . nonDynamic [ newKey ] = { } ;
674
+
675
+ const newSsgRoute = Object . assign (
676
+ localeSsgPages . nonDynamic [ newKey ] ,
677
+ ssgPages . nonDynamic [ key ]
678
+ ) ;
679
+
680
+ // Replace with localized value
681
+ newSsgRoute . dataRoute = newSsgRoute . dataRoute . replace (
682
+ `/_next/data/${ buildId } /` ,
683
+ `/_next/data/${ buildId } /${ locale } /`
684
+ ) ;
685
+ }
686
+
687
+ ssgPages . nonDynamic = {
688
+ ...ssgPages . nonDynamic ,
689
+ ...localeSsgPages . nonDynamic
690
+ } ;
691
+
692
+ for ( const key in ssgPages . dynamic ) {
693
+ const newKey = key === "/" ? `/${ locale } ` : `/${ locale } ${ key } ` ;
694
+ localeSsgPages . dynamic [ newKey ] = ssgPages . dynamic [ key ] ;
695
+
696
+ const newDynamicSsgRoute = localeSsgPages . dynamic [ newKey ] ;
697
+
698
+ // Replace with localized values
699
+ newDynamicSsgRoute . dataRoute = newDynamicSsgRoute . dataRoute . replace (
700
+ `/_next/data/${ buildId } /` ,
701
+ `/_next/data/${ buildId } /${ locale } /`
702
+ ) ;
703
+ newDynamicSsgRoute . dataRouteRegex = newDynamicSsgRoute . dataRouteRegex . replace (
704
+ `/_next/data/${ buildId } /` ,
705
+ `/_next/data/${ buildId } /${ locale } /`
706
+ ) ;
707
+ newDynamicSsgRoute . fallback =
708
+ typeof newDynamicSsgRoute . fallback === "string"
709
+ ? newDynamicSsgRoute . fallback . replace ( "/" , `/${ locale } /` )
710
+ : newDynamicSsgRoute . fallback ;
711
+ newDynamicSsgRoute . routeRegex = localeSsgPages . dynamic [
712
+ newKey
713
+ ] . routeRegex . replace ( "^/" , `^/${ locale } /` ) ;
714
+ }
715
+
716
+ ssgPages . dynamic = {
717
+ ...ssgPages . dynamic ,
718
+ ...localeSsgPages . dynamic
719
+ } ;
720
+ }
721
+ }
722
+ }
723
+
585
724
const publicFiles = await this . readPublicFiles ( ) ;
586
725
587
726
publicFiles . forEach ( ( pf ) => {
@@ -727,26 +866,16 @@ class Builder {
727
866
) ;
728
867
const destination = path . join (
729
868
assetOutputDirectory ,
730
- withBasePath ( `_next/data/${ buildId } /${ localePrefixedJSONFileName } ` )
869
+ withBasePath (
870
+ `_next/data/${ buildId } /${
871
+ defaultLocale && defaultLocale === locale
872
+ ? JSONFileName
873
+ : localePrefixedJSONFileName
874
+ } `
875
+ )
731
876
) ;
732
877
733
- if ( defaultLocale && defaultLocale === locale ) {
734
- // If this is default locale, we need to copy to two destinations
735
- // the locale-prefixed path and non-locale-prefixed path
736
- const defaultDestination = path . join (
737
- assetOutputDirectory ,
738
- withBasePath ( `_next/data/${ buildId } /${ JSONFileName } ` )
739
- ) ;
740
-
741
- return new Promise ( async ( ) => {
742
- await Promise . all ( [
743
- copyIfExists ( source , destination ) ,
744
- copyIfExists ( source , defaultDestination )
745
- ] ) ;
746
- } ) ;
747
- } else {
748
- return copyIfExists ( source , destination ) ;
749
- }
878
+ return copyIfExists ( source , destination ) ;
750
879
} )
751
880
) ;
752
881
@@ -765,32 +894,22 @@ class Builder {
765
894
const destination = path . join (
766
895
assetOutputDirectory ,
767
896
withBasePath (
768
- path . join ( "static-pages" , buildId , localePrefixedPageFilePath )
897
+ path . join (
898
+ "static-pages" ,
899
+ buildId ,
900
+ defaultLocale && defaultLocale === locale
901
+ ? pageFilePath
902
+ : localePrefixedPageFilePath
903
+ )
769
904
)
770
905
) ;
771
906
772
- if ( defaultLocale && defaultLocale === locale ) {
773
- // If this is default locale, we need to copy to two destinations
774
- // the locale-prefixed path and non-locale-prefixed path
775
- const defaultDestination = path . join (
776
- assetOutputDirectory ,
777
- withBasePath ( path . join ( "static-pages" , buildId , pageFilePath ) )
778
- ) ;
779
-
780
- return new Promise ( async ( ) => {
781
- await Promise . all ( [
782
- copyIfExists ( source , destination ) ,
783
- copyIfExists ( source , defaultDestination )
784
- ] ) ;
785
- } ) ;
786
- } else {
787
- return copyIfExists ( source , destination ) ;
788
- }
907
+ return copyIfExists ( source , destination ) ;
789
908
} )
790
909
) ;
791
910
792
911
fallbackHTMLPageAssets . concat (
793
- Object . values ( prerenderManifest . dynamicRoutes || { } )
912
+ Object . values ( prerenderManifest . dynamicRoutes ?? { } )
794
913
. filter ( ( { fallback } ) => {
795
914
return ! ! fallback ;
796
915
} )
@@ -806,27 +925,17 @@ class Builder {
806
925
const destination = path . join (
807
926
assetOutputDirectory ,
808
927
withBasePath (
809
- path . join ( "static-pages" , buildId , localePrefixedFallback )
928
+ path . join (
929
+ "static-pages" ,
930
+ buildId ,
931
+ defaultLocale && defaultLocale === locale
932
+ ? fallback
933
+ : localePrefixedFallback
934
+ )
810
935
)
811
936
) ;
812
937
813
- if ( defaultLocale && defaultLocale === locale ) {
814
- // If this is default locale, we need to copy to two destinations
815
- // the locale-prefixed path and non-locale-prefixed path
816
- const defaultDestination = path . join (
817
- assetOutputDirectory ,
818
- withBasePath ( path . join ( "static-pages" , buildId , fallback ) )
819
- ) ;
820
-
821
- return new Promise ( async ( ) => {
822
- await Promise . all ( [
823
- copyIfExists ( source , destination ) ,
824
- copyIfExists ( source , defaultDestination )
825
- ] ) ;
826
- } ) ;
827
- } else {
828
- return copyIfExists ( source , destination ) ;
829
- }
938
+ return copyIfExists ( source , destination ) ;
830
939
} )
831
940
) ;
832
941
}
@@ -927,11 +1036,21 @@ class Builder {
927
1036
await restoreUserConfig ( ) ;
928
1037
}
929
1038
1039
+ const routesManifest = require ( join (
1040
+ this . dotNextDir ,
1041
+ "routes-manifest.json"
1042
+ ) ) ;
1043
+
1044
+ const prerenderManifest = require ( join (
1045
+ this . dotNextDir ,
1046
+ "prerender-manifest.json"
1047
+ ) ) ;
1048
+
930
1049
const {
931
1050
defaultBuildManifest,
932
1051
apiBuildManifest,
933
1052
imageBuildManifest
934
- } = await this . prepareBuildManifests ( ) ;
1053
+ } = await this . prepareBuildManifests ( routesManifest , prerenderManifest ) ;
935
1054
936
1055
await this . buildDefaultLambda ( defaultBuildManifest ) ;
937
1056
@@ -953,10 +1072,6 @@ class Builder {
953
1072
}
954
1073
955
1074
// Copy static assets to .serverless_nextjs directory
956
- const routesManifest = require ( join (
957
- this . dotNextDir ,
958
- "routes-manifest.json"
959
- ) ) ;
960
1075
await this . buildStaticAssets ( defaultBuildManifest , routesManifest ) ;
961
1076
}
962
1077
0 commit comments