turbopack_core/module_graph/
async_module_info.rs1use anyhow::{Context, Result};
2use rustc_hash::FxHashSet;
3use turbo_tasks::{OperationVc, ResolvedVc, TryFlatJoinIterExt, Vc};
4
5use crate::{
6 module::Module,
7 module_graph::{GraphTraversalAction, ModuleGraph, ModuleGraphLayer, SingleModuleGraphNode},
8};
9
10#[turbo_tasks::value(transparent, cell = "keyed")]
13pub struct AsyncModulesInfo(FxHashSet<ResolvedVc<Box<dyn Module>>>);
14
15impl AsyncModulesInfo {
16 pub async fn is_async(self: Vc<Self>, module: ResolvedVc<Box<dyn Module>>) -> Result<bool> {
17 self.contains_key(&module).await
18 }
19}
20
21#[turbo_tasks::function(operation, root)]
22pub async fn compute_async_module_info(
23 graphs: ResolvedVc<ModuleGraph>,
24) -> Result<Vc<AsyncModulesInfo>> {
25 let mut result = None;
27 for graph in graphs.iter_graphs().await? {
28 result = Some(compute_async_module_info_single(*graph, result));
29 }
30 Ok(result
31 .context("There must be at least one single graph in the module graph")?
32 .connect())
33}
34
35#[turbo_tasks::function(operation, root)]
36async fn compute_async_module_info_single(
37 graph: OperationVc<ModuleGraphLayer>,
38 parent_async_modules: Option<OperationVc<AsyncModulesInfo>>,
39) -> Result<Vc<AsyncModulesInfo>> {
40 let parent_async_modules = if let Some(parent_async_modules) = parent_async_modules {
41 Some(parent_async_modules.read_strongly_consistent().await?)
42 } else {
43 None
44 };
45 let graph = graph.read_strongly_consistent().await?;
46 let self_async_modules = graph
47 .iter_reachable_nodes()?
48 .map(async |node| {
49 Ok(match node {
50 SingleModuleGraphNode::Module(node) => node.is_self_async().await?.then_some(*node),
51 SingleModuleGraphNode::VisitedModule { idx: _, module } => {
52 parent_async_modules
55 .as_ref()
56 .is_some_and(|set| set.contains(module))
57 .then_some(*module)
58 }
59 })
60 })
61 .try_flat_join()
62 .await?;
63
64 let mut async_modules = FxHashSet::default();
69 async_modules.extend(self_async_modules.iter());
70
71 graph.traverse_edges_reverse_dfs(
72 self_async_modules,
73 &mut (),
74 |child, parent, _state| {
77 Ok(if let Some((_, edge)) = child {
78 if edge.chunking_type.is_inherit_async() {
79 async_modules.insert(parent);
80 GraphTraversalAction::Continue
81 } else {
82 GraphTraversalAction::Exclude
84 }
85 } else {
86 GraphTraversalAction::Continue
88 })
89 },
90 |_, _, _| Ok(()),
91 )?;
92
93 async_modules.extend(parent_async_modules.into_iter().flatten());
95
96 Ok(Vc::cell(async_modules))
97}