1use anyhow::{Result, bail};
2use rustc_hash::FxHashMap;
3use serde::{Deserialize, Serialize};
4use turbo_rcstr::RcStr;
5use turbo_tasks::{NonLocalValue, ResolvedVc, TaskInput, Upcast, 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::{
17 ModuleGraph, chunk_group_info::ChunkGroup, export_usage::ModuleExportUsage,
18 module_batches::BatchingConfig,
19 },
20 output::{OutputAsset, OutputAssets, OutputAssetsWithReferenced},
21};
22
23#[derive(
24 Debug,
25 TaskInput,
26 Clone,
27 Copy,
28 PartialEq,
29 Eq,
30 Hash,
31 Serialize,
32 Deserialize,
33 TraceRawVcs,
34 DeterministicHash,
35 NonLocalValue,
36)]
37#[serde(rename_all = "kebab-case")]
38pub enum MangleType {
39 OptimalSize,
40 Deterministic,
41}
42
43#[turbo_tasks::value(shared)]
44#[derive(Debug, TaskInput, Clone, Copy, Hash, DeterministicHash)]
45pub enum MinifyType {
46 Minify { mangle: Option<MangleType> },
49 NoMinify,
50}
51
52impl Default for MinifyType {
53 fn default() -> Self {
54 Self::Minify {
55 mangle: Some(MangleType::OptimalSize),
56 }
57 }
58}
59
60#[turbo_tasks::value(shared)]
61#[derive(Debug, Default, TaskInput, Clone, Copy, Hash, DeterministicHash)]
62pub enum SourceMapsType {
63 #[default]
65 Full,
66 None,
68}
69
70#[derive(
71 Debug,
72 TaskInput,
73 Clone,
74 Copy,
75 PartialEq,
76 Eq,
77 Hash,
78 Serialize,
79 Deserialize,
80 TraceRawVcs,
81 DeterministicHash,
82 NonLocalValue,
83)]
84pub enum ChunkGroupType {
85 Entry,
86 Evaluated,
87}
88
89#[turbo_tasks::value(shared)]
90#[derive(Clone, Copy)]
91pub struct ChunkGroupResult {
92 pub assets: ResolvedVc<OutputAssets>,
93 pub referenced_assets: ResolvedVc<OutputAssets>,
94 pub availability_info: AvailabilityInfo,
95}
96
97#[turbo_tasks::value(shared)]
98pub struct EntryChunkGroupResult {
99 pub asset: ResolvedVc<Box<dyn OutputAsset>>,
100 pub availability_info: AvailabilityInfo,
101}
102
103#[derive(
104 Default,
105 Debug,
106 Clone,
107 PartialEq,
108 Eq,
109 Hash,
110 Serialize,
111 Deserialize,
112 TraceRawVcs,
113 NonLocalValue,
114 TaskInput,
115)]
116pub struct ChunkingConfig {
117 pub min_chunk_size: usize,
120
121 pub max_chunk_count_per_group: usize,
124
125 pub max_merge_chunk_size: usize,
128
129 #[allow(dead_code)]
130 pub placeholder_for_future_extensions: (),
131}
132
133#[turbo_tasks::value(transparent)]
134pub struct ChunkingConfigs(FxHashMap<ResolvedVc<Box<dyn ChunkType>>, ChunkingConfig>);
135
136#[turbo_tasks::value(shared)]
137#[derive(Debug, Clone, Copy, Hash, TaskInput, Default)]
138pub enum SourceMapSourceType {
139 AbsoluteFileUri,
140 RelativeUri,
141 #[default]
142 TurbopackUri,
143}
144
145#[turbo_tasks::value_trait]
147pub trait ChunkingContext {
148 #[turbo_tasks::function]
149 fn name(self: Vc<Self>) -> Vc<RcStr>;
150 #[turbo_tasks::function]
151 fn source_map_source_type(self: Vc<Self>) -> Vc<SourceMapSourceType>;
152 #[turbo_tasks::function]
154 fn root_path(self: Vc<Self>) -> Vc<FileSystemPath>;
155 #[turbo_tasks::function]
157 fn output_root(self: Vc<Self>) -> Vc<FileSystemPath>;
158 #[turbo_tasks::function]
161 fn output_root_to_root_path(self: Vc<Self>) -> Vc<RcStr>;
162
163 #[turbo_tasks::function]
166 fn environment(self: Vc<Self>) -> Vc<Environment>;
167
168 #[turbo_tasks::function]
171 fn chunk_root_path(self: Vc<Self>) -> Vc<FileSystemPath>;
172
173 #[turbo_tasks::function]
178 fn chunk_path(
179 self: Vc<Self>,
180 asset: Option<Vc<Box<dyn Asset>>>,
181 ident: Vc<AssetIdent>,
182 content_hashing_prefix: Option<RcStr>,
183 extension: RcStr,
184 ) -> Vc<FileSystemPath>;
185
186 #[turbo_tasks::function]
188 fn reference_chunk_source_maps(self: Vc<Self>, chunk: Vc<Box<dyn OutputAsset>>) -> Vc<bool>;
189
190 #[turbo_tasks::function]
192 fn reference_module_source_maps(self: Vc<Self>, module: Vc<Box<dyn Module>>) -> Vc<bool>;
193
194 #[turbo_tasks::function]
199 fn asset_url(self: Vc<Self>, ident: FileSystemPath, tag: Option<RcStr>) -> Result<Vc<RcStr>>;
200
201 #[turbo_tasks::function]
202 fn asset_path(
203 self: Vc<Self>,
204 content_hash: RcStr,
205 original_asset_ident: Vc<AssetIdent>,
206 tag: Option<RcStr>,
207 ) -> Vc<FileSystemPath>;
208
209 #[turbo_tasks::function]
210 fn is_hot_module_replacement_enabled(self: Vc<Self>) -> Vc<bool> {
211 Vc::cell(false)
212 }
213
214 #[turbo_tasks::function]
215 fn chunking_configs(self: Vc<Self>) -> Vc<ChunkingConfigs> {
216 Vc::cell(Default::default())
217 }
218
219 #[turbo_tasks::function]
220 fn batching_config(self: Vc<Self>) -> Vc<BatchingConfig> {
221 BatchingConfig::new(BatchingConfig {
222 ..Default::default()
223 })
224 }
225
226 #[turbo_tasks::function]
229 fn is_tracing_enabled(self: Vc<Self>) -> Vc<bool> {
230 Vc::cell(false)
231 }
232
233 #[turbo_tasks::function]
235 fn is_module_merging_enabled(self: Vc<Self>) -> Vc<bool> {
236 Vc::cell(false)
237 }
238
239 #[turbo_tasks::function]
242 fn is_dynamic_chunk_content_loading_enabled(self: Vc<Self>) -> Vc<bool> {
243 Vc::cell(false)
244 }
245
246 #[turbo_tasks::function]
247 fn minify_type(self: Vc<Self>) -> Vc<MinifyType> {
248 MinifyType::NoMinify.cell()
249 }
250
251 #[turbo_tasks::function]
252 fn should_use_absolute_url_references(self: Vc<Self>) -> Vc<bool> {
253 Vc::cell(false)
254 }
255
256 #[turbo_tasks::function]
257 fn async_loader_chunk_item(
258 &self,
259 module: Vc<Box<dyn ChunkableModule>>,
260 module_graph: Vc<ModuleGraph>,
261 availability_info: AvailabilityInfo,
262 ) -> Vc<Box<dyn ChunkItem>>;
263 #[turbo_tasks::function]
264 fn async_loader_chunk_item_id(&self, module: Vc<Box<dyn ChunkableModule>>) -> Vc<ModuleId>;
265
266 #[turbo_tasks::function]
267 fn chunk_group(
268 self: Vc<Self>,
269 ident: Vc<AssetIdent>,
270 chunk_group: ChunkGroup,
271 module_graph: Vc<ModuleGraph>,
272 availability_info: AvailabilityInfo,
273 ) -> Vc<ChunkGroupResult>;
274
275 #[turbo_tasks::function]
276 fn evaluated_chunk_group(
277 self: Vc<Self>,
278 ident: Vc<AssetIdent>,
279 chunk_group: ChunkGroup,
280 module_graph: Vc<ModuleGraph>,
281 availability_info: AvailabilityInfo,
282 ) -> Vc<ChunkGroupResult>;
283
284 #[turbo_tasks::function]
289 fn entry_chunk_group(
290 self: Vc<Self>,
291 path: FileSystemPath,
292 evaluatable_assets: Vc<EvaluatableAssets>,
293 module_graph: Vc<ModuleGraph>,
294 extra_chunks: Vc<OutputAssets>,
295 extra_referenced_assets: Vc<OutputAssets>,
296 availability_info: AvailabilityInfo,
297 ) -> Result<Vc<EntryChunkGroupResult>>;
298
299 #[turbo_tasks::function]
300 async fn chunk_item_id_from_ident(
301 self: Vc<Self>,
302 ident: Vc<AssetIdent>,
303 ) -> Result<Vc<ModuleId>>;
304
305 #[turbo_tasks::function]
306 fn chunk_item_id(self: Vc<Self>, module: Vc<Box<dyn ChunkItem>>) -> Vc<ModuleId> {
307 self.chunk_item_id_from_ident(module.asset_ident())
308 }
309 #[turbo_tasks::function]
310 fn chunk_item_id_from_module(self: Vc<Self>, module: Vc<Box<dyn Module>>) -> Vc<ModuleId> {
311 self.chunk_item_id_from_ident(module.ident())
312 }
313
314 #[turbo_tasks::function]
315 async fn module_export_usage(
316 self: Vc<Self>,
317 module: Vc<Box<dyn Module>>,
318 ) -> Result<Vc<ModuleExportUsage>>;
319
320 #[turbo_tasks::function]
322 fn debug_ids_enabled(self: Vc<Self>) -> Vc<bool>;
323}
324
325pub trait ChunkingContextExt {
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 where
333 Self: Send;
334
335 fn root_chunk_group_assets(
336 self: Vc<Self>,
337 ident: Vc<AssetIdent>,
338 chunk_group: ChunkGroup,
339 module_graph: Vc<ModuleGraph>,
340 ) -> Vc<OutputAssetsWithReferenced>
341 where
342 Self: Send;
343
344 fn evaluated_chunk_group_assets(
345 self: Vc<Self>,
346 ident: Vc<AssetIdent>,
347 chunk_group: ChunkGroup,
348 module_graph: Vc<ModuleGraph>,
349 availability_info: AvailabilityInfo,
350 ) -> Vc<OutputAssetsWithReferenced>
351 where
352 Self: Send;
353
354 fn entry_chunk_group_asset(
355 self: Vc<Self>,
356 path: FileSystemPath,
357 evaluatable_assets: Vc<EvaluatableAssets>,
358 module_graph: Vc<ModuleGraph>,
359 extra_chunks: Vc<OutputAssets>,
360 extra_referenced_assets: Vc<OutputAssets>,
361 availability_info: AvailabilityInfo,
362 ) -> Vc<Box<dyn OutputAsset>>
363 where
364 Self: Send;
365
366 fn root_entry_chunk_group(
367 self: Vc<Self>,
368 path: FileSystemPath,
369 evaluatable_assets: Vc<EvaluatableAssets>,
370 module_graph: Vc<ModuleGraph>,
371 extra_chunks: Vc<OutputAssets>,
372 extra_referenced_assets: Vc<OutputAssets>,
373 ) -> Vc<EntryChunkGroupResult>
374 where
375 Self: Send;
376
377 fn root_entry_chunk_group_asset(
378 self: Vc<Self>,
379 path: FileSystemPath,
380 evaluatable_assets: Vc<EvaluatableAssets>,
381 module_graph: Vc<ModuleGraph>,
382 extra_chunks: Vc<OutputAssets>,
383 extra_referenced_assets: Vc<OutputAssets>,
384 ) -> Vc<Box<dyn OutputAsset>>
385 where
386 Self: Send;
387
388 fn chunk_group_assets(
389 self: Vc<Self>,
390 ident: Vc<AssetIdent>,
391 chunk_group: ChunkGroup,
392 module_graph: Vc<ModuleGraph>,
393 availability_info: AvailabilityInfo,
394 ) -> Vc<OutputAssetsWithReferenced>
395 where
396 Self: Send;
397
398 fn relative_path_from_chunk_root_to_project_root(self: Vc<Self>) -> Vc<RcStr>
402 where
403 Self: Send;
404}
405
406impl<T: ChunkingContext + Send + Upcast<Box<dyn ChunkingContext>>> ChunkingContextExt for T {
407 fn root_chunk_group(
408 self: Vc<Self>,
409 ident: Vc<AssetIdent>,
410 chunk_group: ChunkGroup,
411 module_graph: Vc<ModuleGraph>,
412 ) -> Vc<ChunkGroupResult> {
413 self.chunk_group(ident, chunk_group, module_graph, AvailabilityInfo::Root)
414 }
415
416 fn root_chunk_group_assets(
417 self: Vc<Self>,
418 ident: Vc<AssetIdent>,
419 chunk_group: ChunkGroup,
420 module_graph: Vc<ModuleGraph>,
421 ) -> Vc<OutputAssetsWithReferenced> {
422 root_chunk_group_assets(
423 Vc::upcast_non_strict(self),
424 ident,
425 chunk_group,
426 module_graph,
427 )
428 }
429
430 fn evaluated_chunk_group_assets(
431 self: Vc<Self>,
432 ident: Vc<AssetIdent>,
433 chunk_group: ChunkGroup,
434 module_graph: Vc<ModuleGraph>,
435 availability_info: AvailabilityInfo,
436 ) -> Vc<OutputAssetsWithReferenced> {
437 evaluated_chunk_group_assets(
438 Vc::upcast_non_strict(self),
439 ident,
440 chunk_group,
441 module_graph,
442 availability_info,
443 )
444 }
445
446 fn entry_chunk_group_asset(
447 self: Vc<Self>,
448 path: FileSystemPath,
449 evaluatable_assets: Vc<EvaluatableAssets>,
450 module_graph: Vc<ModuleGraph>,
451 extra_chunks: Vc<OutputAssets>,
452 extra_referenced_assets: Vc<OutputAssets>,
453 availability_info: AvailabilityInfo,
454 ) -> Vc<Box<dyn OutputAsset>> {
455 entry_chunk_group_asset(
456 Vc::upcast_non_strict(self),
457 path,
458 evaluatable_assets,
459 module_graph,
460 extra_chunks,
461 extra_referenced_assets,
462 availability_info,
463 )
464 }
465
466 fn root_entry_chunk_group(
467 self: Vc<Self>,
468 path: FileSystemPath,
469 evaluatable_assets: Vc<EvaluatableAssets>,
470 module_graph: Vc<ModuleGraph>,
471 extra_chunks: Vc<OutputAssets>,
472 extra_referenced_assets: Vc<OutputAssets>,
473 ) -> Vc<EntryChunkGroupResult> {
474 self.entry_chunk_group(
475 path,
476 evaluatable_assets,
477 module_graph,
478 extra_chunks,
479 extra_referenced_assets,
480 AvailabilityInfo::Root,
481 )
482 }
483
484 fn root_entry_chunk_group_asset(
485 self: Vc<Self>,
486 path: FileSystemPath,
487 evaluatable_assets: Vc<EvaluatableAssets>,
488 module_graph: Vc<ModuleGraph>,
489 extra_chunks: Vc<OutputAssets>,
490 extra_referenced_assets: Vc<OutputAssets>,
491 ) -> Vc<Box<dyn OutputAsset>> {
492 entry_chunk_group_asset(
493 Vc::upcast_non_strict(self),
494 path,
495 evaluatable_assets,
496 module_graph,
497 extra_chunks,
498 extra_referenced_assets,
499 AvailabilityInfo::Root,
500 )
501 }
502
503 fn chunk_group_assets(
504 self: Vc<Self>,
505 ident: Vc<AssetIdent>,
506 chunk_group: ChunkGroup,
507 module_graph: Vc<ModuleGraph>,
508 availability_info: AvailabilityInfo,
509 ) -> Vc<OutputAssetsWithReferenced> {
510 chunk_group_assets(
511 Vc::upcast_non_strict(self),
512 ident,
513 chunk_group,
514 module_graph,
515 availability_info,
516 )
517 }
518
519 fn relative_path_from_chunk_root_to_project_root(self: Vc<Self>) -> Vc<RcStr> {
520 relative_path_from_chunk_root_to_project_root(Vc::upcast_non_strict(self))
521 }
522}
523
524#[turbo_tasks::function]
525async fn relative_path_from_chunk_root_to_project_root(
526 chunking_context: Vc<Box<dyn ChunkingContext>>,
527) -> Result<Vc<RcStr>> {
528 let chunk_root_path = chunking_context.chunk_root_path().await?;
544 let output_root = chunking_context.output_root().await?;
545 let chunk_to_output_root = chunk_root_path.get_relative_path_to(&output_root);
546 let Some(chunk_to_output_root) = chunk_to_output_root else {
547 bail!(
548 "expected chunk_root_path: {chunk_root_path} to be inside of output_root: \
549 {output_root}",
550 chunk_root_path = chunk_root_path.value_to_string().await?,
551 output_root = output_root.value_to_string().await?
552 );
553 };
554 let output_root_to_chunk_root_path = chunking_context.output_root_to_root_path().await?;
555
556 Ok(Vc::cell(
558 format!(
559 "{}/{}",
560 chunk_to_output_root, output_root_to_chunk_root_path
561 )
562 .into(),
563 ))
564}
565
566#[turbo_tasks::function]
567async fn root_chunk_group_assets(
568 chunking_context: Vc<Box<dyn ChunkingContext>>,
569 ident: Vc<AssetIdent>,
570 chunk_group: ChunkGroup,
571 module_graph: Vc<ModuleGraph>,
572) -> Result<Vc<OutputAssetsWithReferenced>> {
573 let root_chunk_group = chunking_context
574 .root_chunk_group(ident, chunk_group, module_graph)
575 .await?;
576 Ok(OutputAssetsWithReferenced {
577 assets: root_chunk_group.assets,
578 referenced_assets: root_chunk_group.referenced_assets,
579 }
580 .cell())
581}
582
583#[turbo_tasks::function]
584async fn evaluated_chunk_group_assets(
585 chunking_context: Vc<Box<dyn ChunkingContext>>,
586 ident: Vc<AssetIdent>,
587 chunk_group: ChunkGroup,
588 module_graph: Vc<ModuleGraph>,
589 availability_info: AvailabilityInfo,
590) -> Result<Vc<OutputAssetsWithReferenced>> {
591 let evaluated_chunk_group = chunking_context
592 .evaluated_chunk_group(ident, chunk_group, module_graph, availability_info)
593 .await?;
594 Ok(OutputAssetsWithReferenced {
595 assets: evaluated_chunk_group.assets,
596 referenced_assets: evaluated_chunk_group.referenced_assets,
597 }
598 .cell())
599}
600
601#[turbo_tasks::function]
602async fn entry_chunk_group_asset(
603 chunking_context: Vc<Box<dyn ChunkingContext>>,
604 path: FileSystemPath,
605 evaluatable_assets: Vc<EvaluatableAssets>,
606 module_graph: Vc<ModuleGraph>,
607 extra_chunks: Vc<OutputAssets>,
608 extra_referenced_assets: Vc<OutputAssets>,
609 availability_info: AvailabilityInfo,
610) -> Result<Vc<Box<dyn OutputAsset>>> {
611 Ok(*chunking_context
612 .entry_chunk_group(
613 path,
614 evaluatable_assets,
615 module_graph,
616 extra_chunks,
617 extra_referenced_assets,
618 availability_info,
619 )
620 .await?
621 .asset)
622}
623
624#[turbo_tasks::function]
625async fn chunk_group_assets(
626 chunking_context: Vc<Box<dyn ChunkingContext>>,
627 ident: Vc<AssetIdent>,
628 chunk_group: ChunkGroup,
629 module_graph: Vc<ModuleGraph>,
630 availability_info: AvailabilityInfo,
631) -> Result<Vc<OutputAssetsWithReferenced>> {
632 let chunk_group = chunking_context
633 .chunk_group(ident, chunk_group, module_graph, availability_info)
634 .await?;
635 Ok(OutputAssetsWithReferenced {
636 assets: chunk_group.assets,
637 referenced_assets: chunk_group.referenced_assets,
638 }
639 .cell())
640}