@@ -31,7 +31,7 @@ use tracing::Instrument;
31
31
use turbo_rcstr:: RcStr ;
32
32
use turbo_tasks:: {
33
33
fxindexmap, trace:: TraceRawVcs , Completion , FxIndexMap , NonLocalValue , ResolvedVc , TaskInput ,
34
- Value , Vc ,
34
+ Value , ValueToString , Vc ,
35
35
} ;
36
36
use turbo_tasks_fs:: {
37
37
self , File , FileContent , FileSystem , FileSystemPath , FileSystemPathOption , VirtualFileSystem ,
@@ -46,15 +46,15 @@ use turbopack_core::{
46
46
asset:: AssetContent ,
47
47
chunk:: {
48
48
availability_info:: AvailabilityInfo , ChunkGroupResult , ChunkingContext , ChunkingContextExt ,
49
- EntryChunkGroupResult , EvaluatableAsset , EvaluatableAssets ,
49
+ EvaluatableAsset , EvaluatableAssets ,
50
50
} ,
51
51
context:: AssetContext ,
52
52
file_source:: FileSource ,
53
53
ident:: AssetIdent ,
54
54
module:: Module ,
55
55
module_graph:: {
56
56
chunk_group_info:: { ChunkGroup , ChunkGroupEntry } ,
57
- GraphEntries , ModuleGraph ,
57
+ GraphEntries , ModuleGraph , SingleModuleGraph , VisitedModules ,
58
58
} ,
59
59
output:: { OptionOutputAsset , OutputAsset , OutputAssets } ,
60
60
reference_type:: { EcmaScriptModulesReferenceSubType , EntryReferenceSubType , ReferenceType } ,
@@ -772,7 +772,45 @@ impl PageEndpoint {
772
772
let this = self . await ?;
773
773
let project = this. pages_project . project ( ) ;
774
774
let evaluatable_assets = self . client_evaluatable_assets ( ) ;
775
- Ok ( project. module_graph_for_entries ( evaluatable_assets) )
775
+ Ok ( project. module_graph_for_modules ( evaluatable_assets) )
776
+ }
777
+
778
+ #[ turbo_tasks:: function]
779
+ async fn ssr_module_graph ( self : Vc < Self > ) -> Result < Vc < ModuleGraph > > {
780
+ let this = self . await ?;
781
+ let project = this. pages_project . project ( ) ;
782
+
783
+ if * project. per_page_module_graph ( ) . await ? {
784
+ let ssr_chunk_module = self . internal_ssr_chunk_module ( ) . await ?;
785
+ // Implements layout segment optimization to compute a graph "chain" for document, app,
786
+ // page
787
+ let mut graphs = vec ! [ ] ;
788
+ let mut visited_modules = VisitedModules :: empty ( ) ;
789
+ for module in [
790
+ ssr_chunk_module. document_module ,
791
+ ssr_chunk_module. app_module ,
792
+ ]
793
+ . into_iter ( )
794
+ . flatten ( )
795
+ {
796
+ let graph = SingleModuleGraph :: new_with_entries_visited_intern (
797
+ vec ! [ ChunkGroupEntry :: Shared ( module) ] ,
798
+ visited_modules,
799
+ ) ;
800
+ graphs. push ( graph) ;
801
+ visited_modules = visited_modules. concatenate ( graph) ;
802
+ }
803
+
804
+ let graph = SingleModuleGraph :: new_with_entries_visited_intern (
805
+ vec ! [ ChunkGroupEntry :: Entry ( vec![ ssr_chunk_module. ssr_module] ) ] ,
806
+ visited_modules,
807
+ ) ;
808
+ graphs. push ( graph) ;
809
+
810
+ Ok ( ModuleGraph :: from_graphs ( graphs) )
811
+ } else {
812
+ Ok ( * project. whole_app_module_graphs ( ) . await ?. full )
813
+ }
776
814
}
777
815
778
816
#[ turbo_tasks:: function]
@@ -852,10 +890,8 @@ impl PageEndpoint {
852
890
. module ( ) ;
853
891
854
892
let config = parse_config_from_source ( ssr_module, NextRuntime :: default ( ) ) . await ?;
855
- let is_edge = matches ! ( config. runtime, NextRuntime :: Edge ) ;
856
-
857
- let ssr_module = if is_edge {
858
- create_page_ssr_entry_module (
893
+ Ok ( if config. runtime == NextRuntime :: Edge {
894
+ let modules = create_page_ssr_entry_module (
859
895
* this. pathname ,
860
896
reference_type,
861
897
project_root,
@@ -866,15 +902,28 @@ impl PageEndpoint {
866
902
config. runtime ,
867
903
this. pages_project . project ( ) . next_config ( ) ,
868
904
)
905
+ . await ?;
906
+
907
+ InternalSsrChunkModule {
908
+ ssr_module : modules. ssr_module ,
909
+ app_module : modules. app_module ,
910
+ document_module : modules. document_module ,
911
+ runtime : config. runtime ,
912
+ }
869
913
} else {
870
914
let pathname = & * * this. pathname . await ?;
871
915
872
916
// `/_app` and `/_document` never get rendered directly so they don't need to be
873
917
// wrapped in the route module.
874
918
if pathname == "/_app" || pathname == "/_document" {
875
- ssr_module
919
+ InternalSsrChunkModule {
920
+ ssr_module : ssr_module. to_resolved ( ) . await ?,
921
+ app_module : None ,
922
+ document_module : None ,
923
+ runtime : config. runtime ,
924
+ }
876
925
} else {
877
- create_page_ssr_entry_module (
926
+ let modules = create_page_ssr_entry_module (
878
927
* this. pathname ,
879
928
reference_type,
880
929
project_root,
@@ -885,12 +934,14 @@ impl PageEndpoint {
885
934
config. runtime ,
886
935
this. pages_project . project ( ) . next_config ( ) ,
887
936
)
937
+ . await ?;
938
+ InternalSsrChunkModule {
939
+ ssr_module : modules. ssr_module ,
940
+ app_module : modules. app_module ,
941
+ document_module : modules. document_module ,
942
+ runtime : config. runtime ,
943
+ }
888
944
}
889
- } ;
890
-
891
- Ok ( InternalSsrChunkModule {
892
- ssr_module : ssr_module. to_resolved ( ) . await ?,
893
- runtime : config. runtime ,
894
945
}
895
946
. cell ( ) )
896
947
}
@@ -900,7 +951,7 @@ impl PageEndpoint {
900
951
self : Vc < Self > ,
901
952
ty : SsrChunkType ,
902
953
node_path : Vc < FileSystemPath > ,
903
- chunking_context : Vc < NodeJsChunkingContext > ,
954
+ node_chunking_context : Vc < NodeJsChunkingContext > ,
904
955
edge_chunking_context : Vc < Box < dyn ChunkingContext > > ,
905
956
runtime_entries : Vc < EvaluatableAssets > ,
906
957
edge_runtime_entries : Vc < EvaluatableAssets > ,
@@ -910,14 +961,16 @@ impl PageEndpoint {
910
961
911
962
let InternalSsrChunkModule {
912
963
ssr_module,
964
+ app_module,
965
+ document_module,
913
966
runtime,
914
967
} = * self . internal_ssr_chunk_module ( ) . await ?;
915
968
916
969
let project = this. pages_project . project ( ) ;
917
970
// The SSR and Client Graphs are not connected in Pages Router.
918
971
// We are only interested in get_next_dynamic_imports_for_endpoint at the
919
972
// moment, which only needs the client graph anyway.
920
- let module_graph = project . module_graph ( * ssr_module ) ;
973
+ let ssr_module_graph = self . ssr_module_graph ( ) ;
921
974
922
975
let next_dynamic_imports = if let PageEndpointType :: Html = this. ty {
923
976
let client_availability_info = self . client_chunks ( ) . await ?. availability_info ;
@@ -952,6 +1005,40 @@ impl PageEndpoint {
952
1005
DynamicImportedChunks :: default ( ) . resolved_cell ( )
953
1006
} ;
954
1007
1008
+ let chunking_context: Vc < Box < dyn ChunkingContext > > = match runtime {
1009
+ NextRuntime :: NodeJs => Vc :: upcast ( node_chunking_context) ,
1010
+ NextRuntime :: Edge => Vc :: upcast ( edge_chunking_context) ,
1011
+ } ;
1012
+
1013
+ let mut current_chunks = OutputAssets :: empty ( ) ;
1014
+ let mut current_availability_info = AvailabilityInfo :: Root ;
1015
+ for layout in [ document_module, app_module] . iter ( ) . flatten ( ) . copied ( ) {
1016
+ let span = tracing:: trace_span!(
1017
+ "layout segment" ,
1018
+ name = display( layout. ident( ) . to_string( ) . await ?)
1019
+ ) ;
1020
+ async {
1021
+ let chunk_group = chunking_context
1022
+ . chunk_group (
1023
+ layout. ident ( ) ,
1024
+ ChunkGroup :: Shared ( layout) ,
1025
+ ssr_module_graph,
1026
+ Value :: new ( current_availability_info) ,
1027
+ )
1028
+ . await ?;
1029
+
1030
+ current_chunks = current_chunks
1031
+ . concatenate ( * chunk_group. assets )
1032
+ . resolve ( )
1033
+ . await ?;
1034
+ current_availability_info = chunk_group. availability_info ;
1035
+
1036
+ anyhow:: Ok ( ( ) )
1037
+ }
1038
+ . instrument ( span)
1039
+ . await ?;
1040
+ }
1041
+
955
1042
let ssr_module_evaluatable = ResolvedVc :: try_sidecast ( ssr_module)
956
1043
. context ( "could not process page loader entry module" ) ?;
957
1044
let is_edge = matches ! ( runtime, NextRuntime :: Edge ) ;
@@ -962,18 +1049,15 @@ impl PageEndpoint {
962
1049
. map ( |m| ResolvedVc :: upcast ( * m) )
963
1050
. chain ( std:: iter:: once ( ResolvedVc :: upcast ( ssr_module_evaluatable) ) ) ;
964
1051
965
- let edge_files = edge_chunking_context
966
- . evaluated_chunk_group_assets (
967
- ssr_module. ident ( ) ,
968
- ChunkGroup :: Entry ( evaluatable_assets. collect ( ) ) ,
969
- module_graph,
970
- Value :: new ( AvailabilityInfo :: Root ) ,
971
- )
972
- . to_resolved ( )
973
- . await ?;
1052
+ let edge_files = edge_chunking_context. evaluated_chunk_group_assets (
1053
+ ssr_module. ident ( ) ,
1054
+ ChunkGroup :: Entry ( evaluatable_assets. collect ( ) ) ,
1055
+ ssr_module_graph,
1056
+ Value :: new ( current_availability_info) ,
1057
+ ) ;
974
1058
975
1059
Ok ( SsrChunk :: Edge {
976
- files : edge_files,
1060
+ files : current_chunks . concatenate ( edge_files) . to_resolved ( ) . await ? ,
977
1061
dynamic_import_entries,
978
1062
}
979
1063
. cell ( ) )
@@ -984,17 +1068,15 @@ impl PageEndpoint {
984
1068
985
1069
let ssr_entry_chunk_path_string: RcStr = format ! ( "pages{asset_path}" ) . into ( ) ;
986
1070
let ssr_entry_chunk_path = node_path. join ( ssr_entry_chunk_path_string) ;
987
- let EntryChunkGroupResult {
988
- asset : ssr_entry_chunk,
989
- ..
990
- } = * chunking_context
991
- . entry_chunk_group (
1071
+ let ssr_entry_chunk = node_chunking_context
1072
+ . entry_chunk_group_asset (
992
1073
ssr_entry_chunk_path,
993
1074
runtime_entries. with_entry ( * ssr_module_evaluatable) ,
994
- module_graph ,
995
- OutputAssets :: empty ( ) ,
996
- Value :: new ( AvailabilityInfo :: Root ) ,
1075
+ ssr_module_graph ,
1076
+ current_chunks ,
1077
+ Value :: new ( current_availability_info ) ,
997
1078
)
1079
+ . to_resolved ( )
998
1080
. await ?;
999
1081
1000
1082
let server_asset_trace_file = if this
@@ -1364,6 +1446,8 @@ impl PageEndpoint {
1364
1446
#[ turbo_tasks:: value]
1365
1447
pub struct InternalSsrChunkModule {
1366
1448
pub ssr_module : ResolvedVc < Box < dyn Module > > ,
1449
+ pub app_module : Option < ResolvedVc < Box < dyn Module > > > ,
1450
+ pub document_module : Option < ResolvedVc < Box < dyn Module > > > ,
1367
1451
pub runtime : NextRuntime ,
1368
1452
}
1369
1453
@@ -1467,17 +1551,32 @@ impl Endpoint for PageEndpoint {
1467
1551
let this = self . await ?;
1468
1552
1469
1553
let ssr_chunk_module = self . internal_ssr_chunk_module ( ) . await ?;
1470
- let mut modules = vec ! [ ChunkGroupEntry :: Entry ( vec![ ssr_chunk_module. ssr_module] ) ] ;
1471
1554
1472
- if let PageEndpointType :: Html = this. ty {
1473
- modules. push ( ChunkGroupEntry :: Entry (
1474
- self . client_evaluatable_assets ( )
1475
- . await ?
1476
- . iter ( )
1477
- . map ( |m| ResolvedVc :: upcast ( * m) )
1478
- . collect ( ) ,
1479
- ) ) ;
1480
- }
1555
+ let shared_entries = [
1556
+ ssr_chunk_module. document_module ,
1557
+ ssr_chunk_module. app_module ,
1558
+ ] ;
1559
+
1560
+ let modules = shared_entries
1561
+ . into_iter ( )
1562
+ . flatten ( )
1563
+ . map ( ChunkGroupEntry :: Shared )
1564
+ . chain ( std:: iter:: once ( ChunkGroupEntry :: Entry ( vec ! [
1565
+ ssr_chunk_module. ssr_module,
1566
+ ] ) ) )
1567
+ . chain ( if this. ty == PageEndpointType :: Html {
1568
+ Some ( ChunkGroupEntry :: Entry (
1569
+ self . client_evaluatable_assets ( )
1570
+ . await ?
1571
+ . iter ( )
1572
+ . map ( |m| ResolvedVc :: upcast ( * m) )
1573
+ . collect ( ) ,
1574
+ ) )
1575
+ . into_iter ( )
1576
+ } else {
1577
+ None . into_iter ( )
1578
+ } )
1579
+ . collect :: < Vec < _ > > ( ) ;
1481
1580
1482
1581
Ok ( Vc :: cell ( modules) )
1483
1582
}
0 commit comments