turbopack_core/chunk/
chunking_context.rs

1use anyhow::{Result, bail};
2use bincode::{Decode, Encode};
3use rustc_hash::{FxHashMap, FxHashSet};
4use serde::{Deserialize, Serialize};
5use turbo_rcstr::RcStr;
6use turbo_tasks::{NonLocalValue, ResolvedVc, TaskInput, Upcast, Vc, trace::TraceRawVcs};
7use turbo_tasks_fs::FileSystemPath;
8use turbo_tasks_hash::DeterministicHash;
9
10use crate::{
11    asset::Asset,
12    chunk::{
13        ChunkItem, ChunkType, ChunkableModule, EvaluatableAssets,
14        availability_info::AvailabilityInfo, chunk_id_strategy::ModuleIdStrategy,
15    },
16    environment::Environment,
17    ident::AssetIdent,
18    module::Module,
19    module_graph::{
20        ModuleGraph, binding_usage_info::ModuleExportUsage, chunk_group_info::ChunkGroup,
21        module_batches::BatchingConfig,
22    },
23    output::{
24        ExpandOutputAssetsInput, OutputAsset, OutputAssets, OutputAssetsReferences,
25        OutputAssetsWithReferenced, expand_output_assets,
26    },
27    reference::ModuleReference,
28};
29
30#[derive(
31    Debug,
32    TaskInput,
33    Clone,
34    Copy,
35    PartialEq,
36    Eq,
37    Hash,
38    Deserialize,
39    TraceRawVcs,
40    DeterministicHash,
41    NonLocalValue,
42    Encode,
43    Decode,
44)]
45#[serde(rename_all = "kebab-case")]
46pub enum MangleType {
47    OptimalSize,
48    Deterministic,
49}
50
51#[turbo_tasks::value(shared)]
52#[derive(Debug, TaskInput, Clone, Copy, Hash, DeterministicHash, Deserialize)]
53pub enum MinifyType {
54    // TODO instead of adding a new property here,
55    // refactor that to Minify(MinifyOptions) to allow defaults on MinifyOptions
56    Minify { mangle: Option<MangleType> },
57    NoMinify,
58}
59
60impl Default for MinifyType {
61    fn default() -> Self {
62        Self::Minify {
63            mangle: Some(MangleType::OptimalSize),
64        }
65    }
66}
67
68#[turbo_tasks::value(shared)]
69#[derive(Debug, Default, TaskInput, Clone, Copy, Hash, DeterministicHash)]
70pub enum SourceMapsType {
71    /// Extracts source maps from input files and writes source maps for output files.
72    #[default]
73    Full,
74    /// Ignores existing input source maps, but writes source maps for output files.
75    Partial,
76    /// Ignores the existence of source maps and does not write source maps for output files.
77    None,
78}
79
80/// Suffix to append to asset URLs.
81#[turbo_tasks::value(shared)]
82#[derive(Debug, Clone)]
83pub enum AssetSuffix {
84    /// No suffix.
85    None,
86    /// A constant suffix to append to URLs.
87    Constant(RcStr),
88    /// Infer the suffix at runtime from the script src attribute.
89    /// Only valid in browser runtime for chunk loading, not for static asset URL generation.
90    Inferred,
91    /// Read the suffix from a global variable at runtime.
92    /// Used for server-side rendering where the suffix is set via `globalThis.{global_name}`.
93    FromGlobal(RcStr),
94}
95
96/// URL behavior configuration for static assets.
97#[turbo_tasks::value(shared)]
98#[derive(Debug, Clone)]
99pub struct UrlBehavior {
100    pub suffix: AssetSuffix,
101}
102
103#[derive(
104    Debug,
105    TaskInput,
106    Clone,
107    Copy,
108    PartialEq,
109    Eq,
110    Hash,
111    Serialize,
112    Deserialize,
113    TraceRawVcs,
114    DeterministicHash,
115    NonLocalValue,
116    Encode,
117    Decode,
118)]
119pub enum ChunkGroupType {
120    Entry,
121    Evaluated,
122}
123
124#[turbo_tasks::value(shared)]
125#[derive(Clone)]
126pub struct ChunkGroupResult {
127    pub assets: ResolvedVc<OutputAssets>,
128    pub referenced_assets: ResolvedVc<OutputAssets>,
129    pub references: ResolvedVc<OutputAssetsReferences>,
130    pub availability_info: AvailabilityInfo,
131}
132
133impl ChunkGroupResult {
134    pub fn empty() -> Vc<Self> {
135        ChunkGroupResult {
136            assets: ResolvedVc::cell(vec![]),
137            referenced_assets: ResolvedVc::cell(vec![]),
138            references: ResolvedVc::cell(vec![]),
139            availability_info: AvailabilityInfo::root(),
140        }
141        .cell()
142    }
143
144    pub fn empty_resolved() -> ResolvedVc<Self> {
145        ChunkGroupResult {
146            assets: ResolvedVc::cell(vec![]),
147            referenced_assets: ResolvedVc::cell(vec![]),
148            references: ResolvedVc::cell(vec![]),
149            availability_info: AvailabilityInfo::root(),
150        }
151        .resolved_cell()
152    }
153}
154
155#[turbo_tasks::value_impl]
156impl ChunkGroupResult {
157    #[turbo_tasks::function]
158    pub async fn output_assets_with_referenced(&self) -> Result<Vc<OutputAssetsWithReferenced>> {
159        Ok(OutputAssetsWithReferenced {
160            assets: self.assets,
161            referenced_assets: self.referenced_assets,
162            references: self.references,
163        }
164        .cell())
165    }
166
167    #[turbo_tasks::function]
168    pub async fn concatenate(&self, next: Vc<Self>) -> Result<Vc<Self>> {
169        let next = next.await?;
170        Ok(ChunkGroupResult {
171            assets: self.assets.concatenate(*next.assets).to_resolved().await?,
172            referenced_assets: self
173                .referenced_assets
174                .concatenate(*next.referenced_assets)
175                .to_resolved()
176                .await?,
177            references: self
178                .references
179                .concatenate(*next.references)
180                .to_resolved()
181                .await?,
182            availability_info: next.availability_info,
183        }
184        .cell())
185    }
186
187    #[turbo_tasks::function]
188    pub async fn all_assets(&self) -> Result<Vc<OutputAssets>> {
189        Ok(Vc::cell(
190            expand_output_assets(
191                self.assets
192                    .await?
193                    .into_iter()
194                    .chain(self.referenced_assets.await?.into_iter())
195                    .copied()
196                    .map(ExpandOutputAssetsInput::Asset)
197                    .chain(
198                        self.references
199                            .await?
200                            .into_iter()
201                            .copied()
202                            .map(ExpandOutputAssetsInput::Reference),
203                    ),
204                false,
205            )
206            .await?,
207        ))
208    }
209
210    /// Returns only primary asset entries. Doesn't expand OutputAssets. Doesn't return referenced
211    /// assets.
212    #[turbo_tasks::function]
213    pub fn primary_assets(&self) -> Vc<OutputAssets> {
214        *self.assets
215    }
216
217    #[turbo_tasks::function]
218    pub async fn referenced_assets(&self) -> Result<Vc<OutputAssets>> {
219        Ok(Vc::cell(
220            expand_output_assets(
221                self.referenced_assets
222                    .await?
223                    .into_iter()
224                    .copied()
225                    .map(ExpandOutputAssetsInput::Asset)
226                    .chain(
227                        self.references
228                            .await?
229                            .into_iter()
230                            .copied()
231                            .map(ExpandOutputAssetsInput::Reference),
232                    ),
233                false,
234            )
235            .await?,
236        ))
237    }
238}
239
240#[turbo_tasks::value(shared)]
241pub struct EntryChunkGroupResult {
242    pub asset: ResolvedVc<Box<dyn OutputAsset>>,
243    pub availability_info: AvailabilityInfo,
244}
245
246#[derive(
247    Default,
248    Debug,
249    Clone,
250    PartialEq,
251    Eq,
252    Hash,
253    TraceRawVcs,
254    NonLocalValue,
255    TaskInput,
256    Encode,
257    Decode,
258)]
259pub struct ChunkingConfig {
260    /// Try to avoid creating more than 1 chunk smaller than this size.
261    /// It merges multiple small chunks into bigger ones to avoid that.
262    pub min_chunk_size: usize,
263
264    /// Try to avoid creating more than this number of chunks per group.
265    /// It merges multiple chunks into bigger ones to avoid that.
266    pub max_chunk_count_per_group: usize,
267
268    /// Never merges chunks bigger than this size with other chunks.
269    /// This makes sure that code in big chunks is not duplicated in multiple chunks.
270    pub max_merge_chunk_size: usize,
271
272    #[allow(dead_code)]
273    pub placeholder_for_future_extensions: (),
274}
275
276#[turbo_tasks::value(transparent)]
277pub struct ChunkingConfigs(FxHashMap<ResolvedVc<Box<dyn ChunkType>>, ChunkingConfig>);
278
279#[turbo_tasks::value(shared)]
280#[derive(Debug, Clone, Copy, Hash, TaskInput, Default, Deserialize)]
281pub enum SourceMapSourceType {
282    AbsoluteFileUri,
283    RelativeUri,
284    #[default]
285    TurbopackUri,
286}
287
288#[turbo_tasks::value(transparent, cell = "keyed")]
289pub struct UnusedReferences(FxHashSet<ResolvedVc<Box<dyn ModuleReference>>>);
290
291/// A context for the chunking that influences the way chunks are created
292#[turbo_tasks::value_trait]
293pub trait ChunkingContext {
294    #[turbo_tasks::function]
295    fn name(self: Vc<Self>) -> Vc<RcStr>;
296    #[turbo_tasks::function]
297    fn source_map_source_type(self: Vc<Self>) -> Vc<SourceMapSourceType>;
298    /// The root path of the project
299    #[turbo_tasks::function]
300    fn root_path(self: Vc<Self>) -> Vc<FileSystemPath>;
301    /// The output root path in the output filesystem
302    #[turbo_tasks::function]
303    fn output_root(self: Vc<Self>) -> Vc<FileSystemPath>;
304    /// A relative path how to reach the root path from the output root. This is used to compute
305    /// original paths at runtime relative to the output files. e. g. import.meta.url needs that.
306    #[turbo_tasks::function]
307    fn output_root_to_root_path(self: Vc<Self>) -> Vc<RcStr>;
308
309    // TODO remove this, a chunking context should not be bound to a specific
310    // environment since this can change due to transitions in the module graph
311    #[turbo_tasks::function]
312    fn environment(self: Vc<Self>) -> Vc<Environment>;
313
314    /// The path to the folder where all chunks are placed. This can be used to compute relative
315    /// paths.
316    #[turbo_tasks::function]
317    fn chunk_root_path(self: Vc<Self>) -> Vc<FileSystemPath>;
318
319    // TODO(alexkirsz) Remove this from the chunking context. This should be at the
320    // discretion of chunking context implementors. However, we currently use this
321    // in a couple of places in `turbopack-css`, so we need to remove that
322    // dependency first.
323    #[turbo_tasks::function]
324    fn chunk_path(
325        self: Vc<Self>,
326        asset: Option<Vc<Box<dyn Asset>>>,
327        ident: Vc<AssetIdent>,
328        content_hashing_prefix: Option<RcStr>,
329        extension: RcStr,
330    ) -> Vc<FileSystemPath>;
331
332    /// Reference Source Map Assets for chunks
333    #[turbo_tasks::function]
334    fn reference_chunk_source_maps(self: Vc<Self>, chunk: Vc<Box<dyn OutputAsset>>) -> Vc<bool>;
335
336    /// Include Source Maps for modules
337    #[turbo_tasks::function]
338    fn reference_module_source_maps(self: Vc<Self>, module: Vc<Box<dyn Module>>) -> Vc<bool>;
339
340    /// Returns a URL (relative or absolute, depending on the asset prefix) to
341    /// the static asset based on its `ident`.
342    /// The `tag` is an arbitrary string that can be used to distinguish
343    /// different usages of the same asset (e.g. different base paths).
344    #[turbo_tasks::function]
345    fn asset_url(self: Vc<Self>, ident: FileSystemPath, tag: Option<RcStr>) -> Result<Vc<RcStr>>;
346
347    #[turbo_tasks::function]
348    fn asset_path(
349        self: Vc<Self>,
350        content_hash: RcStr,
351        original_asset_ident: Vc<AssetIdent>,
352        tag: Option<RcStr>,
353    ) -> Vc<FileSystemPath>;
354
355    /// Returns the URL behavior for a given tag.
356    /// This determines how asset URLs are suffixed (e.g., for deployment IDs).
357    #[turbo_tasks::function]
358    fn url_behavior(self: Vc<Self>, _tag: Option<RcStr>) -> Vc<UrlBehavior> {
359        UrlBehavior {
360            suffix: AssetSuffix::Inferred,
361        }
362        .cell()
363    }
364
365    #[turbo_tasks::function]
366    fn is_hot_module_replacement_enabled(self: Vc<Self>) -> Vc<bool> {
367        Vc::cell(false)
368    }
369
370    #[turbo_tasks::function]
371    fn chunking_configs(self: Vc<Self>) -> Vc<ChunkingConfigs> {
372        Vc::cell(Default::default())
373    }
374
375    #[turbo_tasks::function]
376    fn batching_config(self: Vc<Self>) -> Vc<BatchingConfig> {
377        BatchingConfig::new(BatchingConfig {
378            ..Default::default()
379        })
380    }
381
382    /// Whether `ChunkingType::Traced` are used to create corresponding output assets for each
383    /// traced module.
384    #[turbo_tasks::function]
385    fn is_tracing_enabled(self: Vc<Self>) -> Vc<bool> {
386        Vc::cell(false)
387    }
388
389    /// Whether async modules should create an new availability boundary and therefore nested async
390    /// modules include less modules. Enabling this will lead to better optimized async chunks,
391    /// but it will require to compute all possible paths in the application, which might lead to
392    /// many combinations.
393    #[turbo_tasks::function]
394    fn is_nested_async_availability_enabled(self: Vc<Self>) -> Vc<bool> {
395        Vc::cell(false)
396    }
397
398    /// Whether to use `MergeableModule` to merge modules if possible.
399    #[turbo_tasks::function]
400    fn is_module_merging_enabled(self: Vc<Self>) -> Vc<bool> {
401        Vc::cell(false)
402    }
403
404    /// Whether to include information about the content of the chunk into the runtime, to allow
405    /// more incremental loading of individual chunk items.
406    #[turbo_tasks::function]
407    fn is_dynamic_chunk_content_loading_enabled(self: Vc<Self>) -> Vc<bool> {
408        Vc::cell(false)
409    }
410
411    #[turbo_tasks::function]
412    fn minify_type(self: Vc<Self>) -> Vc<MinifyType> {
413        MinifyType::NoMinify.cell()
414    }
415
416    #[turbo_tasks::function]
417    fn should_use_absolute_url_references(self: Vc<Self>) -> Vc<bool> {
418        Vc::cell(false)
419    }
420
421    #[turbo_tasks::function]
422    fn async_loader_chunk_item(
423        &self,
424        module: Vc<Box<dyn ChunkableModule>>,
425        module_graph: Vc<ModuleGraph>,
426        availability_info: AvailabilityInfo,
427    ) -> Vc<Box<dyn ChunkItem>>;
428    #[turbo_tasks::function]
429    fn async_loader_chunk_item_ident(&self, module: Vc<Box<dyn ChunkableModule>>)
430    -> Vc<AssetIdent>;
431
432    #[turbo_tasks::function]
433    fn chunk_group(
434        self: Vc<Self>,
435        ident: Vc<AssetIdent>,
436        chunk_group: ChunkGroup,
437        module_graph: Vc<ModuleGraph>,
438        availability_info: AvailabilityInfo,
439    ) -> Vc<ChunkGroupResult>;
440
441    #[turbo_tasks::function]
442    fn evaluated_chunk_group(
443        self: Vc<Self>,
444        ident: Vc<AssetIdent>,
445        chunk_group: ChunkGroup,
446        module_graph: Vc<ModuleGraph>,
447        availability_info: AvailabilityInfo,
448    ) -> Vc<ChunkGroupResult>;
449
450    /// Generates an output chunk that:
451    /// * loads the given extra_chunks in addition to the generated chunks; and
452    /// * evaluates the given assets; and
453    /// * exports the result of evaluating the last module as a CommonJS default export.
454    #[turbo_tasks::function]
455    fn entry_chunk_group(
456        self: Vc<Self>,
457        path: FileSystemPath,
458        evaluatable_assets: Vc<EvaluatableAssets>,
459        module_graph: Vc<ModuleGraph>,
460        extra_chunks: Vc<OutputAssets>,
461        extra_referenced_assets: Vc<OutputAssets>,
462        availability_info: AvailabilityInfo,
463    ) -> Result<Vc<EntryChunkGroupResult>>;
464
465    #[turbo_tasks::function]
466    async fn chunk_item_id_strategy(self: Vc<Self>) -> Result<Vc<ModuleIdStrategy>>;
467
468    #[turbo_tasks::function]
469    async fn module_export_usage(
470        self: Vc<Self>,
471        module: Vc<Box<dyn Module>>,
472    ) -> Result<Vc<ModuleExportUsage>>;
473
474    #[turbo_tasks::function]
475    async fn unused_references(self: Vc<Self>) -> Result<Vc<UnusedReferences>>;
476
477    /// Returns whether debug IDs are enabled for this chunking context.
478    #[turbo_tasks::function]
479    fn debug_ids_enabled(self: Vc<Self>) -> Vc<bool>;
480
481    /// Returns the list of global variable names to forward to workers.
482    /// These globals are read from globalThis at worker creation time and passed
483    /// to the worker via URL params.
484    #[turbo_tasks::function]
485    fn worker_forwarded_globals(self: Vc<Self>) -> Vc<Vec<RcStr>> {
486        Vc::cell(vec![])
487    }
488
489    /// Returns the worker entrypoint for this chunking context.
490    #[turbo_tasks::function]
491    async fn worker_entrypoint(self: Vc<Self>) -> Result<Vc<Box<dyn OutputAsset>>> {
492        bail!(
493            "Worker entrypoint is not supported by {name}",
494            name = self.name().await?
495        );
496    }
497}
498pub trait ChunkingContextExt {
499    fn root_chunk_group(
500        self: Vc<Self>,
501        ident: Vc<AssetIdent>,
502        chunk_group: ChunkGroup,
503        module_graph: Vc<ModuleGraph>,
504    ) -> Vc<ChunkGroupResult>
505    where
506        Self: Send;
507
508    fn root_chunk_group_assets(
509        self: Vc<Self>,
510        ident: Vc<AssetIdent>,
511        chunk_group: ChunkGroup,
512        module_graph: Vc<ModuleGraph>,
513    ) -> Vc<OutputAssetsWithReferenced>
514    where
515        Self: Send;
516
517    fn evaluated_chunk_group_assets(
518        self: Vc<Self>,
519        ident: Vc<AssetIdent>,
520        chunk_group: ChunkGroup,
521        module_graph: Vc<ModuleGraph>,
522        availability_info: AvailabilityInfo,
523    ) -> Vc<OutputAssetsWithReferenced>
524    where
525        Self: Send;
526
527    fn entry_chunk_group_asset(
528        self: Vc<Self>,
529        path: FileSystemPath,
530        evaluatable_assets: Vc<EvaluatableAssets>,
531        module_graph: Vc<ModuleGraph>,
532        extra_chunks: Vc<OutputAssets>,
533        extra_referenced_assets: Vc<OutputAssets>,
534        availability_info: AvailabilityInfo,
535    ) -> Vc<Box<dyn OutputAsset>>
536    where
537        Self: Send;
538
539    fn root_entry_chunk_group(
540        self: Vc<Self>,
541        path: FileSystemPath,
542        evaluatable_assets: Vc<EvaluatableAssets>,
543        module_graph: Vc<ModuleGraph>,
544        extra_chunks: Vc<OutputAssets>,
545        extra_referenced_assets: Vc<OutputAssets>,
546    ) -> Vc<EntryChunkGroupResult>
547    where
548        Self: Send;
549
550    fn root_entry_chunk_group_asset(
551        self: Vc<Self>,
552        path: FileSystemPath,
553        evaluatable_assets: Vc<EvaluatableAssets>,
554        module_graph: Vc<ModuleGraph>,
555        extra_chunks: Vc<OutputAssets>,
556        extra_referenced_assets: Vc<OutputAssets>,
557    ) -> Vc<Box<dyn OutputAsset>>
558    where
559        Self: Send;
560
561    fn chunk_group_assets(
562        self: Vc<Self>,
563        ident: Vc<AssetIdent>,
564        chunk_group: ChunkGroup,
565        module_graph: Vc<ModuleGraph>,
566        availability_info: AvailabilityInfo,
567    ) -> Vc<OutputAssetsWithReferenced>
568    where
569        Self: Send;
570
571    /// Computes the relative path from the chunk output root to the project root.
572    ///
573    /// This is used to compute relative paths for source maps in certain configurations.
574    fn relative_path_from_chunk_root_to_project_root(self: Vc<Self>) -> Vc<RcStr>
575    where
576        Self: Send;
577}
578
579impl<T: ChunkingContext + Send + Upcast<Box<dyn ChunkingContext>>> ChunkingContextExt for T {
580    fn root_chunk_group(
581        self: Vc<Self>,
582        ident: Vc<AssetIdent>,
583        chunk_group: ChunkGroup,
584        module_graph: Vc<ModuleGraph>,
585    ) -> Vc<ChunkGroupResult> {
586        self.chunk_group(ident, chunk_group, module_graph, AvailabilityInfo::root())
587    }
588
589    fn root_chunk_group_assets(
590        self: Vc<Self>,
591        ident: Vc<AssetIdent>,
592        chunk_group: ChunkGroup,
593        module_graph: Vc<ModuleGraph>,
594    ) -> Vc<OutputAssetsWithReferenced> {
595        root_chunk_group_assets(
596            Vc::upcast_non_strict(self),
597            ident,
598            chunk_group,
599            module_graph,
600        )
601    }
602
603    fn evaluated_chunk_group_assets(
604        self: Vc<Self>,
605        ident: Vc<AssetIdent>,
606        chunk_group: ChunkGroup,
607        module_graph: Vc<ModuleGraph>,
608        availability_info: AvailabilityInfo,
609    ) -> Vc<OutputAssetsWithReferenced> {
610        evaluated_chunk_group_assets(
611            Vc::upcast_non_strict(self),
612            ident,
613            chunk_group,
614            module_graph,
615            availability_info,
616        )
617    }
618
619    fn entry_chunk_group_asset(
620        self: Vc<Self>,
621        path: FileSystemPath,
622        evaluatable_assets: Vc<EvaluatableAssets>,
623        module_graph: Vc<ModuleGraph>,
624        extra_chunks: Vc<OutputAssets>,
625        extra_referenced_assets: Vc<OutputAssets>,
626        availability_info: AvailabilityInfo,
627    ) -> Vc<Box<dyn OutputAsset>> {
628        entry_chunk_group_asset(
629            Vc::upcast_non_strict(self),
630            path,
631            evaluatable_assets,
632            module_graph,
633            extra_chunks,
634            extra_referenced_assets,
635            availability_info,
636        )
637    }
638
639    fn root_entry_chunk_group(
640        self: Vc<Self>,
641        path: FileSystemPath,
642        evaluatable_assets: Vc<EvaluatableAssets>,
643        module_graph: Vc<ModuleGraph>,
644        extra_chunks: Vc<OutputAssets>,
645        extra_referenced_assets: Vc<OutputAssets>,
646    ) -> Vc<EntryChunkGroupResult> {
647        self.entry_chunk_group(
648            path,
649            evaluatable_assets,
650            module_graph,
651            extra_chunks,
652            extra_referenced_assets,
653            AvailabilityInfo::root(),
654        )
655    }
656
657    fn root_entry_chunk_group_asset(
658        self: Vc<Self>,
659        path: FileSystemPath,
660        evaluatable_assets: Vc<EvaluatableAssets>,
661        module_graph: Vc<ModuleGraph>,
662        extra_chunks: Vc<OutputAssets>,
663        extra_referenced_assets: Vc<OutputAssets>,
664    ) -> Vc<Box<dyn OutputAsset>> {
665        entry_chunk_group_asset(
666            Vc::upcast_non_strict(self),
667            path,
668            evaluatable_assets,
669            module_graph,
670            extra_chunks,
671            extra_referenced_assets,
672            AvailabilityInfo::root(),
673        )
674    }
675
676    fn chunk_group_assets(
677        self: Vc<Self>,
678        ident: Vc<AssetIdent>,
679        chunk_group: ChunkGroup,
680        module_graph: Vc<ModuleGraph>,
681        availability_info: AvailabilityInfo,
682    ) -> Vc<OutputAssetsWithReferenced> {
683        chunk_group_assets(
684            Vc::upcast_non_strict(self),
685            ident,
686            chunk_group,
687            module_graph,
688            availability_info,
689        )
690    }
691
692    fn relative_path_from_chunk_root_to_project_root(self: Vc<Self>) -> Vc<RcStr> {
693        relative_path_from_chunk_root_to_project_root(Vc::upcast_non_strict(self))
694    }
695}
696
697#[turbo_tasks::function]
698async fn relative_path_from_chunk_root_to_project_root(
699    chunking_context: Vc<Box<dyn ChunkingContext>>,
700) -> Result<Vc<RcStr>> {
701    // Example,
702    //   project root: /project/root
703    //   output root: /project/root/dist
704    //   chunk root path: /project/root/dist/ssr/chunks
705    //   output_root_to_chunk_root: ../
706    //
707    // Example2,
708    //   project root: /project/root
709    //   output root: /project/out
710    //   chunk root path: /project/out/ssr/chunks
711    //   output_root_to_chunk_root: ../root
712    //
713    // From that we want to return  ../../../root to get from a path in `chunks` to a path in the
714    // project root.
715
716    let chunk_root_path = chunking_context.chunk_root_path().await?;
717    let output_root = chunking_context.output_root().await?;
718    let chunk_to_output_root = chunk_root_path.get_relative_path_to(&output_root);
719    let Some(chunk_to_output_root) = chunk_to_output_root else {
720        bail!(
721            "expected chunk_root_path: {chunk_root_path} to be inside of output_root: \
722             {output_root}",
723            chunk_root_path = chunk_root_path.value_to_string().await?,
724            output_root = output_root.value_to_string().await?
725        );
726    };
727    let output_root_to_chunk_root_path = chunking_context.output_root_to_root_path().await?;
728
729    // Note we cannot use `normalize_path` here since it rejects paths that start with `../`
730    Ok(Vc::cell(
731        format!(
732            "{}/{}",
733            chunk_to_output_root, output_root_to_chunk_root_path
734        )
735        .into(),
736    ))
737}
738
739#[turbo_tasks::function]
740fn root_chunk_group_assets(
741    chunking_context: Vc<Box<dyn ChunkingContext>>,
742    ident: Vc<AssetIdent>,
743    chunk_group: ChunkGroup,
744    module_graph: Vc<ModuleGraph>,
745) -> Vc<OutputAssetsWithReferenced> {
746    chunking_context
747        .root_chunk_group(ident, chunk_group, module_graph)
748        .output_assets_with_referenced()
749}
750
751#[turbo_tasks::function]
752fn evaluated_chunk_group_assets(
753    chunking_context: Vc<Box<dyn ChunkingContext>>,
754    ident: Vc<AssetIdent>,
755    chunk_group: ChunkGroup,
756    module_graph: Vc<ModuleGraph>,
757    availability_info: AvailabilityInfo,
758) -> Vc<OutputAssetsWithReferenced> {
759    chunking_context
760        .evaluated_chunk_group(ident, chunk_group, module_graph, availability_info)
761        .output_assets_with_referenced()
762}
763
764#[turbo_tasks::function]
765async fn entry_chunk_group_asset(
766    chunking_context: Vc<Box<dyn ChunkingContext>>,
767    path: FileSystemPath,
768    evaluatable_assets: Vc<EvaluatableAssets>,
769    module_graph: Vc<ModuleGraph>,
770    extra_chunks: Vc<OutputAssets>,
771    extra_referenced_assets: Vc<OutputAssets>,
772    availability_info: AvailabilityInfo,
773) -> Result<Vc<Box<dyn OutputAsset>>> {
774    Ok(*chunking_context
775        .entry_chunk_group(
776            path,
777            evaluatable_assets,
778            module_graph,
779            extra_chunks,
780            extra_referenced_assets,
781            availability_info,
782        )
783        .await?
784        .asset)
785}
786
787#[turbo_tasks::function]
788fn chunk_group_assets(
789    chunking_context: Vc<Box<dyn ChunkingContext>>,
790    ident: Vc<AssetIdent>,
791    chunk_group: ChunkGroup,
792    module_graph: Vc<ModuleGraph>,
793    availability_info: AvailabilityInfo,
794) -> Vc<OutputAssetsWithReferenced> {
795    chunking_context
796        .chunk_group(ident, chunk_group, module_graph, availability_info)
797        .output_assets_with_referenced()
798}