turbopack_core/reference/
mod.rs1use std::collections::HashSet;
2
3use anyhow::Result;
4use bincode::{Decode, Encode};
5use smallvec::SmallVec;
6use turbo_rcstr::RcStr;
7use turbo_tasks::{
8 NonLocalValue, ResolvedVc, TryFlatJoinIterExt, TryJoinIterExt, ValueToString, Vc,
9 debug::ValueDebugFormat,
10};
11
12use crate::{
13 chunk::{ChunkingType, TracedMode},
14 issue::IssueSource,
15 module::{Module, Modules},
16 output::{
17 ExpandOutputAssetsInput, ExpandedOutputAssets, OutputAsset, OutputAssets,
18 expand_output_assets,
19 },
20 raw_module::RawModule,
21 resolve::{BindingUsage, ExportUsage, ImportUsage, ModuleResolveResult},
22};
23pub mod source_map;
24
25pub use source_map::SourceMapReference;
26
27#[turbo_tasks::value_trait]
33pub trait ModuleReference: ValueToString {
34 #[turbo_tasks::function]
35 fn resolve_reference(self: Vc<Self>) -> Vc<ModuleResolveResult>;
36 fn chunking_type(&self) -> Option<ChunkingType>;
40
41 fn binding_usage(&self) -> BindingUsage {
42 BindingUsage::default()
43 }
44
45 fn source(&self) -> Option<IssueSource> {
46 None
47 }
48}
49
50#[turbo_tasks::value_trait]
53pub trait DynamicTraceReference: ModuleReference {
54 fn origin_fn_name(&self) -> RcStr;
59}
60
61#[turbo_tasks::value(transparent)]
63pub struct ModuleReferences(Vec<ResolvedVc<Box<dyn ModuleReference>>>);
64
65#[turbo_tasks::value_impl]
66impl ModuleReferences {
67 #[turbo_tasks::function]
69 pub fn empty() -> Vc<Self> {
70 Vc::cell(Vec::new())
71 }
72}
73
74#[turbo_tasks::value]
75#[derive(ValueToString)]
76#[value_to_string(self.description)]
77pub struct SingleChunkableModuleReference {
78 asset: ResolvedVc<Box<dyn Module>>,
79 description: RcStr,
80 export: ExportUsage,
81}
82
83#[turbo_tasks::value_impl]
84impl SingleChunkableModuleReference {
85 #[turbo_tasks::function]
86 pub async fn new(
87 asset: ResolvedVc<Box<dyn Module>>,
88 description: RcStr,
89 export: Vc<ExportUsage>,
90 ) -> Result<Vc<Self>> {
91 Ok(Self::cell(SingleChunkableModuleReference {
92 asset,
93 description,
94 export: export.owned().await?,
95 }))
96 }
97}
98
99#[turbo_tasks::value_impl]
100impl ModuleReference for SingleChunkableModuleReference {
101 #[turbo_tasks::function]
102 fn resolve_reference(&self) -> Vc<ModuleResolveResult> {
103 *ModuleResolveResult::module(self.asset)
104 }
105
106 fn chunking_type(&self) -> Option<ChunkingType> {
107 Some(ChunkingType::Parallel {
108 inherit_async: true,
109 hoisted: false,
110 })
111 }
112
113 fn binding_usage(&self) -> BindingUsage {
114 BindingUsage {
115 import: ImportUsage::TopLevel,
116 export: self.export.clone(),
117 }
118 }
119}
120
121#[turbo_tasks::function]
127pub async fn referenced_modules_and_affecting_sources(
128 module: Vc<Box<dyn Module>>,
129 include_binding_usage: bool,
130) -> Result<Vc<ModulesWithRefData>> {
131 let modules = module
132 .references()
133 .await?
134 .iter()
135 .map(async |reference| {
136 let trait_ref = reference.into_trait_ref().await?;
137 let resolve_result = reference.resolve_reference().await?;
138 if let Some(chunking_type) = &trait_ref.chunking_type() {
139 let mut modules: SmallVec<[_; 2]> =
140 resolve_result.primary_modules_raw_iter().collect();
141 modules.extend(
142 resolve_result
143 .affecting_sources_iter()
144 .map(async |source| {
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(async |reference| 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, NonLocalValue, Encode, Decode)]
225pub struct ResolvedReference {
226 pub chunking_type: ChunkingType,
227 pub binding_usage: BindingUsage,
228 pub modules: SmallVec<[ResolvedVc<Box<dyn Module>>; 2]>,
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(async |reference| {
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}