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