turbopack_core/reference/
mod.rs1use std::collections::HashSet;
2
3use anyhow::Result;
4use bincode::{Decode, Encode};
5use turbo_rcstr::RcStr;
6use turbo_tasks::{
7 NonLocalValue, ResolvedVc, TryFlatJoinIterExt, TryJoinIterExt, ValueToString, Vc,
8 debug::ValueDebugFormat, trace::TraceRawVcs,
9};
10
11use crate::{
12 chunk::{ChunkingType, TracedMode},
13 issue::IssueSource,
14 module::{Module, Modules},
15 output::{
16 ExpandOutputAssetsInput, ExpandedOutputAssets, OutputAsset, OutputAssets,
17 expand_output_assets,
18 },
19 raw_module::RawModule,
20 resolve::{BindingUsage, ExportUsage, ImportUsage, ModuleResolveResult},
21};
22pub mod source_map;
23
24pub use source_map::SourceMapReference;
25
26#[turbo_tasks::value_trait]
32pub trait ModuleReference: ValueToString {
33 #[turbo_tasks::function]
34 fn resolve_reference(self: Vc<Self>) -> Vc<ModuleResolveResult>;
35 fn chunking_type(&self) -> Option<ChunkingType>;
39
40 fn binding_usage(&self) -> BindingUsage {
41 BindingUsage::default()
42 }
43
44 fn source(&self) -> Option<IssueSource> {
45 None
46 }
47}
48
49#[turbo_tasks::value_trait]
52pub trait DynamicTraceReference: ModuleReference {
53 fn origin_fn_name(&self) -> RcStr;
58}
59
60#[turbo_tasks::value(transparent)]
62pub struct ModuleReferences(Vec<ResolvedVc<Box<dyn ModuleReference>>>);
63
64#[turbo_tasks::value_impl]
65impl ModuleReferences {
66 #[turbo_tasks::function]
68 pub fn empty() -> Vc<Self> {
69 Vc::cell(Vec::new())
70 }
71}
72
73#[turbo_tasks::value]
74#[derive(ValueToString)]
75#[value_to_string(self.description)]
76pub struct SingleChunkableModuleReference {
77 asset: ResolvedVc<Box<dyn Module>>,
78 description: RcStr,
79 export: ExportUsage,
80}
81
82#[turbo_tasks::value_impl]
83impl SingleChunkableModuleReference {
84 #[turbo_tasks::function]
85 pub async fn new(
86 asset: ResolvedVc<Box<dyn Module>>,
87 description: RcStr,
88 export: Vc<ExportUsage>,
89 ) -> Result<Vc<Self>> {
90 Ok(Self::cell(SingleChunkableModuleReference {
91 asset,
92 description,
93 export: export.owned().await?,
94 }))
95 }
96}
97
98#[turbo_tasks::value_impl]
99impl ModuleReference for SingleChunkableModuleReference {
100 #[turbo_tasks::function]
101 fn resolve_reference(&self) -> Vc<ModuleResolveResult> {
102 *ModuleResolveResult::module(self.asset)
103 }
104
105 fn chunking_type(&self) -> Option<ChunkingType> {
106 Some(ChunkingType::Parallel {
107 inherit_async: true,
108 hoisted: false,
109 })
110 }
111
112 fn binding_usage(&self) -> BindingUsage {
113 BindingUsage {
114 import: ImportUsage::TopLevel,
115 export: self.export.clone(),
116 }
117 }
118}
119
120#[turbo_tasks::function]
126pub async fn referenced_modules_and_affecting_sources(
127 module: Vc<Box<dyn Module>>,
128 include_binding_usage: bool,
129) -> Result<Vc<ModulesWithRefData>> {
130 let modules = module
131 .references()
132 .await?
133 .iter()
134 .map(|reference| async {
135 let trait_ref = reference.into_trait_ref().await?;
136 let resolve_result = reference.resolve_reference().await?;
137 if let Some(chunking_type) = &trait_ref.chunking_type() {
138 let mut modules = resolve_result
139 .primary_modules_raw_iter()
140 .collect::<Vec<_>>();
141 modules.extend(
142 resolve_result
143 .affecting_sources_iter()
144 .map(|source| async move {
145 Ok(ResolvedVc::upcast(
146 RawModule::new(*source).to_resolved().await?,
147 ))
148 })
149 .try_join()
150 .await?,
151 );
152
153 let binding_usage = if include_binding_usage {
154 trait_ref.binding_usage()
155 } else {
156 BindingUsage::default()
157 };
158
159 return Ok(Some((
160 *reference,
161 ResolvedReference {
162 chunking_type: chunking_type.clone(),
163 binding_usage,
164 modules,
165 },
166 )));
167 }
168 Ok(None)
169 })
170 .try_flat_join()
171 .await?;
172 Ok(Vc::cell(modules))
173}
174
175#[turbo_tasks::value]
176#[derive(ValueToString)]
177#[value_to_string("traced {}", self.module.ident())]
178pub struct TracedModuleReference {
179 module: ResolvedVc<Box<dyn Module>>,
180 mode: TracedMode,
181}
182
183#[turbo_tasks::value_impl]
184impl ModuleReference for TracedModuleReference {
185 #[turbo_tasks::function]
186 fn resolve_reference(&self) -> Vc<ModuleResolveResult> {
187 *ModuleResolveResult::module(self.module)
188 }
189
190 fn chunking_type(&self) -> Option<ChunkingType> {
191 Some(ChunkingType::Traced { mode: self.mode })
192 }
193}
194
195#[turbo_tasks::value_impl]
196impl TracedModuleReference {
197 #[turbo_tasks::function]
198 pub fn new(module: ResolvedVc<Box<dyn Module>>, mode: TracedMode) -> Vc<Self> {
199 Self::cell(TracedModuleReference { module, mode })
200 }
201}
202
203#[turbo_tasks::function]
208pub async fn primary_referenced_modules(module: Vc<Box<dyn Module>>) -> Result<Vc<Modules>> {
209 let mut set = HashSet::new();
210 let modules = module
211 .references()
212 .await?
213 .iter()
214 .map(|reference| async { reference.resolve_reference().await?.primary_modules().await })
215 .try_join()
216 .await?
217 .into_iter()
218 .flatten()
219 .filter(|&module| set.insert(module))
220 .collect();
221 Ok(Vc::cell(modules))
222}
223
224#[derive(Clone, Eq, PartialEq, ValueDebugFormat, TraceRawVcs, NonLocalValue, Encode, Decode)]
225pub struct ResolvedReference {
226 pub chunking_type: ChunkingType,
227 pub binding_usage: BindingUsage,
228 pub modules: Vec<ResolvedVc<Box<dyn Module>>>,
229}
230
231#[turbo_tasks::value(transparent)]
232pub struct ModulesWithRefData(Vec<(ResolvedVc<Box<dyn ModuleReference>>, ResolvedReference)>);
233
234#[turbo_tasks::function]
240pub async fn primary_chunkable_referenced_modules(
241 module: ResolvedVc<Box<dyn Module>>,
242 include_traced: bool,
243 include_binding_usage: bool,
244) -> Result<Vc<ModulesWithRefData>> {
245 let modules = module
246 .references()
247 .await?
248 .iter()
249 .map(|reference| async {
250 let trait_ref = reference.into_trait_ref().await?;
251 if let Some(chunking_type) = &trait_ref.chunking_type() {
252 if !include_traced && chunking_type.is_traced() {
253 return Ok(None);
254 }
255
256 let resolved = reference
257 .resolve_reference()
258 .await?
259 .primary_modules()
260 .await?;
261 let binding_usage = if include_binding_usage {
262 trait_ref.binding_usage()
263 } else {
264 BindingUsage::default()
265 };
266
267 return Ok(Some((
268 *reference,
269 ResolvedReference {
270 chunking_type: chunking_type.clone(),
271 binding_usage,
272 modules: resolved,
273 },
274 )));
275 }
276 Ok(None)
277 })
278 .try_flat_join()
279 .await?;
280 Ok(Vc::cell(modules))
281}
282
283#[turbo_tasks::function]
286pub async fn all_assets_from_entries(
287 entries: Vc<OutputAssets>,
288) -> Result<Vc<ExpandedOutputAssets>> {
289 Ok(Vc::cell(
290 expand_output_assets(
291 entries
292 .await?
293 .into_iter()
294 .map(ExpandOutputAssetsInput::Asset),
295 true,
296 )
297 .await?,
298 ))
299}
300
301#[turbo_tasks::function]
304pub async fn all_assets_from_entry(
305 entry: ResolvedVc<Box<dyn OutputAsset>>,
306) -> Result<Vc<ExpandedOutputAssets>> {
307 Ok(Vc::cell(
308 expand_output_assets(std::iter::once(ExpandOutputAssetsInput::Asset(entry)), true).await?,
309 ))
310}