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},
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)]
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)]
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 .enumerate_nodes()
48 .map(async |(_, node)| {
49 Ok(match node {
50 super::SingleModuleGraphNode::Module(node) => {
51 node.is_self_async().await?.then_some(*node)
52 }
53 super::SingleModuleGraphNode::VisitedModule { idx: _, module } => {
54 parent_async_modules
57 .as_ref()
58 .is_some_and(|set| set.contains(module))
59 .then_some(*module)
60 }
61 })
62 })
63 .try_flat_join()
64 .await?;
65
66 let mut async_modules = FxHashSet::default();
71 async_modules.extend(self_async_modules.iter());
72
73 graph.traverse_edges_reverse_dfs(
74 self_async_modules,
75 &mut (),
76 |child, parent, _state| {
79 Ok(if let Some((_, edge)) = child {
80 if edge.chunking_type.is_inherit_async() {
81 async_modules.insert(parent);
82 GraphTraversalAction::Continue
83 } else {
84 GraphTraversalAction::Exclude
86 }
87 } else {
88 GraphTraversalAction::Continue
90 })
91 },
92 |_, _, _| Ok(()),
93 )?;
94
95 async_modules.extend(parent_async_modules.into_iter().flatten());
97
98 Ok(Vc::cell(async_modules))
99}