Skip to main content

turbopack_core/chunk/
chunking_context.rs

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