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(transparent)]
51pub struct ModuleReferences(Vec<ResolvedVc<Box<dyn ModuleReference>>>);
52
53#[turbo_tasks::value_impl]
54impl ModuleReferences {
55 #[turbo_tasks::function]
57 pub fn empty() -> Vc<Self> {
58 Vc::cell(Vec::new())
59 }
60}
61
62#[turbo_tasks::value]
63#[derive(ValueToString)]
64#[value_to_string(self.description)]
65pub struct SingleChunkableModuleReference {
66 asset: ResolvedVc<Box<dyn Module>>,
67 description: RcStr,
68 export: ExportUsage,
69}
70
71#[turbo_tasks::value_impl]
72impl SingleChunkableModuleReference {
73 #[turbo_tasks::function]
74 pub async fn new(
75 asset: ResolvedVc<Box<dyn Module>>,
76 description: RcStr,
77 export: Vc<ExportUsage>,
78 ) -> Result<Vc<Self>> {
79 Ok(Self::cell(SingleChunkableModuleReference {
80 asset,
81 description,
82 export: export.owned().await?,
83 }))
84 }
85}
86
87#[turbo_tasks::value_impl]
88impl ModuleReference for SingleChunkableModuleReference {
89 #[turbo_tasks::function]
90 fn resolve_reference(&self) -> Vc<ModuleResolveResult> {
91 *ModuleResolveResult::module(self.asset)
92 }
93
94 fn chunking_type(&self) -> Option<ChunkingType> {
95 Some(ChunkingType::Parallel {
96 inherit_async: true,
97 hoisted: false,
98 })
99 }
100
101 fn binding_usage(&self) -> BindingUsage {
102 BindingUsage {
103 import: ImportUsage::TopLevel,
104 export: self.export.clone(),
105 }
106 }
107}
108
109#[turbo_tasks::function]
115pub async fn referenced_modules_and_affecting_sources(
116 module: Vc<Box<dyn Module>>,
117 include_binding_usage: bool,
118) -> Result<Vc<ModulesWithRefData>> {
119 let modules = module
120 .references()
121 .await?
122 .iter()
123 .map(|reference| async {
124 let trait_ref = reference.into_trait_ref().await?;
125 let resolve_result = reference.resolve_reference().await?;
126 if let Some(chunking_type) = &trait_ref.chunking_type() {
127 let mut modules = resolve_result
128 .primary_modules_raw_iter()
129 .collect::<Vec<_>>();
130 modules.extend(
131 resolve_result
132 .affecting_sources_iter()
133 .map(|source| async move {
134 Ok(ResolvedVc::upcast(
135 RawModule::new(*source).to_resolved().await?,
136 ))
137 })
138 .try_join()
139 .await?,
140 );
141
142 let binding_usage = if include_binding_usage {
143 trait_ref.binding_usage()
144 } else {
145 BindingUsage::default()
146 };
147
148 return Ok(Some((
149 *reference,
150 ResolvedReference {
151 chunking_type: chunking_type.clone(),
152 binding_usage,
153 modules,
154 },
155 )));
156 }
157 Ok(None)
158 })
159 .try_flat_join()
160 .await?;
161 Ok(Vc::cell(modules))
162}
163
164#[turbo_tasks::value]
165#[derive(ValueToString)]
166#[value_to_string("traced {}", self.module.ident())]
167pub struct TracedModuleReference {
168 module: ResolvedVc<Box<dyn Module>>,
169 mode: TracedMode,
170}
171
172#[turbo_tasks::value_impl]
173impl ModuleReference for TracedModuleReference {
174 #[turbo_tasks::function]
175 fn resolve_reference(&self) -> Vc<ModuleResolveResult> {
176 *ModuleResolveResult::module(self.module)
177 }
178
179 fn chunking_type(&self) -> Option<ChunkingType> {
180 Some(ChunkingType::Traced { mode: self.mode })
181 }
182}
183
184#[turbo_tasks::value_impl]
185impl TracedModuleReference {
186 #[turbo_tasks::function]
187 pub fn new(module: ResolvedVc<Box<dyn Module>>, mode: TracedMode) -> Vc<Self> {
188 Self::cell(TracedModuleReference { module, mode })
189 }
190}
191
192#[turbo_tasks::function]
197pub async fn primary_referenced_modules(module: Vc<Box<dyn Module>>) -> Result<Vc<Modules>> {
198 let mut set = HashSet::new();
199 let modules = module
200 .references()
201 .await?
202 .iter()
203 .map(|reference| async { reference.resolve_reference().await?.primary_modules().await })
204 .try_join()
205 .await?
206 .into_iter()
207 .flatten()
208 .filter(|&module| set.insert(module))
209 .collect();
210 Ok(Vc::cell(modules))
211}
212
213#[derive(Clone, Eq, PartialEq, ValueDebugFormat, TraceRawVcs, NonLocalValue, Encode, Decode)]
214pub struct ResolvedReference {
215 pub chunking_type: ChunkingType,
216 pub binding_usage: BindingUsage,
217 pub modules: Vec<ResolvedVc<Box<dyn Module>>>,
218}
219
220#[turbo_tasks::value(transparent)]
221pub struct ModulesWithRefData(Vec<(ResolvedVc<Box<dyn ModuleReference>>, ResolvedReference)>);
222
223#[turbo_tasks::function]
229pub async fn primary_chunkable_referenced_modules(
230 module: ResolvedVc<Box<dyn Module>>,
231 include_traced: bool,
232 include_binding_usage: bool,
233) -> Result<Vc<ModulesWithRefData>> {
234 let modules = module
235 .references()
236 .await?
237 .iter()
238 .map(|reference| async {
239 let trait_ref = reference.into_trait_ref().await?;
240 if let Some(chunking_type) = &trait_ref.chunking_type() {
241 if !include_traced && chunking_type.is_traced() {
242 return Ok(None);
243 }
244
245 let resolved = reference
246 .resolve_reference()
247 .await?
248 .primary_modules()
249 .await?;
250 let binding_usage = if include_binding_usage {
251 trait_ref.binding_usage()
252 } else {
253 BindingUsage::default()
254 };
255
256 return Ok(Some((
257 *reference,
258 ResolvedReference {
259 chunking_type: chunking_type.clone(),
260 binding_usage,
261 modules: resolved,
262 },
263 )));
264 }
265 Ok(None)
266 })
267 .try_flat_join()
268 .await?;
269 Ok(Vc::cell(modules))
270}
271
272#[turbo_tasks::function]
275pub async fn all_assets_from_entries(
276 entries: Vc<OutputAssets>,
277) -> Result<Vc<ExpandedOutputAssets>> {
278 Ok(Vc::cell(
279 expand_output_assets(
280 entries
281 .await?
282 .into_iter()
283 .map(ExpandOutputAssetsInput::Asset),
284 true,
285 )
286 .await?,
287 ))
288}
289
290#[turbo_tasks::function]
293pub async fn all_assets_from_entry(
294 entry: ResolvedVc<Box<dyn OutputAsset>>,
295) -> Result<Vc<ExpandedOutputAssets>> {
296 Ok(Vc::cell(
297 expand_output_assets(std::iter::once(ExpandOutputAssetsInput::Asset(entry)), true).await?,
298 ))
299}