Skip to main content

turbopack_core/reference/
mod.rs

1use std::collections::HashSet;
2
3use anyhow::Result;
4use bincode::{Decode, Encode};
5use turbo_rcstr::RcStr;
6use turbo_tasks::{
7    FxIndexSet, NonLocalValue, ResolvedVc, TryFlatJoinIterExt, TryJoinIterExt, ValueToString, Vc,
8    debug::ValueDebugFormat, trace::TraceRawVcs,
9};
10
11use crate::{
12    chunk::ChunkingType,
13    module::{Module, Modules},
14    output::{
15        ExpandOutputAssetsInput, ExpandedOutputAssets, OutputAsset, OutputAssets,
16        expand_output_assets,
17    },
18    raw_module::RawModule,
19    resolve::{BindingUsage, ExportUsage, ImportUsage, ModuleResolveResult},
20};
21pub mod source_map;
22
23pub use source_map::SourceMapReference;
24
25/// A reference to one or multiple [Module]s, [OutputAsset]s or other special
26/// things.
27///
28/// [Module]: crate::module::Module
29/// [OutputAsset]: crate::output::OutputAsset
30#[turbo_tasks::value_trait]
31pub trait ModuleReference: ValueToString {
32    #[turbo_tasks::function]
33    fn resolve_reference(self: Vc<Self>) -> Vc<ModuleResolveResult>;
34    // TODO think about different types
35    // fn kind(&self) -> Vc<AssetReferenceType>;
36
37    fn chunking_type(&self) -> Option<ChunkingType> {
38        None
39    }
40
41    fn binding_usage(&self) -> BindingUsage {
42        BindingUsage::default()
43    }
44}
45
46/// Multiple [ModuleReference]s
47#[turbo_tasks::value(transparent)]
48pub struct ModuleReferences(Vec<ResolvedVc<Box<dyn ModuleReference>>>);
49
50#[turbo_tasks::value_impl]
51impl ModuleReferences {
52    /// An empty list of [ModuleReference]s
53    #[turbo_tasks::function]
54    pub fn empty() -> Vc<Self> {
55        Vc::cell(Vec::new())
56    }
57}
58
59#[turbo_tasks::value]
60#[derive(ValueToString)]
61#[value_to_string(self.description)]
62pub struct SingleChunkableModuleReference {
63    asset: ResolvedVc<Box<dyn Module>>,
64    description: RcStr,
65    export: ExportUsage,
66}
67
68#[turbo_tasks::value_impl]
69impl SingleChunkableModuleReference {
70    #[turbo_tasks::function]
71    pub async fn new(
72        asset: ResolvedVc<Box<dyn Module>>,
73        description: RcStr,
74        export: Vc<ExportUsage>,
75    ) -> Result<Vc<Self>> {
76        Ok(Self::cell(SingleChunkableModuleReference {
77            asset,
78            description,
79            export: export.owned().await?,
80        }))
81    }
82}
83
84#[turbo_tasks::value_impl]
85impl ModuleReference for SingleChunkableModuleReference {
86    #[turbo_tasks::function]
87    fn resolve_reference(&self) -> Vc<ModuleResolveResult> {
88        *ModuleResolveResult::module(self.asset)
89    }
90
91    fn chunking_type(&self) -> Option<ChunkingType> {
92        Some(ChunkingType::Parallel {
93            inherit_async: true,
94            hoisted: false,
95        })
96    }
97
98    fn binding_usage(&self) -> BindingUsage {
99        BindingUsage {
100            import: ImportUsage::TopLevel,
101            export: self.export.clone(),
102        }
103    }
104}
105
106/// Aggregates all [Module]s referenced by an [Module]. [ModuleReference]
107/// This does not include transitively references [Module]s, but it includes
108/// primary and secondary [Module]s referenced.
109///
110/// [Module]: crate::module::Module
111#[turbo_tasks::function]
112pub async fn referenced_modules_and_affecting_sources(
113    module: Vc<Box<dyn Module>>,
114) -> Result<Vc<Modules>> {
115    let references = module.references().await?;
116
117    let resolved_references = references
118        .iter()
119        .map(|r| r.resolve_reference())
120        .try_join()
121        .await?;
122    let mut modules = Vec::new();
123    for resolve_result in resolved_references {
124        modules.extend(resolve_result.primary_modules_raw_iter());
125        modules.extend(
126            resolve_result
127                .affecting_sources_iter()
128                .map(|source| async move {
129                    Ok(ResolvedVc::upcast(
130                        RawModule::new(*source).to_resolved().await?,
131                    ))
132                })
133                .try_join()
134                .await?,
135        );
136    }
137
138    let resolved_modules: FxIndexSet<_> = modules.into_iter().collect();
139
140    Ok(Vc::cell(resolved_modules.into_iter().collect()))
141}
142
143#[turbo_tasks::value]
144#[derive(ValueToString)]
145#[value_to_string("traced {}", self.module.ident())]
146pub struct TracedModuleReference {
147    module: ResolvedVc<Box<dyn Module>>,
148}
149
150#[turbo_tasks::value_impl]
151impl ModuleReference for TracedModuleReference {
152    #[turbo_tasks::function]
153    fn resolve_reference(&self) -> Vc<ModuleResolveResult> {
154        *ModuleResolveResult::module(self.module)
155    }
156
157    fn chunking_type(&self) -> Option<ChunkingType> {
158        Some(ChunkingType::Traced)
159    }
160}
161
162#[turbo_tasks::value_impl]
163impl TracedModuleReference {
164    #[turbo_tasks::function]
165    pub fn new(module: ResolvedVc<Box<dyn Module>>) -> Vc<Self> {
166        Self::cell(TracedModuleReference { module })
167    }
168}
169
170/// Aggregates all primary [`Module`]s referenced by an [`Module`]. This does not include
171/// transitively references [`Module`]s, only includes primary [`Module`]s referenced.
172///
173/// [`Module`]: crate::module::Module
174#[turbo_tasks::function]
175pub async fn primary_referenced_modules(module: Vc<Box<dyn Module>>) -> Result<Vc<Modules>> {
176    let mut set = HashSet::new();
177    let modules = module
178        .references()
179        .await?
180        .iter()
181        .map(|reference| async {
182            reference
183                .resolve_reference()
184                .to_resolved()
185                .await?
186                .primary_modules()
187                .owned()
188                .await
189        })
190        .try_join()
191        .await?
192        .into_iter()
193        .flatten()
194        .filter(|&module| set.insert(module))
195        .collect();
196    Ok(Vc::cell(modules))
197}
198
199#[derive(Clone, Eq, PartialEq, ValueDebugFormat, TraceRawVcs, NonLocalValue, Encode, Decode)]
200pub struct ResolvedReference {
201    pub chunking_type: ChunkingType,
202    pub binding_usage: BindingUsage,
203    pub modules: Vec<ResolvedVc<Box<dyn Module>>>,
204}
205
206#[turbo_tasks::value(transparent)]
207pub struct ModulesWithRefData(Vec<(ResolvedVc<Box<dyn ModuleReference>>, ResolvedReference)>);
208
209/// Aggregates all primary [Module]s referenced by an [Module] via [ModuleReference]s with a
210/// non-empty chunking_type. This does not include transitively referenced [Module]s, only primary
211/// [Module]s referenced.
212///
213/// [Module]: crate::module::Module
214#[turbo_tasks::function]
215pub async fn primary_chunkable_referenced_modules(
216    module: ResolvedVc<Box<dyn Module>>,
217    include_traced: bool,
218    include_binding_usage: bool,
219) -> Result<Vc<ModulesWithRefData>> {
220    let modules = module
221        .references()
222        .await?
223        .iter()
224        .map(|reference| async {
225            let trait_ref = reference.into_trait_ref().await?;
226            if let Some(chunking_type) = &trait_ref.chunking_type() {
227                if !include_traced && matches!(chunking_type, ChunkingType::Traced) {
228                    return Ok(None);
229                }
230
231                let resolved = reference
232                    .resolve_reference()
233                    .await?
234                    .primary_modules_ref()
235                    .await?;
236                let binding_usage = if include_binding_usage {
237                    trait_ref.binding_usage()
238                } else {
239                    BindingUsage::default()
240                };
241
242                return Ok(Some((
243                    *reference,
244                    ResolvedReference {
245                        chunking_type: chunking_type.clone(),
246                        binding_usage,
247                        modules: resolved,
248                    },
249                )));
250            }
251            Ok(None)
252        })
253        .try_flat_join()
254        .await?;
255    Ok(Vc::cell(modules))
256}
257
258/// Walks the asset graph from multiple assets and collect all referenced
259/// assets.
260#[turbo_tasks::function]
261pub async fn all_assets_from_entries(
262    entries: Vc<OutputAssets>,
263) -> Result<Vc<ExpandedOutputAssets>> {
264    Ok(Vc::cell(
265        expand_output_assets(
266            entries
267                .await?
268                .into_iter()
269                .map(|&asset| ExpandOutputAssetsInput::Asset(asset)),
270            true,
271        )
272        .await?,
273    ))
274}
275
276/// Walks the asset graph from multiple assets and collect all referenced
277/// assets.
278#[turbo_tasks::function]
279pub async fn all_assets_from_entry(
280    entry: ResolvedVc<Box<dyn OutputAsset>>,
281) -> Result<Vc<ExpandedOutputAssets>> {
282    Ok(Vc::cell(
283        expand_output_assets(std::iter::once(ExpandOutputAssetsInput::Asset(entry)), true).await?,
284    ))
285}