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, RequestKey},
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/// A reference that always resolves to a single module.
60#[turbo_tasks::value]
61#[derive(ValueToString)]
62#[value_to_string(self.description)]
63pub struct SingleModuleReference {
64    asset: ResolvedVc<Box<dyn Module>>,
65    description: RcStr,
66}
67
68#[turbo_tasks::value_impl]
69impl ModuleReference for SingleModuleReference {
70    #[turbo_tasks::function]
71    fn resolve_reference(&self) -> Vc<ModuleResolveResult> {
72        *ModuleResolveResult::module(self.asset)
73    }
74}
75
76#[turbo_tasks::value_impl]
77impl SingleModuleReference {
78    /// Create a new [Vc<SingleModuleReference>] that resolves to the given
79    /// asset.
80    #[turbo_tasks::function]
81    pub fn new(asset: ResolvedVc<Box<dyn Module>>, description: RcStr) -> Vc<Self> {
82        Self::cell(SingleModuleReference { asset, description })
83    }
84
85    /// The [Vc<Box<dyn Asset>>] that this reference resolves to.
86    #[turbo_tasks::function]
87    pub fn asset(&self) -> Vc<Box<dyn Module>> {
88        *self.asset
89    }
90}
91
92#[turbo_tasks::value]
93#[derive(ValueToString)]
94#[value_to_string(self.description)]
95pub struct SingleChunkableModuleReference {
96    asset: ResolvedVc<Box<dyn Module>>,
97    description: RcStr,
98    export: ExportUsage,
99}
100
101#[turbo_tasks::value_impl]
102impl SingleChunkableModuleReference {
103    #[turbo_tasks::function]
104    pub async fn new(
105        asset: ResolvedVc<Box<dyn Module>>,
106        description: RcStr,
107        export: Vc<ExportUsage>,
108    ) -> Result<Vc<Self>> {
109        Ok(Self::cell(SingleChunkableModuleReference {
110            asset,
111            description,
112            export: export.owned().await?,
113        }))
114    }
115}
116
117#[turbo_tasks::value_impl]
118impl ModuleReference for SingleChunkableModuleReference {
119    #[turbo_tasks::function]
120    fn resolve_reference(&self) -> Vc<ModuleResolveResult> {
121        *ModuleResolveResult::module(self.asset)
122    }
123
124    fn chunking_type(&self) -> Option<ChunkingType> {
125        Some(ChunkingType::Parallel {
126            inherit_async: true,
127            hoisted: false,
128        })
129    }
130
131    fn binding_usage(&self) -> BindingUsage {
132        BindingUsage {
133            import: ImportUsage::TopLevel,
134            export: self.export.clone(),
135        }
136    }
137}
138
139/// A reference that always resolves to a single module.
140#[turbo_tasks::value]
141#[derive(ValueToString)]
142#[value_to_string(self.description)]
143pub struct SingleOutputAssetReference {
144    asset: ResolvedVc<Box<dyn OutputAsset>>,
145    description: RcStr,
146}
147
148#[turbo_tasks::value_impl]
149impl ModuleReference for SingleOutputAssetReference {
150    #[turbo_tasks::function]
151    fn resolve_reference(&self) -> Vc<ModuleResolveResult> {
152        *ModuleResolveResult::output_asset(RequestKey::default(), self.asset)
153    }
154}
155
156#[turbo_tasks::value_impl]
157impl SingleOutputAssetReference {
158    /// Create a new [Vc<SingleOutputAssetReference>] that resolves to the given
159    /// asset.
160    #[turbo_tasks::function]
161    pub fn new(asset: ResolvedVc<Box<dyn OutputAsset>>, description: RcStr) -> Vc<Self> {
162        Self::cell(SingleOutputAssetReference { asset, description })
163    }
164
165    /// The [Vc<Box<dyn Asset>>] that this reference resolves to.
166    #[turbo_tasks::function]
167    pub fn asset(&self) -> Vc<Box<dyn OutputAsset>> {
168        *self.asset
169    }
170}
171
172/// Aggregates all [Module]s referenced by an [Module]. [ModuleReference]
173/// This does not include transitively references [Module]s, but it includes
174/// primary and secondary [Module]s referenced.
175///
176/// [Module]: crate::module::Module
177#[turbo_tasks::function]
178pub async fn referenced_modules_and_affecting_sources(
179    module: Vc<Box<dyn Module>>,
180) -> Result<Vc<Modules>> {
181    let references = module.references().await?;
182
183    let resolved_references = references
184        .iter()
185        .map(|r| r.resolve_reference())
186        .try_join()
187        .await?;
188    let mut modules = Vec::new();
189    for resolve_result in resolved_references {
190        modules.extend(resolve_result.primary_modules_raw_iter());
191        modules.extend(
192            resolve_result
193                .affecting_sources_iter()
194                .map(|source| async move {
195                    Ok(ResolvedVc::upcast(
196                        RawModule::new(*source).to_resolved().await?,
197                    ))
198                })
199                .try_join()
200                .await?,
201        );
202    }
203
204    let resolved_modules: FxIndexSet<_> = modules.into_iter().collect();
205
206    Ok(Vc::cell(resolved_modules.into_iter().collect()))
207}
208
209#[turbo_tasks::value]
210#[derive(ValueToString)]
211#[value_to_string("traced {}", self.module.ident())]
212pub struct TracedModuleReference {
213    module: ResolvedVc<Box<dyn Module>>,
214}
215
216#[turbo_tasks::value_impl]
217impl ModuleReference for TracedModuleReference {
218    #[turbo_tasks::function]
219    fn resolve_reference(&self) -> Vc<ModuleResolveResult> {
220        *ModuleResolveResult::module(self.module)
221    }
222
223    fn chunking_type(&self) -> Option<ChunkingType> {
224        Some(ChunkingType::Traced)
225    }
226}
227
228#[turbo_tasks::value_impl]
229impl TracedModuleReference {
230    #[turbo_tasks::function]
231    pub fn new(module: ResolvedVc<Box<dyn Module>>) -> Vc<Self> {
232        Self::cell(TracedModuleReference { module })
233    }
234}
235
236/// Aggregates all primary [Module]s referenced by an [Module]. [AssetReference]
237/// This does not include transitively references [Module]s, only includes
238/// primary [Module]s referenced.
239///
240/// [Module]: crate::module::Module
241#[turbo_tasks::function]
242pub async fn primary_referenced_modules(module: Vc<Box<dyn Module>>) -> Result<Vc<Modules>> {
243    let mut set = HashSet::new();
244    let modules = module
245        .references()
246        .await?
247        .iter()
248        .map(|reference| async {
249            reference
250                .resolve_reference()
251                .resolve()
252                .await?
253                .primary_modules()
254                .owned()
255                .await
256        })
257        .try_join()
258        .await?
259        .into_iter()
260        .flatten()
261        .filter(|&module| set.insert(module))
262        .collect();
263    Ok(Vc::cell(modules))
264}
265
266#[derive(Clone, Eq, PartialEq, ValueDebugFormat, TraceRawVcs, NonLocalValue, Encode, Decode)]
267pub struct ResolvedReference {
268    pub chunking_type: ChunkingType,
269    pub binding_usage: BindingUsage,
270    pub modules: Vec<ResolvedVc<Box<dyn Module>>>,
271}
272
273#[turbo_tasks::value(transparent)]
274pub struct ModulesWithRefData(Vec<(ResolvedVc<Box<dyn ModuleReference>>, ResolvedReference)>);
275
276/// Aggregates all primary [Module]s referenced by an [Module] via [ModuleReference]s with a
277/// non-empty chunking_type. This does not include transitively referenced [Module]s, only primary
278/// [Module]s referenced.
279///
280/// [Module]: crate::module::Module
281#[turbo_tasks::function]
282pub async fn primary_chunkable_referenced_modules(
283    module: ResolvedVc<Box<dyn Module>>,
284    include_traced: bool,
285    include_binding_usage: bool,
286) -> Result<Vc<ModulesWithRefData>> {
287    let modules = module
288        .references()
289        .await?
290        .iter()
291        .map(|reference| async {
292            let trait_ref = reference.into_trait_ref().await?;
293            if let Some(chunking_type) = &trait_ref.chunking_type() {
294                if !include_traced && matches!(chunking_type, ChunkingType::Traced) {
295                    return Ok(None);
296                }
297
298                let resolved = reference
299                    .resolve_reference()
300                    .await?
301                    .primary_modules_ref()
302                    .await?;
303                let binding_usage = if include_binding_usage {
304                    trait_ref.binding_usage()
305                } else {
306                    BindingUsage::default()
307                };
308
309                return Ok(Some((
310                    *reference,
311                    ResolvedReference {
312                        chunking_type: chunking_type.clone(),
313                        binding_usage,
314                        modules: resolved,
315                    },
316                )));
317            }
318            Ok(None)
319        })
320        .try_flat_join()
321        .await?;
322    Ok(Vc::cell(modules))
323}
324
325/// Walks the asset graph from multiple assets and collect all referenced
326/// assets.
327#[turbo_tasks::function]
328pub async fn all_assets_from_entries(
329    entries: Vc<OutputAssets>,
330) -> Result<Vc<ExpandedOutputAssets>> {
331    Ok(Vc::cell(
332        expand_output_assets(
333            entries
334                .await?
335                .into_iter()
336                .map(|&asset| ExpandOutputAssetsInput::Asset(asset)),
337            true,
338        )
339        .await?,
340    ))
341}
342
343/// Walks the asset graph from multiple assets and collect all referenced
344/// assets.
345#[turbo_tasks::function]
346pub async fn all_assets_from_entry(
347    entry: ResolvedVc<Box<dyn OutputAsset>>,
348) -> Result<Vc<ExpandedOutputAssets>> {
349    Ok(Vc::cell(
350        expand_output_assets(std::iter::once(ExpandOutputAssetsInput::Asset(entry)), true).await?,
351    ))
352}