turbopack_core/module_graph/
async_module_info.rs1use anyhow::Result;
2use rustc_hash::FxHashSet;
3use turbo_tasks::{ResolvedVc, TryJoinIterExt, Vc};
4
5use crate::{
6 module::{Module, Modules},
7 module_graph::{GraphTraversalAction, ModuleGraph, SingleModuleGraph},
8};
9
10#[turbo_tasks::value(transparent)]
11pub struct ModulesSet(FxHashSet<ResolvedVc<Box<dyn Module>>>);
12
13#[turbo_tasks::value(transparent)]
16pub struct AsyncModulesInfo(FxHashSet<ResolvedVc<Box<dyn Module>>>);
17
18#[turbo_tasks::value_impl]
19impl AsyncModulesInfo {
20 #[turbo_tasks::function]
21 pub fn is_async(&self, module: ResolvedVc<Box<dyn Module>>) -> Vc<bool> {
22 Vc::cell(self.0.contains(&module))
23 }
24
25 #[turbo_tasks::function]
26 pub async fn is_async_multiple(&self, modules: ResolvedVc<Modules>) -> Result<Vc<ModulesSet>> {
27 Ok(Vc::cell(
28 modules
29 .await?
30 .iter()
31 .copied()
32 .filter(|m| self.0.contains(m))
33 .collect(),
34 ))
35 }
36}
37
38#[turbo_tasks::function(operation)]
39pub async fn compute_async_module_info(
40 graph: ResolvedVc<ModuleGraph>,
41) -> Result<Vc<AsyncModulesInfo>> {
42 let mut result: Vc<AsyncModulesInfo> = Vc::cell(Default::default());
44 for g in &graph.await?.graphs {
45 result = compute_async_module_info_single(**g, result);
46 }
47 Ok(result)
48}
49
50#[turbo_tasks::function]
51async fn compute_async_module_info_single(
52 graph: Vc<SingleModuleGraph>,
53 parent_async_modules: Vc<AsyncModulesInfo>,
54) -> Result<Vc<AsyncModulesInfo>> {
55 let parent_async_modules = parent_async_modules.await?;
56 let graph = graph.await?;
57
58 let self_async_modules = graph
59 .iter_nodes()
60 .map(async |node| Ok((node.module, *node.module.is_self_async().await?)))
61 .try_join()
62 .await?
63 .into_iter()
64 .flat_map(|(k, v)| v.then_some(k))
65 .chain(parent_async_modules.iter().copied())
66 .collect::<FxHashSet<_>>();
67
68 let mut async_modules = self_async_modules;
76 graph.traverse_edges_from_entries_topological(
77 graph.entry_modules(),
78 &mut (),
79 |_, _, _| Ok(GraphTraversalAction::Continue),
80 |parent_info, module, _| {
81 let Some((parent_module, chunking_type)) = parent_info else {
82 return;
84 };
85 let module = module.module();
86 let parent_module = parent_module.module;
87
88 if chunking_type.is_inherit_async() && async_modules.contains(&module) {
89 async_modules.insert(parent_module);
90 }
91 },
92 )?;
93
94 graph.traverse_cycles(
95 |ty| ty.is_inherit_async(),
96 |cycle| {
97 if cycle
98 .iter()
99 .any(|node| async_modules.contains(&node.module))
100 {
101 for &node in cycle {
102 async_modules.insert(node.module);
103 }
104 }
105 },
106 );
107
108 Ok(Vc::cell(async_modules))
109}