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::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#[turbo_tasks::value_trait]
31pub trait ModuleReference: ValueToString {
32 #[turbo_tasks::function]
33 fn resolve_reference(self: Vc<Self>) -> Vc<ModuleResolveResult>;
34 fn chunking_type(&self) -> Option<ChunkingType> {
38 None
39 }
40
41 fn binding_usage(&self) -> BindingUsage {
42 BindingUsage::default()
43 }
44}
45
46#[turbo_tasks::value(transparent)]
48pub struct ModuleReferences(Vec<ResolvedVc<Box<dyn ModuleReference>>>);
49
50#[turbo_tasks::value_impl]
51impl ModuleReferences {
52 #[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#[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#[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#[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#[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#[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}