turbopack_core/reference/
mod.rs1use 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::{ChunkableModuleReference, ChunkingType, ChunkingTypeOption},
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#[turbo_tasks::value_trait]
33pub trait ModuleReference: ValueToString {
34 #[turbo_tasks::function]
35 fn resolve_reference(self: Vc<Self>) -> Vc<ModuleResolveResult>;
36 }
39
40#[turbo_tasks::value(transparent)]
42pub struct ModuleReferences(Vec<ResolvedVc<Box<dyn ModuleReference>>>);
43
44#[turbo_tasks::value_impl]
45impl ModuleReferences {
46 #[turbo_tasks::function]
48 pub fn empty() -> Vc<Self> {
49 Vc::cell(Vec::new())
50 }
51}
52
53#[turbo_tasks::value]
55pub struct SingleModuleReference {
56 asset: ResolvedVc<Box<dyn Module>>,
57 description: RcStr,
58}
59
60#[turbo_tasks::value_impl]
61impl ModuleReference for SingleModuleReference {
62 #[turbo_tasks::function]
63 fn resolve_reference(&self) -> Vc<ModuleResolveResult> {
64 *ModuleResolveResult::module(self.asset)
65 }
66}
67
68#[turbo_tasks::value_impl]
69impl ValueToString for SingleModuleReference {
70 #[turbo_tasks::function]
71 fn to_string(&self) -> Vc<RcStr> {
72 Vc::cell(self.description.clone())
73 }
74}
75
76#[turbo_tasks::value_impl]
77impl SingleModuleReference {
78 #[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 #[turbo_tasks::function]
87 pub fn asset(&self) -> Vc<Box<dyn Module>> {
88 *self.asset
89 }
90}
91
92#[turbo_tasks::value]
93pub struct SingleChunkableModuleReference {
94 asset: ResolvedVc<Box<dyn Module>>,
95 description: RcStr,
96 export: ResolvedVc<ExportUsage>,
97}
98
99#[turbo_tasks::value_impl]
100impl SingleChunkableModuleReference {
101 #[turbo_tasks::function]
102 pub fn new(
103 asset: ResolvedVc<Box<dyn Module>>,
104 description: RcStr,
105 export: ResolvedVc<ExportUsage>,
106 ) -> Vc<Self> {
107 Self::cell(SingleChunkableModuleReference {
108 asset,
109 description,
110 export,
111 })
112 }
113}
114
115#[turbo_tasks::value_impl]
116impl ChunkableModuleReference for SingleChunkableModuleReference {
117 #[turbo_tasks::function]
118 fn chunking_type(self: Vc<Self>) -> Vc<ChunkingTypeOption> {
119 Vc::cell(Some(ChunkingType::Parallel {
120 inherit_async: true,
121 hoisted: false,
122 }))
123 }
124
125 #[turbo_tasks::function]
126 async fn binding_usage(&self) -> Result<Vc<BindingUsage>> {
127 Ok(BindingUsage {
128 import: ImportUsage::SideEffects,
129 export: self.export.owned().await?,
130 }
131 .cell())
132 }
133}
134
135#[turbo_tasks::value_impl]
136impl ModuleReference for SingleChunkableModuleReference {
137 #[turbo_tasks::function]
138 fn resolve_reference(&self) -> Vc<ModuleResolveResult> {
139 *ModuleResolveResult::module(self.asset)
140 }
141}
142
143#[turbo_tasks::value_impl]
144impl ValueToString for SingleChunkableModuleReference {
145 #[turbo_tasks::function]
146 fn to_string(&self) -> Vc<RcStr> {
147 Vc::cell(self.description.clone())
148 }
149}
150
151#[turbo_tasks::value]
153pub struct SingleOutputAssetReference {
154 asset: ResolvedVc<Box<dyn OutputAsset>>,
155 description: RcStr,
156}
157
158#[turbo_tasks::value_impl]
159impl ModuleReference for SingleOutputAssetReference {
160 #[turbo_tasks::function]
161 fn resolve_reference(&self) -> Vc<ModuleResolveResult> {
162 *ModuleResolveResult::output_asset(RequestKey::default(), self.asset)
163 }
164}
165
166#[turbo_tasks::value_impl]
167impl ValueToString for SingleOutputAssetReference {
168 #[turbo_tasks::function]
169 fn to_string(&self) -> Vc<RcStr> {
170 Vc::cell(self.description.clone())
171 }
172}
173
174#[turbo_tasks::value_impl]
175impl SingleOutputAssetReference {
176 #[turbo_tasks::function]
179 pub fn new(asset: ResolvedVc<Box<dyn OutputAsset>>, description: RcStr) -> Vc<Self> {
180 Self::cell(SingleOutputAssetReference { asset, description })
181 }
182
183 #[turbo_tasks::function]
185 pub fn asset(&self) -> Vc<Box<dyn OutputAsset>> {
186 *self.asset
187 }
188}
189
190#[turbo_tasks::function]
196pub async fn referenced_modules_and_affecting_sources(
197 module: Vc<Box<dyn Module>>,
198) -> Result<Vc<Modules>> {
199 let references = module.references().await?;
200
201 let resolved_references = references
202 .iter()
203 .map(|r| r.resolve_reference())
204 .try_join()
205 .await?;
206 let mut modules = Vec::new();
207 for resolve_result in resolved_references {
208 modules.extend(resolve_result.primary_modules_raw_iter());
209 modules.extend(
210 resolve_result
211 .affecting_sources_iter()
212 .map(|source| async move {
213 Ok(ResolvedVc::upcast(
214 RawModule::new(*source).to_resolved().await?,
215 ))
216 })
217 .try_join()
218 .await?,
219 );
220 }
221
222 let resolved_modules: FxIndexSet<_> = modules.into_iter().collect();
223
224 Ok(Vc::cell(resolved_modules.into_iter().collect()))
225}
226
227#[turbo_tasks::value]
228pub struct TracedModuleReference {
229 module: ResolvedVc<Box<dyn Module>>,
230}
231
232#[turbo_tasks::value_impl]
233impl ModuleReference for TracedModuleReference {
234 #[turbo_tasks::function]
235 fn resolve_reference(&self) -> Vc<ModuleResolveResult> {
236 *ModuleResolveResult::module(self.module)
237 }
238}
239
240#[turbo_tasks::value_impl]
241impl ValueToString for TracedModuleReference {
242 #[turbo_tasks::function]
243 async fn to_string(&self) -> Result<Vc<RcStr>> {
244 Ok(Vc::cell(
245 format!("traced {}", self.module.ident().to_string().await?).into(),
246 ))
247 }
248}
249
250#[turbo_tasks::value_impl]
251impl ChunkableModuleReference for TracedModuleReference {
252 #[turbo_tasks::function]
253 fn chunking_type(&self) -> Vc<ChunkingTypeOption> {
254 Vc::cell(Some(ChunkingType::Traced))
255 }
256}
257
258#[turbo_tasks::value_impl]
259impl TracedModuleReference {
260 #[turbo_tasks::function]
261 pub fn new(module: ResolvedVc<Box<dyn Module>>) -> Vc<Self> {
262 Self::cell(TracedModuleReference { module })
263 }
264}
265
266#[turbo_tasks::function]
272pub async fn primary_referenced_modules(module: Vc<Box<dyn Module>>) -> Result<Vc<Modules>> {
273 let mut set = HashSet::new();
274 let modules = module
275 .references()
276 .await?
277 .iter()
278 .map(|reference| async {
279 reference
280 .resolve_reference()
281 .resolve()
282 .await?
283 .primary_modules()
284 .owned()
285 .await
286 })
287 .try_join()
288 .await?
289 .into_iter()
290 .flatten()
291 .filter(|&module| set.insert(module))
292 .collect();
293 Ok(Vc::cell(modules))
294}
295
296#[derive(Clone, Eq, PartialEq, ValueDebugFormat, TraceRawVcs, NonLocalValue, Encode, Decode)]
297pub struct ResolvedReference {
298 pub chunking_type: ChunkingType,
299 pub binding_usage: BindingUsage,
300 pub modules: Vec<ResolvedVc<Box<dyn Module>>>,
301}
302
303#[turbo_tasks::value(transparent)]
304pub struct ModulesWithRefData(Vec<(ResolvedVc<Box<dyn ModuleReference>>, ResolvedReference)>);
305
306#[turbo_tasks::function]
312pub async fn primary_chunkable_referenced_modules(
313 module: ResolvedVc<Box<dyn Module>>,
314 include_traced: bool,
315 include_binding_usage: bool,
316) -> Result<Vc<ModulesWithRefData>> {
317 let modules = module
318 .references()
319 .await?
320 .iter()
321 .map(|reference| async {
322 if let Some(reference) =
323 ResolvedVc::try_downcast::<Box<dyn ChunkableModuleReference>>(*reference)
324 && let Some(chunking_type) = &*reference.chunking_type().await?
325 {
326 if !include_traced && matches!(chunking_type, ChunkingType::Traced) {
327 return Ok(None);
328 }
329
330 let resolved = reference
331 .resolve_reference()
332 .await?
333 .primary_modules_ref()
334 .await?;
335 let binding_usage = if include_binding_usage {
336 reference.binding_usage().owned().await?
337 } else {
338 BindingUsage::default()
339 };
340
341 return Ok(Some((
342 ResolvedVc::upcast(reference),
343 ResolvedReference {
344 chunking_type: chunking_type.clone(),
345 binding_usage,
346 modules: resolved,
347 },
348 )));
349 }
350 Ok(None)
351 })
352 .try_flat_join()
353 .await?;
354 Ok(Vc::cell(modules))
355}
356
357#[turbo_tasks::function]
360pub async fn all_assets_from_entries(
361 entries: Vc<OutputAssets>,
362) -> Result<Vc<ExpandedOutputAssets>> {
363 Ok(Vc::cell(
364 expand_output_assets(
365 entries
366 .await?
367 .into_iter()
368 .map(|&asset| ExpandOutputAssetsInput::Asset(asset)),
369 true,
370 )
371 .await?,
372 ))
373}
374
375#[turbo_tasks::function]
378pub async fn all_assets_from_entry(
379 entry: ResolvedVc<Box<dyn OutputAsset>>,
380) -> Result<Vc<ExpandedOutputAssets>> {
381 Ok(Vc::cell(
382 expand_output_assets(std::iter::once(ExpandOutputAssetsInput::Asset(entry)), true).await?,
383 ))
384}