Skip to content

Commit a8d73c2

Browse files
authored
Turbopack: Refactor output assets to allow to lazy compute output assets (#85753)
### What? Refactor the OutputAssets of chunk groups to not eagerly return all referenced output assets from async loaders, but instead return a list of references that can be followed to get the full list. That solves a problem that will happen when the async loaders create cycles in the output graph.
1 parent f6c2d49 commit a8d73c2

File tree

91 files changed

+1377
-1336
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

91 files changed

+1377
-1336
lines changed

crates/next-api/src/analyze.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use turbopack_core::{
1919
asset::{Asset, AssetContent},
2020
chunk::ChunkingType,
2121
module::Module,
22-
output::{OutputAsset, OutputAssets},
22+
output::{OutputAsset, OutputAssets, OutputAssetsReference},
2323
reference::all_assets_from_entries,
2424
};
2525

@@ -566,6 +566,9 @@ impl Asset for AnalyzeDataOutputAsset {
566566
}
567567
}
568568

569+
#[turbo_tasks::value_impl]
570+
impl OutputAssetsReference for AnalyzeDataOutputAsset {}
571+
569572
#[turbo_tasks::value_impl]
570573
impl OutputAsset for AnalyzeDataOutputAsset {
571574
#[turbo_tasks::function]
@@ -601,6 +604,9 @@ impl Asset for ModulesDataOutputAsset {
601604
}
602605
}
603606

607+
#[turbo_tasks::value_impl]
608+
impl OutputAssetsReference for ModulesDataOutputAsset {}
609+
604610
#[turbo_tasks::value_impl]
605611
impl OutputAsset for ModulesDataOutputAsset {
606612
#[turbo_tasks::function]

crates/next-api/src/app.rs

Lines changed: 79 additions & 144 deletions
Large diffs are not rendered by default.

crates/next-api/src/dynamic_imports.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,12 @@ use turbo_tasks::{
3131
};
3232
use turbopack_core::{
3333
chunk::{
34-
ChunkItem, ChunkableModule, ChunkingContext, ModuleChunkItemIdExt, ModuleId,
34+
ChunkableModule, ChunkingContext, ModuleChunkItemIdExt, ModuleId,
3535
availability_info::AvailabilityInfo,
3636
},
3737
module::Module,
3838
module_graph::{ModuleGraph, SingleModuleGraph},
39-
output::OutputAssets,
39+
output::{OutputAssetsReference, OutputAssetsWithReferenced},
4040
};
4141

4242
use crate::module_graph::DynamicImportEntriesWithImporter;
@@ -72,6 +72,7 @@ pub(crate) async fn collect_next_dynamic_chunks(
7272
)?,
7373
)
7474
.context("Client reference chunk group not found for next/dynamic import")?
75+
.await?
7576
.availability_info
7677
}
7778
NextDynamicChunkAvailability::AvailabilityInfo(availability_info) => {
@@ -103,7 +104,7 @@ pub(crate) async fn collect_next_dynamic_chunks(
103104
pub struct DynamicImportedChunks(
104105
pub FxIndexMap<
105106
ResolvedVc<NextDynamicEntryModule>,
106-
(ResolvedVc<ModuleId>, ResolvedVc<OutputAssets>),
107+
(ResolvedVc<ModuleId>, ResolvedVc<OutputAssetsWithReferenced>),
107108
>,
108109
);
109110

crates/next-api/src/font.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
use anyhow::Result;
2-
use next_core::{all_assets_from_entries, next_manifests::NextFontManifest};
2+
use next_core::next_manifests::NextFontManifest;
33
use turbo_rcstr::RcStr;
44
use turbo_tasks::{ResolvedVc, Vc};
55
use turbo_tasks_fs::{File, FileSystemPath};
66
use turbopack_core::{
77
asset::{Asset, AssetContent},
8-
output::{OutputAsset, OutputAssets},
8+
output::{OutputAsset, OutputAssets, OutputAssetsReference},
9+
reference::all_assets_from_entries,
910
};
1011

1112
use crate::paths::get_font_paths_from_root;
@@ -22,6 +23,9 @@ pub struct FontManifest {
2223
pub app_dir: bool,
2324
}
2425

26+
#[turbo_tasks::value_impl]
27+
impl OutputAssetsReference for FontManifest {}
28+
2529
#[turbo_tasks::value_impl]
2630
impl OutputAsset for FontManifest {
2731
#[turbo_tasks::function]

crates/next-api/src/instrumentation.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use anyhow::{Result, bail};
22
use next_core::{
3-
all_assets_from_entries,
43
next_edge::entry::wrap_edge_entry,
54
next_manifests::{InstrumentationDefinition, MiddlewaresManifestV2},
65
};
@@ -147,7 +146,7 @@ impl InstrumentationEndpoint {
147146

148147
if this.is_edge {
149148
let edge_chunk_group = self.edge_chunk_group();
150-
let edge_all_assets = edge_chunk_group.all_assets();
149+
let edge_all_assets = edge_chunk_group.expand_all_assets();
151150

152151
let node_root = this.project.node_root().owned().await?;
153152
let node_root_value = node_root.clone();
@@ -156,10 +155,10 @@ impl InstrumentationEndpoint {
156155
get_js_paths_from_root(&node_root_value, &edge_chunk_group.await?.assets.await?)
157156
.await?;
158157

159-
let mut output_assets = all_assets_from_entries(edge_all_assets).owned().await?;
158+
let mut output_assets = edge_chunk_group.all_assets().owned().await?;
160159

161160
let wasm_paths_from_root =
162-
get_wasm_paths_from_root(&node_root_value, &output_assets).await?;
161+
get_wasm_paths_from_root(&node_root_value, edge_all_assets.await?).await?;
163162

164163
let instrumentation_definition = InstrumentationDefinition {
165164
files: file_paths_from_root,

crates/next-api/src/loadable_manifest.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ pub async fn create_react_loadable_manifest(
2323
let mut loadable_manifest: FxIndexMap<String, LoadableManifest> = FxIndexMap::default();
2424

2525
for (_, (module_id, chunk_output)) in dynamic_import_entries.into_iter() {
26-
let chunk_output = chunk_output.await?;
26+
let chunk_output = chunk_output.primary_assets().await?;
2727

2828
let id = &*module_id.await?;
2929

crates/next-api/src/middleware.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use std::future::IntoFuture;
22

33
use anyhow::{Result, bail};
44
use next_core::{
5-
all_assets_from_entries,
65
middleware::get_middleware_module,
76
next_edge::entry::wrap_edge_entry,
87
next_manifests::{EdgeFunctionDefinition, MiddlewaresManifestV2, ProxyMatcher, Regions},
@@ -258,7 +257,7 @@ impl MiddlewareEndpoint {
258257
Ok(Vc::cell(output_assets))
259258
} else {
260259
let edge_chunk_group = self.edge_chunk_group();
261-
let edge_all_assets = edge_chunk_group.all_assets();
260+
let edge_all_assets = edge_chunk_group.expand_all_assets();
262261

263262
let node_root = this.project.node_root().owned().await?;
264263
let node_root_value = node_root.clone();
@@ -267,12 +266,13 @@ impl MiddlewareEndpoint {
267266
get_js_paths_from_root(&node_root_value, &edge_chunk_group.await?.assets.await?)
268267
.await?;
269268

270-
let mut output_assets = all_assets_from_entries(edge_all_assets).owned().await?;
269+
let mut output_assets = edge_chunk_group.all_assets().owned().await?;
271270

272271
let wasm_paths_from_root =
273-
get_wasm_paths_from_root(&node_root_value, &output_assets).await?;
272+
get_wasm_paths_from_root(&node_root_value, edge_all_assets.await?).await?;
274273

275-
let all_assets = get_asset_paths_from_root(&node_root_value, &output_assets).await?;
274+
let all_assets =
275+
get_asset_paths_from_root(&node_root_value, &edge_all_assets.await?).await?;
276276

277277
let regions = if let Some(regions) = config.preferred_region.as_ref() {
278278
if regions.len() == 1 {

crates/next-api/src/next_server_nft.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use turbopack_core::{
1616
asset::{Asset, AssetContent},
1717
context::AssetContext,
1818
file_source::FileSource,
19-
output::{OutputAsset, OutputAssets},
19+
output::{OutputAsset, OutputAssets, OutputAssetsReference},
2020
reference_type::{CommonJsReferenceSubType, ReferenceType},
2121
resolve::{origin::PlainResolveOrigin, parse::Request},
2222
traced_asset::TracedAsset,
@@ -76,6 +76,9 @@ impl ServerNftJsonAsset {
7676
}
7777
}
7878

79+
#[turbo_tasks::value_impl]
80+
impl OutputAssetsReference for ServerNftJsonAsset {}
81+
7982
#[turbo_tasks::value_impl]
8083
impl OutputAsset for ServerNftJsonAsset {
8184
#[turbo_tasks::function]

crates/next-api/src/nft_json.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use turbo_tasks_fs::{
1414
};
1515
use turbopack_core::{
1616
asset::{Asset, AssetContent},
17-
output::{OutputAsset, OutputAssets},
17+
output::{OutputAsset, OutputAssets, OutputAssetsReference},
1818
};
1919

2020
use crate::project::Project;
@@ -59,6 +59,9 @@ impl NftJsonAsset {
5959
}
6060
}
6161

62+
#[turbo_tasks::value_impl]
63+
impl OutputAssetsReference for NftJsonAsset {}
64+
6265
#[turbo_tasks::value_impl]
6366
impl OutputAsset for NftJsonAsset {
6467
#[turbo_tasks::function]
@@ -454,7 +457,7 @@ impl Visit<(ResolvedVc<Box<dyn OutputAsset>>, Option<ReadRef<RcStr>>)>
454457
node: &(ResolvedVc<Box<dyn OutputAsset>>, Option<ReadRef<RcStr>>),
455458
) -> Self::EdgesFuture {
456459
let client_root = self.client_root.clone();
457-
let exclude_glob = self.exclude_glob.clone();
460+
let exclude_glob: Option<ReadRef<Glob>> = self.exclude_glob.clone();
458461
get_referenced_server_assets(self.emit_spans, node.0, client_root, exclude_glob)
459462
}
460463

@@ -478,7 +481,7 @@ async fn get_referenced_server_assets(
478481
client_root: Option<FileSystemPath>,
479482
exclude_glob: Option<ReadRef<Glob>>,
480483
) -> Result<Vec<(ResolvedVc<Box<dyn OutputAsset>>, Option<ReadRef<RcStr>>)>> {
481-
let refs = asset.references().await?;
484+
let refs = asset.references().all_assets().await?;
482485

483486
refs.iter()
484487
.map(async |asset| {

crates/next-api/src/pages.rs

Lines changed: 37 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use anyhow::{Context, Result, bail};
22
use futures::future::BoxFuture;
33
use next_core::{
4-
PageLoaderAsset, all_assets_from_entries, create_page_loader_entry_module,
5-
get_asset_path_from_pathname, get_edge_resolve_options_context,
4+
PageLoaderAsset, create_page_loader_entry_module, get_asset_path_from_pathname,
5+
get_edge_resolve_options_context,
66
hmr_entry::HmrEntryModule,
77
mode::NextMode,
88
next_client::{
@@ -56,7 +56,8 @@ use turbopack_core::{
5656
GraphEntries, ModuleGraph, SingleModuleGraph, VisitedModules,
5757
chunk_group_info::{ChunkGroup, ChunkGroupEntry},
5858
},
59-
output::{OptionOutputAsset, OutputAsset, OutputAssets, OutputAssetsWithReferenced},
59+
output::{OptionOutputAsset, OutputAsset, OutputAssets},
60+
reference::all_assets_from_entries,
6061
reference_type::{EcmaScriptModulesReferenceSubType, EntryReferenceSubType, ReferenceType},
6162
resolve::{origin::PlainResolveOrigin, parse::Request, pattern::Pattern},
6263
source::Source,
@@ -1003,34 +1004,24 @@ impl PageEndpoint {
10031004
NextRuntime::Edge => edge_chunking_context,
10041005
};
10051006

1006-
let mut current_chunks = OutputAssets::empty();
1007-
let mut current_referenced_assets = OutputAssets::empty();
1008-
let mut current_availability_info = AvailabilityInfo::Root;
1007+
let mut current_chunk_group = ChunkGroupResult::empty_resolved();
10091008
for layout in [document_module, app_module].iter().flatten().copied() {
10101009
let span = tracing::trace_span!(
10111010
"layout segment",
10121011
name = display(layout.ident().to_string().await?)
10131012
);
10141013
async {
1015-
let ChunkGroupResult {
1016-
assets,
1017-
referenced_assets,
1018-
availability_info,
1019-
} = *chunking_context
1020-
.chunk_group(
1021-
layout.ident(),
1022-
ChunkGroup::Shared(layout),
1023-
ssr_module_graph,
1024-
current_availability_info,
1025-
)
1026-
.await?;
1014+
let chunk_group = chunking_context.chunk_group(
1015+
layout.ident(),
1016+
ChunkGroup::Shared(layout),
1017+
ssr_module_graph,
1018+
current_chunk_group.await?.availability_info,
1019+
);
10271020

1028-
current_chunks = current_chunks.concatenate(*assets).resolve().await?;
1029-
current_referenced_assets = current_referenced_assets
1030-
.concatenate(*referenced_assets)
1031-
.resolve()
1021+
current_chunk_group = current_chunk_group
1022+
.concatenate(chunk_group)
1023+
.to_resolved()
10321024
.await?;
1033-
current_availability_info = availability_info;
10341025

10351026
anyhow::Ok(())
10361027
}
@@ -1042,27 +1033,22 @@ impl PageEndpoint {
10421033
.context("could not process page loader entry module")?;
10431034
let is_edge = matches!(runtime, NextRuntime::Edge);
10441035
if is_edge {
1045-
let OutputAssetsWithReferenced {
1046-
assets: edge_assets,
1047-
referenced_assets: edge_referenced_assets,
1048-
} = *edge_chunking_context
1049-
.evaluated_chunk_group_assets(
1050-
ssr_module.ident(),
1051-
ChunkGroup::Entry(vec![ResolvedVc::upcast(ssr_module_evaluatable)]),
1052-
ssr_module_graph,
1053-
current_availability_info,
1054-
)
1036+
let chunk_assets = edge_chunking_context.evaluated_chunk_group_assets(
1037+
ssr_module.ident(),
1038+
ChunkGroup::Entry(vec![ResolvedVc::upcast(ssr_module_evaluatable)]),
1039+
ssr_module_graph,
1040+
current_chunk_group.await?.availability_info,
1041+
);
1042+
1043+
let chunk_assets = current_chunk_group
1044+
.output_assets_with_referenced()
1045+
.concatenate(chunk_assets)
1046+
.to_resolved()
10551047
.await?;
10561048

10571049
Ok(SsrChunk::Edge {
1058-
assets: current_chunks
1059-
.concatenate(*edge_assets)
1060-
.to_resolved()
1061-
.await?,
1062-
referenced_assets: current_referenced_assets
1063-
.concatenate(*edge_referenced_assets)
1064-
.to_resolved()
1065-
.await?,
1050+
assets: chunk_assets.primary_assets().to_resolved().await?,
1051+
referenced_assets: chunk_assets.referenced_assets().to_resolved().await?,
10661052
dynamic_import_entries,
10671053
regions: regions.clone(),
10681054
}
@@ -1079,9 +1065,9 @@ impl PageEndpoint {
10791065
ssr_entry_chunk_path,
10801066
EvaluatableAssets::empty().with_entry(*ssr_module_evaluatable),
10811067
ssr_module_graph,
1082-
current_chunks,
1083-
current_referenced_assets,
1084-
current_availability_info,
1068+
current_chunk_group.primary_assets(),
1069+
current_chunk_group.referenced_assets(),
1070+
current_chunk_group.await?.availability_info,
10851071
)
10861072
.to_resolved()
10871073
.await?;
@@ -1321,21 +1307,14 @@ impl PageEndpoint {
13211307

13221308
let ssr_chunk = match this.ty {
13231309
PageEndpointType::Html => {
1324-
let client_chunk_group = self.client_chunk_group().await?;
1325-
let client_chunks = *client_chunk_group.assets;
1326-
client_assets.extend(client_chunks.await?.iter().map(|asset| **asset));
1327-
client_assets.extend(
1328-
client_chunk_group
1329-
.referenced_assets
1330-
.await?
1331-
.iter()
1332-
.map(|asset| **asset),
1333-
);
1310+
let client_chunk_group = self.client_chunk_group();
1311+
client_assets.extend(client_chunk_group.all_assets().await?.iter().copied());
1312+
let client_chunks = *client_chunk_group.await?.assets;
13341313

13351314
let build_manifest = self.build_manifest(client_chunks).to_resolved().await?;
1336-
let page_loader = self.page_loader(client_chunks);
1315+
let page_loader = self.page_loader(client_chunks).to_resolved().await?;
13371316
let client_build_manifest = self
1338-
.client_build_manifest(page_loader)
1317+
.client_build_manifest(*page_loader)
13391318
.to_resolved()
13401319
.await?;
13411320
client_assets.push(page_loader);
@@ -1350,7 +1329,7 @@ impl PageEndpoint {
13501329
PageEndpointType::SsrOnly => self.ssr_chunk(emit_manifests),
13511330
};
13521331

1353-
let client_assets = OutputAssets::new(client_assets).to_resolved().await?;
1332+
let client_assets: ResolvedVc<OutputAssets> = ResolvedVc::cell(client_assets);
13541333

13551334
let manifest_path_prefix = get_asset_prefix_from_pathname(&this.pathname);
13561335
let node_root = this.pages_project.project().node_root().owned().await?;
@@ -1381,7 +1360,7 @@ impl PageEndpoint {
13811360
let webpack_stats = generate_webpack_stats(
13821361
self.client_module_graph(),
13831362
this.original_name.clone(),
1384-
client_assets.await?.iter().copied(),
1363+
client_assets.await?.into_iter().copied(),
13851364
)
13861365
.await?;
13871366
let stats_output = VirtualOutputAsset::new(

0 commit comments

Comments
 (0)