diff --git a/crates/next-api/src/analyze.rs b/crates/next-api/src/analyze.rs index fd617edb1cfc3..1609eeaf91a25 100644 --- a/crates/next-api/src/analyze.rs +++ b/crates/next-api/src/analyze.rs @@ -425,7 +425,7 @@ pub async fn analyze_module_graphs(module_graphs: Vc) -> Result>, ClientMani #[turbo_tasks::function] pub async fn map_client_references( - graph: Vc, + graph: ResolvedVc, ) -> Result> { let graph = graph.await?; let manifest = graph diff --git a/crates/next-api/src/dynamic_imports.rs b/crates/next-api/src/dynamic_imports.rs index de4e53480d4ac..7b1f46845b6b5 100644 --- a/crates/next-api/src/dynamic_imports.rs +++ b/crates/next-api/src/dynamic_imports.rs @@ -35,7 +35,7 @@ use turbopack_core::{ availability_info::AvailabilityInfo, }, module::Module, - module_graph::{ModuleGraph, SingleModuleGraph}, + module_graph::{ModuleGraph, ModuleGraphLayer}, output::{OutputAssetsReference, OutputAssetsWithReferenced}, }; @@ -122,7 +122,9 @@ pub struct DynamicImportEntries( ); #[turbo_tasks::function] -pub async fn map_next_dynamic(graph: Vc) -> Result> { +pub async fn map_next_dynamic( + graph: ResolvedVc, +) -> Result> { let actions = graph .await? .iter_nodes() diff --git a/crates/next-api/src/module_graph.rs b/crates/next-api/src/module_graph.rs index b7124c18a7e29..8f2c154aa7149 100644 --- a/crates/next-api/src/module_graph.rs +++ b/crates/next-api/src/module_graph.rs @@ -23,7 +23,7 @@ use turbopack_core::{ context::AssetContext, issue::{Issue, IssueExt, IssueSeverity, IssueStage, OptionStyledString, StyledString}, module::Module, - module_graph::{GraphTraversalAction, ModuleGraph, SingleModuleGraphWithBindingUsage}, + module_graph::{GraphTraversalAction, ModuleGraph, ModuleGraphLayer}, }; use turbopack_css::{CssModuleAsset, ModuleCssAsset}; @@ -35,7 +35,7 @@ use crate::{ #[turbo_tasks::value] pub struct NextDynamicGraph { - graph: SingleModuleGraphWithBindingUsage, + graph: ResolvedVc, is_single_page: bool, /// list of NextDynamicEntryModules @@ -52,12 +52,13 @@ impl NextDynamicGraphs { graphs: ResolvedVc, is_single_page: bool, ) -> Result> { - let graphs_ref = &graphs.await?; + let graphs_ref = &graphs.iter_graphs().await?; let next_dynamic = async { graphs_ref - .iter_graphs() + .iter() .map(|graph| { - NextDynamicGraph::new_with_entries(graph, is_single_page).to_resolved() + NextDynamicGraph::new_with_entries(graph.connect(), is_single_page) + .to_resolved() }) .try_join() .await @@ -130,10 +131,10 @@ pub struct DynamicImportEntriesWithImporter( impl NextDynamicGraph { #[turbo_tasks::function] pub async fn new_with_entries( - graph: SingleModuleGraphWithBindingUsage, + graph: ResolvedVc, is_single_page: bool, ) -> Result> { - let mapped = map_next_dynamic(*graph.graph); + let mapped = map_next_dynamic(*graph); Ok(NextDynamicGraph { is_single_page, @@ -151,7 +152,7 @@ impl NextDynamicGraph { let span = tracing::info_span!("collect next/dynamic imports for endpoint"); async move { let data = &*self.data.await?; - let graph = self.graph.read().await?; + let graph = self.graph.await?; #[derive(Clone, PartialEq, Eq)] enum VisitState { @@ -232,7 +233,7 @@ impl NextDynamicGraph { #[turbo_tasks::value] pub struct ServerActionsGraph { - graph: SingleModuleGraphWithBindingUsage, + graph: ResolvedVc, is_single_page: bool, /// (Layer, RSC or Browser module) -> list of actions @@ -249,12 +250,13 @@ impl ServerActionsGraphs { graphs: ResolvedVc, is_single_page: bool, ) -> Result> { - let graphs_ref = &graphs.await?; + let graphs_ref = &graphs.iter_graphs().await?; let server_actions = async { graphs_ref - .iter_graphs() + .iter() .map(|graph| { - ServerActionsGraph::new_with_entries(graph, is_single_page).to_resolved() + ServerActionsGraph::new_with_entries(graph.connect(), is_single_page) + .to_resolved() }) .try_join() .await @@ -316,10 +318,10 @@ impl ServerActionsGraphs { impl ServerActionsGraph { #[turbo_tasks::function] pub async fn new_with_entries( - graph: SingleModuleGraphWithBindingUsage, + graph: ResolvedVc, is_single_page: bool, ) -> Result> { - let mapped = map_server_actions(*graph.graph); + let mapped = map_server_actions(*graph); Ok(ServerActionsGraph { is_single_page, @@ -343,7 +345,7 @@ impl ServerActionsGraph { Cow::Borrowed(data) } else { // The graph contains the whole app, traverse and collect all reachable imports. - let graph = self.graph.read().await?; + let graph = self.graph.await?; if !graph.graphs.first().unwrap().has_entry_module(entry) { // the graph doesn't contain the entry, e.g. for the additional module graph @@ -407,7 +409,7 @@ impl ServerActionsGraph { #[turbo_tasks::value] pub struct ClientReferencesGraph { is_single_page: bool, - graph: SingleModuleGraphWithBindingUsage, + graph: ResolvedVc, /// List of client references (modules that entries into the client graph) data: ResolvedVc, @@ -423,12 +425,13 @@ impl ClientReferencesGraphs { graphs: ResolvedVc, is_single_page: bool, ) -> Result> { - let graphs_ref = &graphs.await?; + let graphs_ref = graphs.iter_graphs().await?; let client_references = async { graphs_ref - .iter_graphs() + .iter() .map(|graph| { - ClientReferencesGraph::new_with_entries(graph, is_single_page).to_resolved() + ClientReferencesGraph::new_with_entries(graph.connect(), is_single_page) + .to_resolved() }) .try_join() .await @@ -518,10 +521,10 @@ impl ClientReferencesGraphs { impl ClientReferencesGraph { #[turbo_tasks::function] pub async fn new_with_entries( - graph: SingleModuleGraphWithBindingUsage, + graph: ResolvedVc, is_single_page: bool, ) -> Result> { - let mapped = map_client_references(*graph.graph); + let mapped = map_client_references(*graph); Ok(Self { is_single_page, @@ -539,7 +542,7 @@ impl ClientReferencesGraph { let span = tracing::info_span!("collect client references for endpoint"); async move { let data = &*self.data.await?; - let graph = self.graph.read().await?; + let graph = self.graph.await?; let entries = if !self.is_single_page { if !graph.graphs.first().unwrap().has_entry_module(entry) { @@ -766,12 +769,12 @@ struct ModuleNameMap(#[bincode(with = "turbo_bincode::indexmap")] pub FxModuleNa #[tracing::instrument(level = "info", name = "validate pages css imports", skip_all)] #[turbo_tasks::function] async fn validate_pages_css_imports_individual( - graph: SingleModuleGraphWithBindingUsage, + graph: ResolvedVc, is_single_page: bool, entry: Vc>, app_module: ResolvedVc>, ) -> Result<()> { - let graph = graph.read().await?; + let graph = graph.await?; let entry = entry.to_resolved().await?; let entries = if !is_single_page { @@ -869,12 +872,17 @@ pub async fn validate_pages_css_imports( entry: Vc>, app_module: Vc>, ) -> Result<()> { - let graphs = &graph.await?; + let graphs = graph.iter_graphs().await?; graphs - .iter_graphs() + .iter() .map(|graph| { - validate_pages_css_imports_individual(graph, is_single_page, entry, app_module) - .as_side_effect() + validate_pages_css_imports_individual( + graph.connect(), + is_single_page, + entry, + app_module, + ) + .as_side_effect() }) .try_join() .await?; diff --git a/crates/next-api/src/pages.rs b/crates/next-api/src/pages.rs index 3b057ba0f66df..d27f4c701269d 100644 --- a/crates/next-api/src/pages.rs +++ b/crates/next-api/src/pages.rs @@ -736,7 +736,7 @@ impl PageEndpoint { should_read_binding_usage, ); graphs.push(graph); - visited_modules = visited_modules.concatenate(graph); + visited_modules = VisitedModules::concatenate(visited_modules, graph); } let graph = SingleModuleGraph::new_with_entries_visited_intern( @@ -747,21 +747,20 @@ impl PageEndpoint { ); graphs.push(graph); - let mut graph = ModuleGraph::from_graphs(graphs); - - if *project + let remove_unused_imports = *project .next_config() .turbopack_remove_unused_imports(next_mode) - .await? - { - graph = graph.without_unused_references( - *compute_binding_usage_info(graph.to_resolved().await?, true) - .resolve_strongly_consistent() - .await?, - ); - } + .await?; + + let graph = if remove_unused_imports { + let graph = ModuleGraph::from_graphs(graphs.clone()); + let binding_usage_info = compute_binding_usage_info(graph, true); + ModuleGraph::from_graphs_without_unused_references(graphs, binding_usage_info) + } else { + ModuleGraph::from_graphs(graphs) + }; - Ok(graph) + Ok(graph.connect()) } else { Ok(*project.whole_app_module_graphs().await?.full) } diff --git a/crates/next-api/src/project.rs b/crates/next-api/src/project.rs index 41377993774e5..95c4947194eb5 100644 --- a/crates/next-api/src/project.rs +++ b/crates/next-api/src/project.rs @@ -1163,7 +1163,12 @@ impl Project { ) -> Result> { Ok(if *self.per_page_module_graph().await? { let is_production = self.next_mode().await?.is_production(); - ModuleGraph::from_entry_module(*entry, is_production, is_production) + ModuleGraph::from_single_graph(SingleModuleGraph::new_with_entry( + ChunkGroupEntry::Entry(vec![entry]), + is_production, + is_production, + )) + .connect() } else { *self.whole_app_module_graphs().await?.full }) @@ -1182,11 +1187,12 @@ impl Project { .copied() .map(ResolvedVc::upcast) .collect(); - ModuleGraph::from_modules( - Vc::cell(vec![ChunkGroupEntry::Entry(entries)]), + ModuleGraph::from_single_graph(SingleModuleGraph::new_with_entries( + ResolvedVc::cell(vec![ChunkGroupEntry::Entry(entries)]), is_production, is_production, - ) + )) + .connect() } else { *self.whole_app_module_graphs().await?.full }) @@ -2034,19 +2040,11 @@ impl Project { /// Compute the used exports and unused imports for each module. #[turbo_tasks::function] async fn binding_usage_info(self: Vc) -> Result> { - let remove_unused_imports = *self - .next_config() - .turbopack_remove_unused_imports(self.next_mode()) - .await?; - let module_graphs = self.whole_app_module_graphs().await?; - Ok(*compute_binding_usage_info( - module_graphs.full_with_unused_references, - remove_unused_imports, - ) - // As a performance optimization, we resolve strongly consistently - .resolve_strongly_consistent() - .await?) + Ok(module_graphs + .binding_usage_info + .context("No binding usage info")? + .connect()) } /// Compute the used exports for each module. @@ -2102,7 +2100,7 @@ async fn whole_app_module_graph_operation( let should_trace = next_mode_ref.is_production(); let should_read_binding_usage = next_mode_ref.is_production(); let base_single_module_graph = SingleModuleGraph::new_with_entries( - project.get_all_entries(), + project.get_all_entries().to_resolved().await?, should_trace, should_read_binding_usage, ); @@ -2118,16 +2116,19 @@ async fn whole_app_module_graph_operation( let base = if turbopack_remove_unused_imports { // TODO suboptimal that we do compute_binding_usage_info twice (once for the base graph // and later for the full graph) - base.without_unused_references( - *compute_binding_usage_info(base.to_resolved().await?, true) - .resolve_strongly_consistent() - .await?, + let binding_usage_info = compute_binding_usage_info(base, true); + ModuleGraph::from_single_graph_without_unused_references( + base_single_module_graph, + binding_usage_info, ) } else { base }; - let additional_entries = project.get_all_additional_entries(base); + let additional_entries = project + .get_all_additional_entries(base.connect()) + .to_resolved() + .await?; let additional_module_graph = SingleModuleGraph::new_with_entries_visited( additional_entries, @@ -2136,28 +2137,23 @@ async fn whole_app_module_graph_operation( should_read_binding_usage, ); - let full_with_unused_references = - ModuleGraph::from_graphs(vec![base_single_module_graph, additional_module_graph]) - .to_resolved() - .await?; + let graphs = vec![base_single_module_graph, additional_module_graph]; - let full = if turbopack_remove_unused_imports { - full_with_unused_references - .without_unused_references( - *compute_binding_usage_info(full_with_unused_references, true) - .resolve_strongly_consistent() - .await?, - ) - .to_resolved() - .await? + let (full, binding_usage_info) = if turbopack_remove_unused_imports { + let full_with_unused_references = ModuleGraph::from_graphs(graphs.clone()); + let binding_usage_info = compute_binding_usage_info(full_with_unused_references, true); + ( + ModuleGraph::from_graphs_without_unused_references(graphs, binding_usage_info), + Some(binding_usage_info), + ) } else { - full_with_unused_references + (ModuleGraph::from_graphs(graphs), None) }; Ok(BaseAndFullModuleGraph { - base: base.to_resolved().await?, - full_with_unused_references, - full, + base: base.connect().to_resolved().await?, + full: full.connect().to_resolved().await?, + binding_usage_info, } .cell()) } @@ -2166,11 +2162,10 @@ async fn whole_app_module_graph_operation( pub struct BaseAndFullModuleGraph { /// The base module graph generated from the entry points. pub base: ResolvedVc, - /// The base graph plus any modules that were generated from additional entries (for which the - /// base graph is needed). - pub full_with_unused_references: ResolvedVc, /// `full_with_unused_references` but with unused references removed. pub full: ResolvedVc, + /// Information about binding usage in the module graph. + pub binding_usage_info: Option>, } #[turbo_tasks::function] diff --git a/crates/next-api/src/routes_hashes_manifest.rs b/crates/next-api/src/routes_hashes_manifest.rs index 87597db9a742c..95f28f7b01b53 100644 --- a/crates/next-api/src/routes_hashes_manifest.rs +++ b/crates/next-api/src/routes_hashes_manifest.rs @@ -62,7 +62,7 @@ pub async fn endpoint_hashes( let mut all_modules = FxIndexSet::default(); - let module_graph = module_graph.read_graphs().await?; + let module_graph = module_graph.await?; module_graph.traverse_nodes_dfs( modules, diff --git a/crates/next-api/src/server_actions.rs b/crates/next-api/src/server_actions.rs index 189c8a2fd05cd..0a99389a66d08 100644 --- a/crates/next-api/src/server_actions.rs +++ b/crates/next-api/src/server_actions.rs @@ -30,7 +30,7 @@ use turbopack_core::{ file_source::FileSource, ident::AssetIdent, module::Module, - module_graph::{ModuleGraph, SingleModuleGraph, async_module_info::AsyncModulesInfo}, + module_graph::{ModuleGraph, ModuleGraphLayer, async_module_info::AsyncModulesInfo}, output::OutputAsset, reference_type::{EcmaScriptModulesReferenceSubType, ReferenceType}, resolve::ModulePart, @@ -453,7 +453,9 @@ pub struct AllModuleActions( ); #[turbo_tasks::function] -pub async fn map_server_actions(graph: Vc) -> Result> { +pub async fn map_server_actions( + graph: ResolvedVc, +) -> Result> { let actions = graph .await? .iter_nodes() diff --git a/crates/next-api/src/webpack_stats.rs b/crates/next-api/src/webpack_stats.rs index bed5c32e4ad9e..12385ee987691 100644 --- a/crates/next-api/src/webpack_stats.rs +++ b/crates/next-api/src/webpack_stats.rs @@ -56,7 +56,7 @@ where }; let asset_reasons = { - let module_graph = module_graph.read_graphs().await?; + let module_graph = module_graph.await?; let mut edges = vec![]; module_graph.traverse_edges_unordered(|parent, current| { if let Some((parent_node, r)) = parent { diff --git a/crates/next-core/src/next_font/google/mod.rs b/crates/next-core/src/next_font/google/mod.rs index 4b4a16e7ae722..9061a73acc28f 100644 --- a/crates/next-core/src/next_font/google/mod.rs +++ b/crates/next-core/src/next_font/google/mod.rs @@ -21,7 +21,7 @@ use turbopack_core::{ context::AssetContext, ident::Layer, issue::{IssueExt, IssueSeverity, StyledString}, - module_graph::ModuleGraph, + module_graph::{ModuleGraph, SingleModuleGraph}, reference_type::{InnerAssets, ReferenceType}, resolve::{ ResolveResult, @@ -760,7 +760,12 @@ async fn get_mock_stylesheet( .module(); let entries = get_evaluate_entries(mocked_response_asset, asset_context, None); - let module_graph = ModuleGraph::from_modules(entries.graph_entries(), false, false); + let module_graph = ModuleGraph::from_single_graph(SingleModuleGraph::new_with_entries( + entries.graph_entries().to_resolved().await?, + false, + false, + )); + let module_graph = module_graph.connect(); let root = mock_fs.root().owned().await?; let val = evaluate( diff --git a/turbopack/crates/turbopack-cli/src/build/mod.rs b/turbopack/crates/turbopack-cli/src/build/mod.rs index c572585ac6912..27976920211e8 100644 --- a/turbopack/crates/turbopack-cli/src/build/mod.rs +++ b/turbopack/crates/turbopack-cli/src/build/mod.rs @@ -29,7 +29,7 @@ use turbopack_core::{ issue::{IssueReporter, IssueSeverity, handle_issues}, module::Module, module_graph::{ - ModuleGraph, + ModuleGraph, SingleModuleGraph, binding_usage_info::compute_binding_usage_info, chunk_group_info::{ChunkGroup, ChunkGroupEntry}, }, @@ -304,21 +304,26 @@ async fn build_internal( .instrument(tracing::info_span!("resolve entries")) .await?; - let mut module_graph = ModuleGraph::from_modules( - Vc::cell(vec![ChunkGroupEntry::Entry(entries.clone())]), + let single_graph = SingleModuleGraph::new_with_entries( + ResolvedVc::cell(vec![ChunkGroupEntry::Entry(entries.clone())]), false, true, ); + let mut module_graph = ModuleGraph::from_single_graph(single_graph); + let binding_usage = compute_binding_usage_info(module_graph, true); + let unused_references = binding_usage + .connect() + .unused_references() + .to_resolved() + .await?; + module_graph = + ModuleGraph::from_single_graph_without_unused_references(single_graph, binding_usage); + let module_graph = module_graph.connect(); let module_id_strategy = ResolvedVc::upcast( get_global_module_id_strategy(module_graph) .to_resolved() .await?, ); - let binding_usage = compute_binding_usage_info(module_graph.to_resolved().await?, true) - .resolve_strongly_consistent() - .await?; - let unused_references = binding_usage.unused_references().to_resolved().await?; - module_graph = module_graph.without_unused_references(*binding_usage); let chunking_context: Vc> = match target { Target::Browser => { @@ -344,7 +349,7 @@ async fn build_internal( ) .source_maps(source_maps_type) .module_id_strategy(module_id_strategy) - .export_usage(Some(binding_usage)) + .export_usage(Some(binding_usage.connect().to_resolved().await?)) .unused_references(unused_references) .current_chunk_method(CurrentChunkMethod::DocumentCurrentScript) .minify_type(minify_type); @@ -394,7 +399,7 @@ async fn build_internal( ) .source_maps(source_maps_type) .module_id_strategy(module_id_strategy) - .export_usage(Some(binding_usage)) + .export_usage(Some(binding_usage.connect().to_resolved().await?)) .unused_references(unused_references) .minify_type(minify_type); diff --git a/turbopack/crates/turbopack-cli/src/dev/web_entry_source.rs b/turbopack/crates/turbopack-cli/src/dev/web_entry_source.rs index 2d64e40e59b87..6c1a2005e6da1 100644 --- a/turbopack/crates/turbopack-cli/src/dev/web_entry_source.rs +++ b/turbopack/crates/turbopack-cli/src/dev/web_entry_source.rs @@ -12,7 +12,7 @@ use turbopack_core::{ environment::Environment, file_source::FileSource, module::Module, - module_graph::{ModuleGraph, chunk_group_info::ChunkGroupEntry}, + module_graph::{ModuleGraph, SingleModuleGraph, chunk_group_info::ChunkGroupEntry}, reference_type::{EntryReferenceSubType, ReferenceType}, resolve::{ origin::{PlainResolveOrigin, ResolveOrigin, ResolveOriginExt}, @@ -161,13 +161,12 @@ pub async fn create_web_entry_source( .map(|&entry| ResolvedVc::upcast(entry)), ) .collect::>>>(); - let module_graph = ModuleGraph::from_modules( - Vc::cell(vec![ChunkGroupEntry::Entry(all_modules)]), + let module_graph = ModuleGraph::from_single_graph(SingleModuleGraph::new_with_entries( + ResolvedVc::cell(vec![ChunkGroupEntry::Entry(all_modules)]), false, false, - ) - .to_resolved() - .await?; + )); + let module_graph = module_graph.connect().to_resolved().await?; let entries: Vec<_> = entries .into_iter() diff --git a/turbopack/crates/turbopack-core/src/module_graph/async_module_info.rs b/turbopack/crates/turbopack-core/src/module_graph/async_module_info.rs index 881fbda7bdd6c..09a6bf328e2cb 100644 --- a/turbopack/crates/turbopack-core/src/module_graph/async_module_info.rs +++ b/turbopack/crates/turbopack-core/src/module_graph/async_module_info.rs @@ -4,7 +4,7 @@ use turbo_tasks::{ResolvedVc, TryFlatJoinIterExt, Vc}; use crate::{ module::{Module, Modules}, - module_graph::{GraphTraversalAction, ModuleGraph, SingleModuleGraphWithBindingUsage}, + module_graph::{GraphTraversalAction, ModuleGraph, ModuleGraphLayer}, }; #[turbo_tasks::value(transparent)] @@ -41,21 +41,19 @@ pub async fn compute_async_module_info( ) -> Result> { // Layout segment optimization, we can individually compute the async modules for each graph. let mut result: Vc = Vc::cell(Default::default()); - let graphs = graphs.await?; - for graph in graphs.iter_graphs() { - result = compute_async_module_info_single(graph, result); + for graph in graphs.iter_graphs().await? { + result = compute_async_module_info_single(graph.connect(), result); } Ok(result) } #[turbo_tasks::function] async fn compute_async_module_info_single( - graph: SingleModuleGraphWithBindingUsage, + graph: ResolvedVc, parent_async_modules: Vc, ) -> Result> { let parent_async_modules = parent_async_modules.await?; - let graph = graph.read().await?; - + let graph = graph.await?; let self_async_modules = graph .enumerate_nodes() .map(async |(_, node)| { diff --git a/turbopack/crates/turbopack-core/src/module_graph/binding_usage_info.rs b/turbopack/crates/turbopack-core/src/module_graph/binding_usage_info.rs index e86386a6c5dde..742985e92cc8a 100644 --- a/turbopack/crates/turbopack-core/src/module_graph/binding_usage_info.rs +++ b/turbopack/crates/turbopack-core/src/module_graph/binding_usage_info.rs @@ -5,7 +5,7 @@ use auto_hash_map::AutoSet; use rustc_hash::{FxHashMap, FxHashSet}; use tracing::Instrument; use turbo_rcstr::RcStr; -use turbo_tasks::{ResolvedVc, Vc}; +use turbo_tasks::{OperationVc, ResolvedVc, Vc}; use crate::{ chunk::chunking_context::UnusedReferences, @@ -90,7 +90,7 @@ impl BindingUsageInfo { #[turbo_tasks::function(operation)] pub async fn compute_binding_usage_info( - graph: ResolvedVc, + graph: OperationVc, remove_unused_imports: bool, ) -> Result> { let span_outer = tracing::info_span!( @@ -111,7 +111,9 @@ pub async fn compute_binding_usage_info( let mut unused_references_edges = FxHashSet::default(); let mut unused_references = FxHashSet::default(); - if graph.await?.binding_usage.is_some() { + let graph = graph.connect(); + let graph_ref = graph.await?; + if graph_ref.binding_usage.is_some() { // If the graph already has binding usage info, return it directly. This is // unfortunately easy to do with // ``` @@ -128,9 +130,8 @@ pub async fn compute_binding_usage_info( without_unused_references" ); } - let graph_ref = graph.read_graphs().await?; let side_effect_free_modules = if remove_unused_imports { - let side_effect_free_modules = compute_side_effect_free_module_info(*graph).await?; + let side_effect_free_modules = compute_side_effect_free_module_info(graph).await?; span.record("side_effect_free_modules", side_effect_free_modules.len()); Some(side_effect_free_modules) } else { diff --git a/turbopack/crates/turbopack-core/src/module_graph/chunk_group_info.rs b/turbopack/crates/turbopack-core/src/module_graph/chunk_group_info.rs index a37e2886f0b15..231e93a7a9931 100644 --- a/turbopack/crates/turbopack-core/src/module_graph/chunk_group_info.rs +++ b/turbopack/crates/turbopack-core/src/module_graph/chunk_group_info.rs @@ -19,7 +19,7 @@ use turbo_tasks::{ use crate::{ chunk::ChunkingType, module::Module, - module_graph::{GraphTraversalAction, ModuleGraphRef, RefData}, + module_graph::{GraphTraversalAction, ModuleGraph, RefData}, }; #[derive(Clone, Debug, Default, PartialEq, TraceRawVcs, ValueDebugFormat, Encode, Decode)] @@ -372,7 +372,7 @@ impl Ord for TraversalPriority { } } -pub async fn compute_chunk_group_info(graph: &ModuleGraphRef) -> Result> { +pub async fn compute_chunk_group_info(graph: &ModuleGraph) -> Result> { let span_outer = tracing::info_span!( "compute chunk group info", module_count = tracing::field::Empty, diff --git a/turbopack/crates/turbopack-core/src/module_graph/merged_modules.rs b/turbopack/crates/turbopack-core/src/module_graph/merged_modules.rs index 0dfe2f9e8541a..9c8d25e489bb2 100644 --- a/turbopack/crates/turbopack-core/src/module_graph/merged_modules.rs +++ b/turbopack/crates/turbopack-core/src/module_graph/merged_modules.rs @@ -74,7 +74,7 @@ pub async fn compute_merged_modules(module_graph: Vc) -> Result(); diff --git a/turbopack/crates/turbopack-core/src/module_graph/mod.rs b/turbopack/crates/turbopack-core/src/module_graph/mod.rs index 1d07833cbc347..f7945d3f3f3ca 100644 --- a/turbopack/crates/turbopack-core/src/module_graph/mod.rs +++ b/turbopack/crates/turbopack-core/src/module_graph/mod.rs @@ -2,6 +2,7 @@ use core::panic; use std::{ collections::{BinaryHeap, VecDeque}, future::Future, + ops::Deref, }; use anyhow::{Context, Result, bail}; @@ -16,8 +17,8 @@ use serde::{Deserialize, Serialize}; use tracing::{Instrument, Level, Span}; use turbo_rcstr::RcStr; use turbo_tasks::{ - CollectiblesSource, FxIndexMap, NonLocalValue, ReadRef, ResolvedVc, TaskInput, TryJoinIterExt, - ValueToString, Vc, + CollectiblesSource, FxIndexMap, NonLocalValue, OperationVc, ReadRef, ResolvedVc, + TryJoinIterExt, ValueToString, Vc, debug::ValueDebugFormat, graph::{AdjacencyMap, GraphTraversal, Visit, VisitControlFlow}, trace::TraceRawVcs, @@ -126,7 +127,7 @@ pub struct VisitedModules { #[turbo_tasks::value_impl] impl VisitedModules { - #[turbo_tasks::function] + #[turbo_tasks::function(operation)] pub fn empty() -> Vc { Self { modules: Default::default(), @@ -135,10 +136,11 @@ impl VisitedModules { .cell() } - #[turbo_tasks::function] - pub async fn from_graph(graph: Vc) -> Result> { + #[turbo_tasks::function(operation)] + pub async fn from_graph(graph: OperationVc) -> Result> { Ok(Self { modules: graph + .connect() .await? .enumerate_nodes() .flat_map(|(node_idx, module)| match module { @@ -157,19 +159,24 @@ impl VisitedModules { .cell()) } - #[turbo_tasks::function] - pub fn with_incremented_index(&self) -> Result> { + #[turbo_tasks::function(operation)] + pub async fn with_incremented_index(this: OperationVc) -> Result> { + let this = this.connect().await?; Ok(Self { - modules: self.modules.clone(), - next_graph_idx: self.next_graph_idx + 1, + modules: this.modules.clone(), + next_graph_idx: this.next_graph_idx + 1, } .cell()) } - #[turbo_tasks::function] - pub async fn concatenate(&self, graph: Vc) -> Result> { - let graph = graph.await?; - let iter = self + #[turbo_tasks::function(operation)] + pub async fn concatenate( + this: OperationVc, + graph: OperationVc, + ) -> Result> { + let graph = graph.connect().await?; + let this = this.connect().await?; + let iter = this .modules .iter() .map(|(module, idx)| (*module, *idx)) @@ -180,7 +187,7 @@ impl VisitedModules { SingleModuleGraphNode::Module(module) => Some(( *module, GraphNodeIndex { - graph_idx: self.next_graph_idx, + graph_idx: this.next_graph_idx, node_idx, }, )), @@ -189,7 +196,7 @@ impl VisitedModules { ); let mut map = FxIndexMap::with_capacity_and_hasher( - self.modules.len() + graph.number_of_modules, + this.modules.len() + graph.number_of_modules, Default::default(), ); for (k, v) in iter { @@ -199,7 +206,7 @@ impl VisitedModules { Ok(Self { modules: map, - next_graph_idx: self.next_graph_idx + 1, + next_graph_idx: this.next_graph_idx + 1, } .cell()) } @@ -263,7 +270,7 @@ impl SingleModuleGraph { /// nodes listed in `visited_modules` /// The resulting graph's outgoing edges are in reverse order. async fn new_inner( - entries: &GraphEntriesT, + entries: Vec, visited_modules: &FxIndexMap>, GraphNodeIndex>, include_traced: bool, include_binding_usage: bool, @@ -634,63 +641,91 @@ impl ImportTracer for ModuleGraphImportTracer { } } -#[turbo_tasks::value(shared)] -#[derive(Clone, Default)] +/// The ReadRef version of ModuleGraphBase. This is better for eventual consistency, as the graphs +/// aren't awaited multiple times within the same task. +#[turbo_tasks::value(shared, serialization = "none", eq = "manual", cell = "new")] pub struct ModuleGraph { - pub graphs: Vec>, + input_graphs: Vec>, + input_binding_usage: Option>, - pub binding_usage: Option>, + snapshot: ModuleGraphSnapshot, } #[turbo_tasks::value_impl] impl ModuleGraph { - #[turbo_tasks::function] - pub fn from_graphs(graphs: Vec>) -> Vc { - Self { - graphs, - binding_usage: None, - } - .cell() + #[turbo_tasks::function(operation)] + pub async fn from_single_graph(graph: OperationVc) -> Result> { + let graph = Self::create(vec![graph], None) + .read_strongly_consistent() + .await?; + Ok(ReadRef::cell(graph)) } - #[turbo_tasks::function] - pub fn from_single_graph(graph: ResolvedVc) -> Vc { - Self { - graphs: vec![graph], - binding_usage: None, - } - .cell() + #[turbo_tasks::function(operation)] + pub async fn from_graphs(graphs: Vec>) -> Result> { + let graph = Self::create(graphs, None) + .read_strongly_consistent() + .await?; + Ok(ReadRef::cell(graph)) } - #[turbo_tasks::function] - pub fn from_entry_module( - module: ResolvedVc>, - include_traced: bool, - include_binding_usage: bool, - ) -> Vc { - Self::from_single_graph(SingleModuleGraph::new_with_entries( - Vc::cell(vec![ChunkGroupEntry::Entry(vec![module])]), - include_traced, - include_binding_usage, - )) + /// Analyze the module graph and remove unused references (by determining the used exports and + /// removing unused imports). + /// + /// In particular, this removes ChunkableModuleReference-s that list only unused exports in the + /// `import_usage()` + #[turbo_tasks::function(operation)] + pub async fn from_single_graph_without_unused_references( + graph: OperationVc, + binding_usage: OperationVc, + ) -> Result> { + let graph = Self::create(vec![graph], Some(binding_usage)) + .read_strongly_consistent() + .await?; + Ok(ReadRef::cell(graph)) } - #[turbo_tasks::function] - pub fn from_modules( - modules: Vc, - include_traced: bool, - include_binding_usage: bool, - ) -> Vc { - Self::from_single_graph(SingleModuleGraph::new_with_entries( - modules, - include_traced, - include_binding_usage, - )) + /// Analyze the module graph and remove unused references (by determining the used exports and + /// removing unused imports). + /// + /// In particular, this removes ChunkableModuleReference-s that list only unused exports in the + /// `import_usage()` + #[turbo_tasks::function(operation)] + pub async fn from_graphs_without_unused_references( + graphs: Vec>, + binding_usage: OperationVc, + ) -> Result> { + let graph = Self::create(graphs, Some(binding_usage)) + .read_strongly_consistent() + .await?; + Ok(ReadRef::cell(graph)) + } + + #[turbo_tasks::function(operation)] + async fn create( + graphs: Vec>, + binding_usage: Option>, + ) -> Result> { + Ok(ModuleGraph { + input_graphs: graphs.clone(), + input_binding_usage: binding_usage, + snapshot: ModuleGraphSnapshot { + graphs: graphs.iter().map(|g| g.connect()).try_join().await?, + skip_visited_module_children: false, + graph_idx_override: None, + binding_usage: if let Some(binding_usage) = binding_usage { + Some(binding_usage.connect().await?) + } else { + None + }, + }, + } + .cell()) } #[turbo_tasks::function] pub async fn chunk_group_info(self: Vc) -> Result> { - compute_chunk_group_info(&self.read_graphs().await?).await + compute_chunk_group_info(&*self.await?).await } #[turbo_tasks::function] @@ -734,7 +769,7 @@ impl ModuleGraph { self: Vc, module: ResolvedVc>, ) -> Result> { - let graph_ref = self.read_graphs().await?; + let graph_ref = self.await?; let async_modules_info = self.async_module_info().await?; let entry = graph_ref.get_entry(module)?; @@ -755,82 +790,71 @@ impl ModuleGraph { Ok(AsyncModuleInfo::new(referenced_modules)) } - /// Analyze the module graph and remove unused references (by determining the used exports and - /// removing unused imports). - /// - /// In particular, this removes ChunkableModuleReference-s that list only unused exports in the - /// `import_usage()` + /// Returns the underlying graphs as a list, to be used for individual graph traversals. #[turbo_tasks::function] - pub async fn without_unused_references( - self: ResolvedVc, - binding_usage: ResolvedVc, - ) -> Result> { - Ok(Self { - graphs: self.await?.graphs.clone(), - binding_usage: Some(binding_usage), - } - .cell()) + pub fn iter_graphs(&self) -> Vc { + Vc::cell( + self.input_graphs + .iter() + .enumerate() + .map(|(graph_idx, graph)| { + ModuleGraphLayer::new(*graph, graph_idx as u32, self.input_binding_usage) + }) + .collect(), + ) } } -impl ModuleGraph { - /// Reads the ModuleGraph into a ModuleGraphRef, awaiting all underlying graphs. - pub async fn read_graphs(self: Vc) -> Result { - let this = self.await?; - Ok(ModuleGraphRef { - graphs: this.graphs.iter().try_join().await?, - skip_visited_module_children: false, - graph_idx_override: None, - binding_usage: if let Some(binding_usage) = this.binding_usage { - Some(binding_usage.await?) - } else { - None - }, - }) - } +impl Deref for ModuleGraph { + type Target = ModuleGraphSnapshot; - /// Returns the underlying graphs as a list, to be used for individual graph traversals. - pub fn iter_graphs( - self: &ModuleGraph, - ) -> impl Iterator { - self.graphs - .iter() - .enumerate() - .map(|(graph_idx, graph)| SingleModuleGraphWithBindingUsage { - graph: *graph, - graph_idx: graph_idx as u32, - binding_usage: self.binding_usage, - }) + fn deref(&self) -> &Self::Target { + &self.snapshot } } -#[derive( - Clone, Debug, PartialEq, Eq, Hash, TaskInput, TraceRawVcs, NonLocalValue, Encode, Decode, -)] -pub struct SingleModuleGraphWithBindingUsage { - pub graph: ResolvedVc, - pub graph_idx: u32, - pub binding_usage: Option>, +#[turbo_tasks::value(shared, serialization = "none", eq = "manual", cell = "new")] +pub struct ModuleGraphLayer { + snapshot: ModuleGraphSnapshot, } -impl SingleModuleGraphWithBindingUsage { - pub async fn read(self: &SingleModuleGraphWithBindingUsage) -> Result { - Ok(ModuleGraphRef { - graphs: vec![self.graph.await?], - skip_visited_module_children: true, - graph_idx_override: Some(self.graph_idx), - binding_usage: if let Some(binding_usage) = &self.binding_usage { - Some(binding_usage.await?) - } else { - None +#[turbo_tasks::value_impl] +impl ModuleGraphLayer { + #[turbo_tasks::function(operation)] + async fn new( + graph: OperationVc, + graph_idx: u32, + binding_usage: Option>, + ) -> Result> { + Ok(Self { + snapshot: ModuleGraphSnapshot { + graphs: vec![graph.connect().await?], + skip_visited_module_children: true, + graph_idx_override: Some(graph_idx), + binding_usage: if let Some(binding_usage) = binding_usage { + Some(binding_usage.connect().await?) + } else { + None + }, }, - }) + } + .cell()) } } -/// The ReadRef version of ModuleGraph. This is better for eventual consistency, as the graphs -/// aren't awaited multiple times within the same task. -pub struct ModuleGraphRef { +impl Deref for ModuleGraphLayer { + type Target = ModuleGraphSnapshot; + + fn deref(&self) -> &Self::Target { + &self.snapshot + } +} + +#[turbo_tasks::value(transparent)] +pub struct ModuleGraphLayers(Vec>); + +#[derive(TraceRawVcs, ValueDebugFormat, NonLocalValue)] +pub struct ModuleGraphSnapshot { pub graphs: Vec>, // Whether to simply ignore SingleModuleGraphNode::VisitedModule during traversals. For single // module graph usecases, this is what you want. For the whole graph, there should be an error. @@ -841,7 +865,7 @@ pub struct ModuleGraphRef { pub binding_usage: Option>, } -impl ModuleGraphRef { +impl ModuleGraphSnapshot { fn get_entry(&self, entry: ResolvedVc>) -> Result { if self.graph_idx_override.is_some() { debug_assert_eq!(self.graphs.len(), 1,); @@ -905,6 +929,10 @@ impl ModuleGraphRef { self.graphs.iter().flat_map(|g| g.enumerate_nodes()) } + pub fn iter_nodes(&self) -> impl Iterator>> + '_ { + self.graphs.iter().flat_map(|g| g.iter_nodes()) + } + /// Iterate the edges of a node REVERSED! fn iter_graphs_neighbors_rev<'a>( &'a self, @@ -1387,14 +1415,29 @@ impl ModuleGraphRef { #[turbo_tasks::value_impl] impl SingleModuleGraph { - #[turbo_tasks::function] + #[turbo_tasks::function(operation)] + pub async fn new_with_entry( + entry: ChunkGroupEntry, + include_traced: bool, + include_binding_usage: bool, + ) -> Result> { + SingleModuleGraph::new_inner( + vec![entry], + &Default::default(), + include_traced, + include_binding_usage, + ) + .await + } + + #[turbo_tasks::function(operation)] pub async fn new_with_entries( - entries: Vc, + entries: ResolvedVc, include_traced: bool, include_binding_usage: bool, ) -> Result> { SingleModuleGraph::new_inner( - &*entries.await?, + entries.owned().await?, &Default::default(), include_traced, include_binding_usage, @@ -1402,33 +1445,33 @@ impl SingleModuleGraph { .await } - #[turbo_tasks::function] + #[turbo_tasks::function(operation)] pub async fn new_with_entries_visited( - entries: Vc, - visited_modules: Vc, + entries: ResolvedVc, + visited_modules: OperationVc, include_traced: bool, include_binding_usage: bool, ) -> Result> { SingleModuleGraph::new_inner( - &*entries.await?, - &visited_modules.await?.modules, + entries.owned().await?, + &visited_modules.connect().await?.modules, include_traced, include_binding_usage, ) .await } - #[turbo_tasks::function] + #[turbo_tasks::function(operation)] pub async fn new_with_entries_visited_intern( // This must not be a Vc> to ensure layout segment optimization hits the cache entries: GraphEntriesT, - visited_modules: Vc, + visited_modules: OperationVc, include_traced: bool, include_binding_usage: bool, ) -> Result> { SingleModuleGraph::new_inner( - &entries, - &visited_modules.await?.modules, + entries, + &visited_modules.connect().await?.modules, include_traced, include_binding_usage, ) @@ -1671,8 +1714,8 @@ pub mod tests { ident::AssetIdent, module::{Module, ModuleSideEffects}, module_graph::{ - GraphEntries, GraphTraversalAction, ModuleGraph, ModuleGraphRef, SingleModuleGraph, - VisitedModules, chunk_group_info::ChunkGroupEntry, + GraphEntries, GraphTraversalAction, ModuleGraph, SingleModuleGraph, VisitedModules, + chunk_group_info::ChunkGroupEntry, }, reference::{ModuleReference, ModuleReferences, SingleChunkableModuleReference}, resolve::ExportUsage, @@ -1999,7 +2042,7 @@ pub mod tests { let b_module = make_module("b.js").await?; let parent_graph = SingleModuleGraph::new_with_entries( - GraphEntries::cell(GraphEntries(vec![ChunkGroupEntry::Entry(vec![b_module])])), + ResolvedVc::cell(vec![ChunkGroupEntry::Entry(vec![b_module])]), false, false, ); @@ -2007,14 +2050,21 @@ pub mod tests { let module_graph = ModuleGraph::from_graphs(vec![ parent_graph, SingleModuleGraph::new_with_entries_visited( - GraphEntries::cell(GraphEntries(vec![ChunkGroupEntry::Entry(vec![a_module])])), + ResolvedVc::cell(vec![ChunkGroupEntry::Entry(vec![a_module])]), VisitedModules::from_graph(parent_graph), false, false, ), ]) - .await?; - let child_graph = module_graph.iter_graphs().nth(1).unwrap().read().await?; + .connect(); + let child_graph = module_graph + .iter_graphs() + .await? + .iter() + .nth(1) + .unwrap() + .connect() + .await?; // test traversing forward from a in the child graph { let mut visited_forward = Vec::new(); @@ -2200,7 +2250,7 @@ pub mod tests { entries: Vec, graph: FxHashMap>, test_fn: impl FnOnce( - ModuleGraphRef, + &ModuleGraph, Vec>>, FxHashMap>, RcStr>, ) -> Result<()> @@ -2236,7 +2286,7 @@ pub mod tests { .try_join() .await?; let graph = SingleModuleGraph::new_with_entries( - GraphEntries::cell(GraphEntries(vec![ChunkGroupEntry::Entry( + GraphEntries::resolved_cell(GraphEntries(vec![ChunkGroupEntry::Entry( entry_modules.clone(), )])), false, @@ -2247,6 +2297,7 @@ pub mod tests { // Technically they could always pull this name off of the // `module.ident().await?.path.path` themselves but you cannot `await` in visitors. let module_to_name = graph + .connect() .await? .modules .keys() @@ -2256,7 +2307,7 @@ pub mod tests { .into_iter() .collect(); test_fn( - ModuleGraph::from_single_graph(graph).read_graphs().await?, + &*ModuleGraph::from_single_graph(graph).connect().await?, entry_modules, module_to_name, ) diff --git a/turbopack/crates/turbopack-core/src/module_graph/module_batches.rs b/turbopack/crates/turbopack-core/src/module_graph/module_batches.rs index 686ce61f9d208..708cf74c55304 100644 --- a/turbopack/crates/turbopack-core/src/module_graph/module_batches.rs +++ b/turbopack/crates/turbopack-core/src/module_graph/module_batches.rs @@ -21,7 +21,7 @@ use crate::{ chunk::{ChunkableModule, ChunkingType}, module::Module, module_graph::{ - GraphTraversalAction, ModuleGraph, ModuleGraphRef, + GraphTraversalAction, ModuleGraph, chunk_group_info::{ChunkGroupInfo, ChunkGroupKey, RoaringBitmapWrapper}, module_batch::{ModuleBatch, ModuleBatchGroup, ModuleOrBatch}, traced_di_graph::{TracedDiGraph, iter_neighbors_rev}, @@ -281,7 +281,7 @@ impl PreBatches { &mut self, entry: ResolvedVc>, chunk_group_info: &ChunkGroupInfo, - module_graph: &ModuleGraphRef, + module_graph: &ModuleGraph, queue: &mut VecDeque<(ResolvedVc>, PreBatchIndex)>, ) -> Result> { let mut state = TraversalState { @@ -349,7 +349,7 @@ pub async fn compute_module_batches( let span = outer_span.clone(); async move { let chunk_group_info = module_graph.chunk_group_info().await?; - let module_graph = module_graph.read_graphs().await?; + let module_graph = module_graph.await?; let mut pre_batches = PreBatches::new(); diff --git a/turbopack/crates/turbopack-core/src/module_graph/side_effect_module_info.rs b/turbopack/crates/turbopack-core/src/module_graph/side_effect_module_info.rs index b5d267d9cc0b4..2034fbdd24eca 100644 --- a/turbopack/crates/turbopack-core/src/module_graph/side_effect_module_info.rs +++ b/turbopack/crates/turbopack-core/src/module_graph/side_effect_module_info.rs @@ -4,7 +4,7 @@ use turbo_tasks::{ResolvedVc, TryJoinIterExt, Vc}; use crate::{ module::{Module, ModuleSideEffects}, - module_graph::{GraphTraversalAction, ModuleGraph, SingleModuleGraphWithBindingUsage}, + module_graph::{GraphTraversalAction, ModuleGraph, ModuleGraphLayer}, }; /// This lists all the modules that are side effect free @@ -29,21 +29,19 @@ pub async fn compute_side_effect_free_module_info( // Layout segment optimization, we can individually compute the side effect free modules for // each graph. let mut result: Vc = Vc::cell(Default::default()); - let graphs = graphs.await?; - for graph in graphs.iter_graphs() { - result = compute_side_effect_free_module_info_single(graph, result); + for graph in graphs.iter_graphs().await? { + result = compute_side_effect_free_module_info_single(graph.connect(), result); } Ok(result) } #[turbo_tasks::function] async fn compute_side_effect_free_module_info_single( - graph: SingleModuleGraphWithBindingUsage, + graph: ResolvedVc, parent_side_effect_free_modules: Vc, ) -> Result> { let parent_side_effect_free_modules = parent_side_effect_free_modules.await?; - let graph = graph.read().await?; - + let graph = graph.await?; let module_side_effects = graph .enumerate_nodes() .map(async |(_, node)| { diff --git a/turbopack/crates/turbopack-node/src/transforms/postcss.rs b/turbopack/crates/turbopack-node/src/transforms/postcss.rs index 2f58b7991ad18..673573e3bb8f3 100644 --- a/turbopack/crates/turbopack-node/src/transforms/postcss.rs +++ b/turbopack/crates/turbopack-node/src/transforms/postcss.rs @@ -16,7 +16,7 @@ use turbopack_core::{ context::{AssetContext, ProcessResult}, file_source::FileSource, ident::AssetIdent, - module_graph::ModuleGraph, + module_graph::{ModuleGraph, SingleModuleGraph}, reference_type::{EntryReferenceSubType, InnerAssets, ReferenceType}, resolve::{FindContextFileResult, find_context_file_or_package_key, options::ImportMapping}, source::Source, @@ -501,9 +501,14 @@ impl PostCssTransformedAsset { .to_resolved() .await?; - let module_graph = ModuleGraph::from_modules(entries.graph_entries(), false, false) - .to_resolved() - .await?; + let module_graph = ModuleGraph::from_single_graph(SingleModuleGraph::new_with_entries( + entries.graph_entries().to_resolved().await?, + false, + false, + )) + .connect() + .to_resolved() + .await?; let css_fs_path = self.source.ident().path(); diff --git a/turbopack/crates/turbopack-node/src/transforms/webpack.rs b/turbopack/crates/turbopack-node/src/transforms/webpack.rs index 7b3e2b928e9a4..5d1b6d7bfdfa7 100644 --- a/turbopack/crates/turbopack-node/src/transforms/webpack.rs +++ b/turbopack/crates/turbopack-node/src/transforms/webpack.rs @@ -30,7 +30,7 @@ use turbopack_core::{ Issue, IssueExt, IssueSeverity, IssueSource, IssueStage, OptionIssueSource, OptionStyledString, StyledString, }, - module_graph::ModuleGraph, + module_graph::{ModuleGraph, SingleModuleGraph}, reference_type::{InnerAssets, ReferenceType}, resolve::{ options::{ConditionValue, ResolveInPackage, ResolveIntoPackage, ResolveOptions}, @@ -257,9 +257,14 @@ impl WebpackLoadersProcessedAsset { .to_resolved() .await?; - let module_graph = ModuleGraph::from_modules(entries.graph_entries(), false, false) - .to_resolved() - .await?; + let module_graph = ModuleGraph::from_single_graph(SingleModuleGraph::new_with_entries( + entries.graph_entries().to_resolved().await?, + false, + false, + )) + .connect() + .to_resolved() + .await?; let resource_fs_path = self.source.ident().path().await?; let Some(resource_path) = project_path.get_relative_path_to(&resource_fs_path) else { diff --git a/turbopack/crates/turbopack-tests/tests/execution.rs b/turbopack/crates/turbopack-tests/tests/execution.rs index 27fc5a43d7d2f..7fe8566e73039 100644 --- a/turbopack/crates/turbopack-tests/tests/execution.rs +++ b/turbopack/crates/turbopack-tests/tests/execution.rs @@ -38,7 +38,9 @@ use turbopack_core::{ file_source::FileSource, ident::Layer, issue::CollectibleIssuesExt, - module_graph::{ModuleGraph, binding_usage_info::compute_binding_usage_info}, + module_graph::{ + ModuleGraph, SingleModuleGraph, binding_usage_info::compute_binding_usage_info, + }, reference_type::{InnerAssets, ReferenceType}, resolve::{ ExternalTraced, ExternalType, @@ -479,23 +481,28 @@ async fn run_test_operation(prepared_test: ResolvedVc) -> Result) -> Result Result> { bail!("Entry module is not chunkable, so it can't be used to bootstrap the application") }; - let mut module_graph = ModuleGraph::from_modules( - Vc::cell(vec![ChunkGroupEntry::Entry(entry_modules.clone())]), + let single_graph = SingleModuleGraph::new_with_entries( + ResolvedVc::cell(vec![ChunkGroupEntry::Entry(entry_modules.clone())]), false, true, ); + let mut module_graph = ModuleGraph::from_single_graph(single_graph); let binding_usage = if options.remove_unused_imports || options.remove_unused_exports { - Some( - compute_binding_usage_info( - module_graph.to_resolved().await?, - options.remove_unused_imports, - ) - .resolve_strongly_consistent() - .await?, - ) + Some(compute_binding_usage_info( + module_graph, + options.remove_unused_imports, + )) } else { None }; - if options.remove_unused_imports { - module_graph = module_graph.without_unused_references(*binding_usage.unwrap()); + if options.remove_unused_imports + && let Some(binding_usage) = binding_usage + { + module_graph = + ModuleGraph::from_single_graph_without_unused_references(single_graph, binding_usage); } + let module_graph = module_graph.connect(); let chunk_root_path = project_path.join("output")?; let static_root_path = project_path.join("static")?; @@ -474,11 +475,11 @@ async fn run_test_operation(resource: RcStr) -> Result> { ) .minify_type(options.minify_type) .module_merging(options.scope_hoisting) - .export_usage( - options - .remove_unused_exports - .then(|| binding_usage.unwrap()), - ) + .export_usage(if options.remove_unused_exports { + Some(binding_usage.unwrap().connect().to_resolved().await?) + } else { + None + }) .debug_ids(options.enable_debug_ids) .source_map_source_type(options.source_map_source_type); @@ -486,6 +487,7 @@ async fn run_test_operation(resource: RcStr) -> Result> { builder = builder.unused_references( binding_usage .unwrap() + .connect() .unused_references() .to_resolved() .await?, @@ -520,11 +522,11 @@ async fn run_test_operation(resource: RcStr) -> Result> { ) .minify_type(options.minify_type) .module_merging(options.scope_hoisting) - .export_usage( - options - .remove_unused_exports - .then(|| binding_usage.unwrap()), - ) + .export_usage(if options.remove_unused_exports { + Some(binding_usage.unwrap().connect().to_resolved().await?) + } else { + None + }) .debug_ids(options.enable_debug_ids) .source_map_source_type(options.source_map_source_type); @@ -532,6 +534,7 @@ async fn run_test_operation(resource: RcStr) -> Result> { builder = builder.unused_references( binding_usage .unwrap() + .connect() .unused_references() .to_resolved() .await?, diff --git a/turbopack/crates/turbopack/src/global_module_ids.rs b/turbopack/crates/turbopack/src/global_module_ids.rs index d800e5eca15ac..f1b53ea6a7e0f 100644 --- a/turbopack/crates/turbopack/src/global_module_ids.rs +++ b/turbopack/crates/turbopack/src/global_module_ids.rs @@ -19,7 +19,7 @@ pub async fn get_global_module_id_strategy( ) -> Result> { let span = tracing::info_span!("compute module id map"); async move { - let module_graph = module_graph.read_graphs().await?; + let module_graph = module_graph.await?; let graphs = &module_graph.graphs; // All modules in the graph