1use anyhow::Result;
2use rustc_hash::FxHashMap;
3use serde::{Deserialize, Serialize};
4use turbo_rcstr::RcStr;
5use turbo_tasks::{NonLocalValue, ResolvedVc, TaskInput, Upcast, Value, Vc, trace::TraceRawVcs};
6use turbo_tasks_fs::FileSystemPath;
7use turbo_tasks_hash::DeterministicHash;
8
9use super::{ChunkableModule, EvaluatableAssets, availability_info::AvailabilityInfo};
10use crate::{
11 asset::Asset,
12 chunk::{ChunkItem, ChunkType, ModuleId},
13 environment::Environment,
14 ident::AssetIdent,
15 module::Module,
16 module_graph::{ModuleGraph, chunk_group_info::ChunkGroup, module_batches::BatchingConfig},
17 output::{OutputAsset, OutputAssets},
18};
19
20#[derive(
21 Debug,
22 TaskInput,
23 Clone,
24 Copy,
25 PartialEq,
26 Eq,
27 Hash,
28 Serialize,
29 Deserialize,
30 TraceRawVcs,
31 DeterministicHash,
32 NonLocalValue,
33)]
34#[serde(rename_all = "kebab-case")]
35pub enum MangleType {
36 OptimalSize,
37 Deterministic,
38}
39
40#[turbo_tasks::value(shared)]
41#[derive(Debug, TaskInput, Clone, Copy, Hash, DeterministicHash)]
42pub enum MinifyType {
43 Minify { mangle: Option<MangleType> },
46 NoMinify,
47}
48
49impl Default for MinifyType {
50 fn default() -> Self {
51 Self::Minify {
52 mangle: Some(MangleType::OptimalSize),
53 }
54 }
55}
56
57#[derive(
58 Debug,
59 Default,
60 TaskInput,
61 Clone,
62 Copy,
63 PartialEq,
64 Eq,
65 Hash,
66 Serialize,
67 Deserialize,
68 TraceRawVcs,
69 DeterministicHash,
70 NonLocalValue,
71)]
72pub enum SourceMapsType {
73 #[default]
75 Full,
76 None,
78}
79
80#[derive(
81 Debug,
82 TaskInput,
83 Clone,
84 Copy,
85 PartialEq,
86 Eq,
87 Hash,
88 Serialize,
89 Deserialize,
90 TraceRawVcs,
91 DeterministicHash,
92 NonLocalValue,
93)]
94pub enum ChunkGroupType {
95 Entry,
96 Evaluated,
97}
98
99#[turbo_tasks::value(shared)]
100pub struct ChunkGroupResult {
101 pub assets: ResolvedVc<OutputAssets>,
102 pub availability_info: AvailabilityInfo,
103}
104
105#[turbo_tasks::value(shared)]
106pub struct EntryChunkGroupResult {
107 pub asset: ResolvedVc<Box<dyn OutputAsset>>,
108 pub availability_info: AvailabilityInfo,
109}
110
111#[derive(
112 Default, Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, TraceRawVcs, NonLocalValue,
113)]
114pub struct ChunkingConfig {
115 pub min_chunk_size: usize,
118
119 pub max_chunk_count_per_group: usize,
122
123 pub max_merge_chunk_size: usize,
126
127 #[allow(dead_code)]
128 pub placeholder_for_future_extensions: (),
129}
130
131#[turbo_tasks::value(transparent)]
132pub struct ChunkingConfigs(FxHashMap<ResolvedVc<Box<dyn ChunkType>>, ChunkingConfig>);
133
134#[turbo_tasks::value_trait]
136pub trait ChunkingContext {
137 fn name(self: Vc<Self>) -> Vc<RcStr>;
138 fn should_use_file_source_map_uris(self: Vc<Self>) -> Vc<bool>;
139 fn root_path(self: Vc<Self>) -> Vc<FileSystemPath>;
141 fn output_root(self: Vc<Self>) -> Vc<FileSystemPath>;
143 fn output_root_to_root_path(self: Vc<Self>) -> Vc<RcStr>;
146
147 fn environment(self: Vc<Self>) -> Vc<Environment>;
150
151 fn chunk_root_path(self: Vc<Self>) -> Vc<FileSystemPath>;
154
155 fn chunk_path(
160 self: Vc<Self>,
161 asset: Option<Vc<Box<dyn Asset>>>,
162 ident: Vc<AssetIdent>,
163 extension: RcStr,
164 ) -> Vc<FileSystemPath>;
165
166 fn reference_chunk_source_maps(self: Vc<Self>, chunk: Vc<Box<dyn OutputAsset>>) -> Vc<bool>;
168
169 fn reference_module_source_maps(self: Vc<Self>, module: Vc<Box<dyn Module>>) -> Vc<bool>;
171
172 fn asset_url(self: Vc<Self>, ident: Vc<FileSystemPath>) -> Result<Vc<RcStr>>;
175
176 fn asset_path(
177 self: Vc<Self>,
178 content_hash: RcStr,
179 original_asset_ident: Vc<AssetIdent>,
180 ) -> Vc<FileSystemPath>;
181
182 fn is_hot_module_replacement_enabled(self: Vc<Self>) -> Vc<bool> {
183 Vc::cell(false)
184 }
185
186 fn chunking_configs(self: Vc<Self>) -> Vc<ChunkingConfigs> {
187 Vc::cell(Default::default())
188 }
189
190 fn batching_config(self: Vc<Self>) -> Vc<BatchingConfig> {
191 BatchingConfig::new(BatchingConfig {
192 ..Default::default()
193 })
194 }
195
196 fn is_tracing_enabled(self: Vc<Self>) -> Vc<bool> {
197 Vc::cell(false)
198 }
199
200 fn minify_type(self: Vc<Self>) -> Vc<MinifyType> {
201 MinifyType::NoMinify.cell()
202 }
203
204 fn async_loader_chunk_item(
205 &self,
206 module: Vc<Box<dyn ChunkableModule>>,
207 module_graph: Vc<ModuleGraph>,
208 availability_info: Value<AvailabilityInfo>,
209 ) -> Vc<Box<dyn ChunkItem>>;
210 fn async_loader_chunk_item_id(&self, module: Vc<Box<dyn ChunkableModule>>) -> Vc<ModuleId>;
211
212 fn chunk_group(
213 self: Vc<Self>,
214 ident: Vc<AssetIdent>,
215 chunk_group: ChunkGroup,
216 module_graph: Vc<ModuleGraph>,
217 availability_info: Value<AvailabilityInfo>,
218 ) -> Vc<ChunkGroupResult>;
219
220 fn evaluated_chunk_group(
221 self: Vc<Self>,
222 ident: Vc<AssetIdent>,
223 chunk_group: ChunkGroup,
224 module_graph: Vc<ModuleGraph>,
225 availability_info: Value<AvailabilityInfo>,
226 ) -> Vc<ChunkGroupResult>;
227
228 fn entry_chunk_group(
233 self: Vc<Self>,
234 path: Vc<FileSystemPath>,
235 evaluatable_assets: Vc<EvaluatableAssets>,
236 module_graph: Vc<ModuleGraph>,
237 extra_chunks: Vc<OutputAssets>,
238 availability_info: Value<AvailabilityInfo>,
239 ) -> Result<Vc<EntryChunkGroupResult>>;
240
241 async fn chunk_item_id_from_ident(
242 self: Vc<Self>,
243 ident: Vc<AssetIdent>,
244 ) -> Result<Vc<ModuleId>>;
245
246 fn chunk_item_id(self: Vc<Self>, module: Vc<Box<dyn ChunkItem>>) -> Vc<ModuleId> {
247 self.chunk_item_id_from_ident(module.asset_ident())
248 }
249 fn chunk_item_id_from_module(self: Vc<Self>, module: Vc<Box<dyn Module>>) -> Vc<ModuleId> {
250 self.chunk_item_id_from_ident(module.ident())
251 }
252}
253
254pub trait ChunkingContextExt {
255 fn root_chunk_group(
256 self: Vc<Self>,
257 ident: Vc<AssetIdent>,
258 chunk_group: ChunkGroup,
259 module_graph: Vc<ModuleGraph>,
260 ) -> Vc<ChunkGroupResult>
261 where
262 Self: Send;
263
264 fn root_chunk_group_assets(
265 self: Vc<Self>,
266 ident: Vc<AssetIdent>,
267 chunk_group: ChunkGroup,
268 module_graph: Vc<ModuleGraph>,
269 ) -> Vc<OutputAssets>
270 where
271 Self: Send;
272
273 fn evaluated_chunk_group_assets(
274 self: Vc<Self>,
275 ident: Vc<AssetIdent>,
276 chunk_group: ChunkGroup,
277 module_graph: Vc<ModuleGraph>,
278 availability_info: Value<AvailabilityInfo>,
279 ) -> Vc<OutputAssets>
280 where
281 Self: Send;
282
283 fn entry_chunk_group_asset(
284 self: Vc<Self>,
285 path: Vc<FileSystemPath>,
286 evaluatable_assets: Vc<EvaluatableAssets>,
287 module_graph: Vc<ModuleGraph>,
288 extra_chunks: Vc<OutputAssets>,
289 availability_info: Value<AvailabilityInfo>,
290 ) -> Vc<Box<dyn OutputAsset>>
291 where
292 Self: Send;
293
294 fn root_entry_chunk_group(
295 self: Vc<Self>,
296 path: Vc<FileSystemPath>,
297 evaluatable_assets: Vc<EvaluatableAssets>,
298 module_graph: Vc<ModuleGraph>,
299 extra_chunks: Vc<OutputAssets>,
300 ) -> Vc<EntryChunkGroupResult>
301 where
302 Self: Send;
303
304 fn root_entry_chunk_group_asset(
305 self: Vc<Self>,
306 path: Vc<FileSystemPath>,
307 evaluatable_assets: Vc<EvaluatableAssets>,
308 module_graph: Vc<ModuleGraph>,
309 extra_chunks: Vc<OutputAssets>,
310 ) -> Vc<Box<dyn OutputAsset>>
311 where
312 Self: Send;
313
314 fn chunk_group_assets(
315 self: Vc<Self>,
316 ident: Vc<AssetIdent>,
317 chunk_group: ChunkGroup,
318 module_graph: Vc<ModuleGraph>,
319 availability_info: Value<AvailabilityInfo>,
320 ) -> Vc<OutputAssets>
321 where
322 Self: Send;
323}
324
325impl<T: ChunkingContext + Send + Upcast<Box<dyn ChunkingContext>>> ChunkingContextExt for T {
326 fn root_chunk_group(
327 self: Vc<Self>,
328 ident: Vc<AssetIdent>,
329 chunk_group: ChunkGroup,
330 module_graph: Vc<ModuleGraph>,
331 ) -> Vc<ChunkGroupResult> {
332 self.chunk_group(
333 ident,
334 chunk_group,
335 module_graph,
336 Value::new(AvailabilityInfo::Root),
337 )
338 }
339
340 fn root_chunk_group_assets(
341 self: Vc<Self>,
342 ident: Vc<AssetIdent>,
343 chunk_group: ChunkGroup,
344 module_graph: Vc<ModuleGraph>,
345 ) -> Vc<OutputAssets> {
346 root_chunk_group_assets(Vc::upcast(self), ident, chunk_group, module_graph)
347 }
348
349 fn evaluated_chunk_group_assets(
350 self: Vc<Self>,
351 ident: Vc<AssetIdent>,
352 chunk_group: ChunkGroup,
353 module_graph: Vc<ModuleGraph>,
354 availability_info: Value<AvailabilityInfo>,
355 ) -> Vc<OutputAssets> {
356 evaluated_chunk_group_assets(
357 Vc::upcast(self),
358 ident,
359 chunk_group,
360 module_graph,
361 availability_info,
362 )
363 }
364
365 fn entry_chunk_group_asset(
366 self: Vc<Self>,
367 path: Vc<FileSystemPath>,
368 evaluatable_assets: Vc<EvaluatableAssets>,
369 module_graph: Vc<ModuleGraph>,
370 extra_chunks: Vc<OutputAssets>,
371 availability_info: Value<AvailabilityInfo>,
372 ) -> Vc<Box<dyn OutputAsset>> {
373 entry_chunk_group_asset(
374 Vc::upcast(self),
375 path,
376 evaluatable_assets,
377 module_graph,
378 extra_chunks,
379 availability_info,
380 )
381 }
382
383 fn root_entry_chunk_group(
384 self: Vc<Self>,
385 path: Vc<FileSystemPath>,
386 evaluatable_assets: Vc<EvaluatableAssets>,
387 module_graph: Vc<ModuleGraph>,
388 extra_chunks: Vc<OutputAssets>,
389 ) -> Vc<EntryChunkGroupResult> {
390 self.entry_chunk_group(
391 path,
392 evaluatable_assets,
393 module_graph,
394 extra_chunks,
395 Value::new(AvailabilityInfo::Root),
396 )
397 }
398
399 fn root_entry_chunk_group_asset(
400 self: Vc<Self>,
401 path: Vc<FileSystemPath>,
402 evaluatable_assets: Vc<EvaluatableAssets>,
403 module_graph: Vc<ModuleGraph>,
404 extra_chunks: Vc<OutputAssets>,
405 ) -> Vc<Box<dyn OutputAsset>> {
406 entry_chunk_group_asset(
407 Vc::upcast(self),
408 path,
409 evaluatable_assets,
410 module_graph,
411 extra_chunks,
412 Value::new(AvailabilityInfo::Root),
413 )
414 }
415
416 fn chunk_group_assets(
417 self: Vc<Self>,
418 ident: Vc<AssetIdent>,
419 chunk_group: ChunkGroup,
420 module_graph: Vc<ModuleGraph>,
421 availability_info: Value<AvailabilityInfo>,
422 ) -> Vc<OutputAssets> {
423 chunk_group_assets(
424 Vc::upcast(self),
425 ident,
426 chunk_group,
427 module_graph,
428 availability_info,
429 )
430 }
431}
432
433#[turbo_tasks::function]
434async fn root_chunk_group_assets(
435 chunking_context: Vc<Box<dyn ChunkingContext>>,
436 ident: Vc<AssetIdent>,
437 chunk_group: ChunkGroup,
438 module_graph: Vc<ModuleGraph>,
439) -> Result<Vc<OutputAssets>> {
440 Ok(*chunking_context
441 .root_chunk_group(ident, chunk_group, module_graph)
442 .await?
443 .assets)
444}
445
446#[turbo_tasks::function]
447async fn evaluated_chunk_group_assets(
448 chunking_context: Vc<Box<dyn ChunkingContext>>,
449 ident: Vc<AssetIdent>,
450 chunk_group: ChunkGroup,
451 module_graph: Vc<ModuleGraph>,
452 availability_info: Value<AvailabilityInfo>,
453) -> Result<Vc<OutputAssets>> {
454 Ok(*chunking_context
455 .evaluated_chunk_group(ident, chunk_group, module_graph, availability_info)
456 .await?
457 .assets)
458}
459
460#[turbo_tasks::function]
461async fn entry_chunk_group_asset(
462 chunking_context: Vc<Box<dyn ChunkingContext>>,
463 path: Vc<FileSystemPath>,
464 evaluatable_assets: Vc<EvaluatableAssets>,
465 module_graph: Vc<ModuleGraph>,
466 extra_chunks: Vc<OutputAssets>,
467 availability_info: Value<AvailabilityInfo>,
468) -> Result<Vc<Box<dyn OutputAsset>>> {
469 Ok(*chunking_context
470 .entry_chunk_group(
471 path,
472 evaluatable_assets,
473 module_graph,
474 extra_chunks,
475 availability_info,
476 )
477 .await?
478 .asset)
479}
480
481#[turbo_tasks::function]
482async fn chunk_group_assets(
483 chunking_context: Vc<Box<dyn ChunkingContext>>,
484 ident: Vc<AssetIdent>,
485 chunk_group: ChunkGroup,
486 module_graph: Vc<ModuleGraph>,
487 availability_info: Value<AvailabilityInfo>,
488) -> Result<Vc<OutputAssets>> {
489 Ok(*chunking_context
490 .chunk_group(ident, chunk_group, module_graph, availability_info)
491 .await?
492 .assets)
493}