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)]
11pub struct ModulesSet(FxHashSet<ResolvedVc<Box<dyn Module>>>);
12
13#[turbo_tasks::value(transparent, cell = "keyed")]
16pub struct AsyncModulesInfo(FxHashSet<ResolvedVc<Box<dyn Module>>>);
17
18impl AsyncModulesInfo {
19 pub async fn is_async(self: Vc<Self>, module: ResolvedVc<Box<dyn Module>>) -> Result<bool> {
20 self.contains_key(&module).await
21 }
22}
23
24#[turbo_tasks::function(operation)]
25pub async fn compute_async_module_info(
26 graphs: ResolvedVc<ModuleGraph>,
27) -> Result<Vc<AsyncModulesInfo>> {
28 let mut result = None;
30 for graph in graphs.iter_graphs().await? {
31 result = Some(compute_async_module_info_single(*graph, result));
32 }
33 Ok(result
34 .context("There must be at least one single graph in the module graph")?
35 .connect())
36}
37
38#[turbo_tasks::function(operation)]
39async fn compute_async_module_info_single(
40 graph: OperationVc<ModuleGraphLayer>,
41 parent_async_modules: Option<OperationVc<AsyncModulesInfo>>,
42) -> Result<Vc<AsyncModulesInfo>> {
43 let parent_async_modules = if let Some(parent_async_modules) = parent_async_modules {
44 Some(parent_async_modules.read_strongly_consistent().await?)
45 } else {
46 None
47 };
48 let graph = graph.read_strongly_consistent().await?;
49 let self_async_modules = graph
50 .enumerate_nodes()
51 .map(async |(_, node)| {
52 Ok(match node {
53 super::SingleModuleGraphNode::Module(node) => {
54 node.is_self_async().await?.then_some(*node)
55 }
56 super::SingleModuleGraphNode::VisitedModule { idx: _, module } => {
57 parent_async_modules
60 .as_ref()
61 .is_some_and(|set| set.contains(module))
62 .then_some(*module)
63 }
64 })
65 })
66 .try_flat_join()
67 .await?;
68
69 let mut async_modules = FxHashSet::default();
74 async_modules.extend(self_async_modules.iter());
75
76 graph.traverse_edges_reverse_dfs(
77 self_async_modules,
78 &mut (),
79 |child, parent, _state| {
82 Ok(if let Some((_, edge)) = child {
83 if edge.chunking_type.is_inherit_async() {
84 async_modules.insert(parent);
85 GraphTraversalAction::Continue
86 } else {
87 GraphTraversalAction::Exclude
89 }
90 } else {
91 GraphTraversalAction::Continue
93 })
94 },
95 |_, _, _| Ok(()),
96 )?;
97
98 async_modules.extend(parent_async_modules.into_iter().flatten());
100
101 Ok(Vc::cell(async_modules))
102}