turbopack_core/reference/
mod.rs1use std::collections::HashSet;
2
3use anyhow::Result;
4use turbo_rcstr::RcStr;
5use turbo_tasks::{
6 FxIndexSet, ResolvedVc, TryFlatJoinIterExt, TryJoinIterExt, ValueToString, Vc,
7 graph::{AdjacencyMap, GraphTraversal},
8};
9
10use crate::{
11 chunk::{ChunkableModuleReference, ChunkingType, ChunkingTypeOption},
12 module::{Module, Modules},
13 output::{OutputAsset, OutputAssets},
14 raw_module::RawModule,
15 resolve::{ModuleResolveResult, RequestKey},
16};
17pub mod source_map;
18
19pub use source_map::SourceMapReference;
20
21#[turbo_tasks::value_trait]
29pub trait ModuleReference: ValueToString {
30 fn resolve_reference(self: Vc<Self>) -> Vc<ModuleResolveResult>;
31 }
34
35#[turbo_tasks::value(transparent)]
37pub struct ModuleReferences(Vec<ResolvedVc<Box<dyn ModuleReference>>>);
38
39#[turbo_tasks::value_impl]
40impl ModuleReferences {
41 #[turbo_tasks::function]
43 pub fn empty() -> Vc<Self> {
44 Vc::cell(Vec::new())
45 }
46}
47
48#[turbo_tasks::value]
50pub struct SingleModuleReference {
51 asset: ResolvedVc<Box<dyn Module>>,
52 description: ResolvedVc<RcStr>,
53}
54
55#[turbo_tasks::value_impl]
56impl ModuleReference for SingleModuleReference {
57 #[turbo_tasks::function]
58 fn resolve_reference(&self) -> Vc<ModuleResolveResult> {
59 *ModuleResolveResult::module(self.asset)
60 }
61}
62
63#[turbo_tasks::value_impl]
64impl ValueToString for SingleModuleReference {
65 #[turbo_tasks::function]
66 fn to_string(&self) -> Vc<RcStr> {
67 *self.description
68 }
69}
70
71#[turbo_tasks::value_impl]
72impl SingleModuleReference {
73 #[turbo_tasks::function]
76 pub fn new(asset: ResolvedVc<Box<dyn Module>>, description: ResolvedVc<RcStr>) -> Vc<Self> {
77 Self::cell(SingleModuleReference { asset, description })
78 }
79
80 #[turbo_tasks::function]
82 pub fn asset(&self) -> Vc<Box<dyn Module>> {
83 *self.asset
84 }
85}
86
87#[turbo_tasks::value]
88pub struct SingleChunkableModuleReference {
89 asset: ResolvedVc<Box<dyn Module>>,
90 description: ResolvedVc<RcStr>,
91}
92
93#[turbo_tasks::value_impl]
94impl SingleChunkableModuleReference {
95 #[turbo_tasks::function]
96 pub fn new(asset: ResolvedVc<Box<dyn Module>>, description: ResolvedVc<RcStr>) -> Vc<Self> {
97 Self::cell(SingleChunkableModuleReference { asset, description })
98 }
99}
100
101#[turbo_tasks::value_impl]
102impl ChunkableModuleReference for SingleChunkableModuleReference {
103 #[turbo_tasks::function]
104 fn chunking_type(self: Vc<Self>) -> Vc<ChunkingTypeOption> {
105 Vc::cell(Some(ChunkingType::Parallel {
106 inherit_async: true,
107 hoisted: false,
108 }))
109 }
110}
111
112#[turbo_tasks::value_impl]
113impl ModuleReference for SingleChunkableModuleReference {
114 #[turbo_tasks::function]
115 fn resolve_reference(&self) -> Vc<ModuleResolveResult> {
116 *ModuleResolveResult::module(self.asset)
117 }
118}
119
120#[turbo_tasks::value_impl]
121impl ValueToString for SingleChunkableModuleReference {
122 #[turbo_tasks::function]
123 fn to_string(&self) -> Vc<RcStr> {
124 *self.description
125 }
126}
127
128#[turbo_tasks::value]
130pub struct SingleOutputAssetReference {
131 asset: ResolvedVc<Box<dyn OutputAsset>>,
132 description: ResolvedVc<RcStr>,
133}
134
135#[turbo_tasks::value_impl]
136impl ModuleReference for SingleOutputAssetReference {
137 #[turbo_tasks::function]
138 fn resolve_reference(&self) -> Vc<ModuleResolveResult> {
139 *ModuleResolveResult::output_asset(RequestKey::default(), self.asset)
140 }
141}
142
143#[turbo_tasks::value_impl]
144impl ValueToString for SingleOutputAssetReference {
145 #[turbo_tasks::function]
146 fn to_string(&self) -> Vc<RcStr> {
147 *self.description
148 }
149}
150
151#[turbo_tasks::value_impl]
152impl SingleOutputAssetReference {
153 #[turbo_tasks::function]
156 pub fn new(
157 asset: ResolvedVc<Box<dyn OutputAsset>>,
158 description: ResolvedVc<RcStr>,
159 ) -> Vc<Self> {
160 Self::cell(SingleOutputAssetReference { asset, description })
161 }
162
163 #[turbo_tasks::function]
165 pub fn asset(&self) -> Vc<Box<dyn OutputAsset>> {
166 *self.asset
167 }
168}
169
170#[turbo_tasks::function]
176pub async fn referenced_modules_and_affecting_sources(
177 module: Vc<Box<dyn Module>>,
178) -> Result<Vc<Modules>> {
179 let references = module.references().await?;
180
181 let resolved_references = references
182 .iter()
183 .map(|r| r.resolve_reference())
184 .try_join()
185 .await?;
186 let mut modules = Vec::new();
187 for resolve_result in resolved_references {
188 modules.extend(resolve_result.primary_modules_raw_iter());
189 modules.extend(
190 resolve_result
191 .affecting_sources_iter()
192 .map(|source| async move {
193 Ok(ResolvedVc::upcast(
194 RawModule::new(*source).to_resolved().await?,
195 ))
196 })
197 .try_join()
198 .await?,
199 );
200 }
201
202 let resolved_modules: FxIndexSet<_> = modules.into_iter().collect();
203
204 Ok(Vc::cell(resolved_modules.into_iter().collect()))
205}
206
207#[turbo_tasks::value]
208pub struct TracedModuleReference {
209 module: ResolvedVc<Box<dyn Module>>,
210}
211
212#[turbo_tasks::value_impl]
213impl ModuleReference for TracedModuleReference {
214 #[turbo_tasks::function]
215 fn resolve_reference(&self) -> Vc<ModuleResolveResult> {
216 *ModuleResolveResult::module(self.module)
217 }
218}
219
220#[turbo_tasks::value_impl]
221impl ValueToString for TracedModuleReference {
222 #[turbo_tasks::function]
223 async fn to_string(&self) -> Result<Vc<RcStr>> {
224 Ok(Vc::cell(
225 format!("traced {}", self.module.ident().to_string().await?).into(),
226 ))
227 }
228}
229
230#[turbo_tasks::value_impl]
231impl ChunkableModuleReference for TracedModuleReference {
232 #[turbo_tasks::function]
233 fn chunking_type(&self) -> Vc<ChunkingTypeOption> {
234 Vc::cell(Some(ChunkingType::Traced))
235 }
236}
237
238#[turbo_tasks::value_impl]
239impl TracedModuleReference {
240 #[turbo_tasks::function]
241 pub fn new(module: ResolvedVc<Box<dyn Module>>) -> Vc<Self> {
242 Self::cell(TracedModuleReference { module })
243 }
244}
245
246#[turbo_tasks::function]
252pub async fn primary_referenced_modules(module: Vc<Box<dyn Module>>) -> Result<Vc<Modules>> {
253 let mut set = HashSet::new();
254 let modules = module
255 .references()
256 .await?
257 .iter()
258 .map(|reference| async {
259 reference
260 .resolve_reference()
261 .resolve()
262 .await?
263 .primary_modules()
264 .owned()
265 .await
266 })
267 .try_join()
268 .await?
269 .into_iter()
270 .flatten()
271 .filter(|&module| set.insert(module))
272 .collect();
273 Ok(Vc::cell(modules))
274}
275
276type ModulesVec = Vec<ResolvedVc<Box<dyn Module>>>;
277#[turbo_tasks::value(transparent)]
278pub struct ModulesWithChunkingType(Vec<(ChunkingType, ModulesVec)>);
279
280#[turbo_tasks::function]
286pub async fn primary_chunkable_referenced_modules(
287 module: Vc<Box<dyn Module>>,
288 include_traced: bool,
289) -> Result<Vc<ModulesWithChunkingType>> {
290 let modules = module
291 .references()
292 .await?
293 .iter()
294 .map(|reference| async {
295 if let Some(reference) =
296 ResolvedVc::try_downcast::<Box<dyn ChunkableModuleReference>>(*reference)
297 {
298 if let Some(chunking_type) = &*reference.chunking_type().await? {
299 if !include_traced && matches!(chunking_type, ChunkingType::Traced) {
300 return Ok(None);
301 }
302
303 let resolved = reference
304 .resolve_reference()
305 .resolve()
306 .await?
307 .primary_modules()
308 .owned()
309 .await?;
310 return Ok(Some((chunking_type.clone(), resolved)));
311 }
312 }
313 Ok(None)
314 })
315 .try_flat_join()
316 .await?;
317 Ok(Vc::cell(modules))
318}
319
320#[turbo_tasks::function]
323pub async fn all_assets_from_entries(entries: Vc<OutputAssets>) -> Result<Vc<OutputAssets>> {
324 Ok(Vc::cell(
325 AdjacencyMap::new()
326 .skip_duplicates()
327 .visit(
328 entries.await?.iter().copied().map(ResolvedVc::upcast),
329 get_referenced_assets,
330 )
331 .await
332 .completed()?
333 .into_inner()
334 .into_postorder_topological()
335 .collect(),
336 ))
337}
338
339pub async fn get_referenced_assets(
341 asset: ResolvedVc<Box<dyn OutputAsset>>,
342) -> Result<impl Iterator<Item = ResolvedVc<Box<dyn OutputAsset>>> + Send> {
343 Ok(asset
344 .references()
345 .await?
346 .iter()
347 .copied()
348 .collect::<Vec<_>>()
349 .into_iter())
350}