1use anyhow::{Context, Result, bail};
2use tracing::Instrument;
3use turbo_rcstr::{RcStr, rcstr};
4use turbo_tasks::{
5 FxIndexMap, ResolvedVc, TryJoinIterExt, Upcast, ValueToString, ValueToStringRef, Vc,
6};
7use turbo_tasks_fs::FileSystemPath;
8use turbo_tasks_hash::HashAlgorithm;
9use turbopack_core::{
10 asset::{Asset, AssetContent},
11 chunk::{
12 AssetSuffix, Chunk, ChunkGroupResult, ChunkItem, ChunkItemOrBatchWithAsyncModuleInfo,
13 ChunkItemWithAsyncModuleInfo, ChunkType, ChunkableModule, ChunkingConfig, ChunkingConfigs,
14 ChunkingContext, ContentHashing, EntryChunkGroupResult, EvaluatableAsset, MinifyType,
15 SourceMapSourceType, SourceMapsType, UnusedReferences, UrlBehavior,
16 WorkerConfigurationOptions,
17 availability_info::AvailabilityInfo,
18 chunk_group::{MakeChunkGroupResult, make_chunk_group},
19 chunk_id_strategy::ModuleIdStrategy,
20 },
21 environment::Environment,
22 ident::AssetIdent,
23 module::Module,
24 module_graph::{
25 ModuleGraph,
26 binding_usage_info::{BindingUsageInfo, ModuleExportUsage},
27 chunk_group_info::ChunkGroup,
28 },
29 output::{OutputAsset, OutputAssets},
30};
31use turbopack_ecmascript::{
32 async_chunk::module::AsyncLoaderModule,
33 chunk::{EcmascriptChunk, EcmascriptChunkPlaceable},
34 manifest::{chunk_asset::ManifestAsyncModule, loader_module::ManifestLoaderModule},
35};
36use turbopack_ecmascript_runtime::RuntimeType;
37
38use crate::ecmascript::node::{
39 chunk::EcmascriptBuildNodeChunk,
40 entry::{chunk::EcmascriptBuildNodeEntryChunk, chunk_list::EcmascriptBuildNodeChunkList},
41};
42
43pub struct NodeJsChunkingContextBuilder {
45 chunking_context: NodeJsChunkingContext,
46}
47
48impl NodeJsChunkingContextBuilder {
49 pub fn asset_prefix(mut self, asset_prefix: Option<RcStr>) -> Self {
50 self.chunking_context.asset_prefix = asset_prefix;
51 self
52 }
53
54 pub fn asset_prefix_override(mut self, tag: RcStr, prefix: RcStr) -> Self {
55 self.chunking_context.asset_prefixes.insert(tag, prefix);
56 self
57 }
58
59 pub fn asset_root_path_override(mut self, tag: RcStr, path: FileSystemPath) -> Self {
60 self.chunking_context.asset_root_paths.insert(tag, path);
61 self
62 }
63
64 pub fn client_roots_override(mut self, tag: RcStr, path: FileSystemPath) -> Self {
65 self.chunking_context.client_roots.insert(tag, path);
66 self
67 }
68
69 pub fn url_behavior_override(mut self, tag: RcStr, behavior: UrlBehavior) -> Self {
70 self.chunking_context.url_behaviors.insert(tag, behavior);
71 self
72 }
73
74 pub fn default_url_behavior(mut self, behavior: UrlBehavior) -> Self {
75 self.chunking_context.default_url_behavior = Some(behavior);
76 self
77 }
78
79 pub fn minify_type(mut self, minify_type: MinifyType) -> Self {
80 self.chunking_context.minify_type = minify_type;
81 self
82 }
83
84 pub fn source_maps(mut self, source_maps: SourceMapsType) -> Self {
85 self.chunking_context.source_maps_type = source_maps;
86 self
87 }
88
89 pub fn nested_async_availability(mut self, enable_nested_async_availability: bool) -> Self {
90 self.chunking_context.enable_nested_async_availability = enable_nested_async_availability;
91 self
92 }
93
94 pub fn module_merging(mut self, enable_module_merging: bool) -> Self {
95 self.chunking_context.enable_module_merging = enable_module_merging;
96 self
97 }
98
99 pub fn dynamic_chunk_content_loading(
100 mut self,
101 enable_dynamic_chunk_content_loading: bool,
102 ) -> Self {
103 self.chunking_context.enable_dynamic_chunk_content_loading =
104 enable_dynamic_chunk_content_loading;
105 self
106 }
107
108 pub fn runtime_type(mut self, runtime_type: RuntimeType) -> Self {
109 self.chunking_context.runtime_type = runtime_type;
110 self
111 }
112
113 pub fn manifest_chunks(mut self, manifest_chunks: bool) -> Self {
114 self.chunking_context.manifest_chunks = manifest_chunks;
115 self
116 }
117
118 pub fn source_map_source_type(mut self, source_map_source_type: SourceMapSourceType) -> Self {
119 self.chunking_context.source_map_source_type = source_map_source_type;
120 self
121 }
122
123 pub fn module_id_strategy(mut self, module_id_strategy: ResolvedVc<ModuleIdStrategy>) -> Self {
124 self.chunking_context.module_id_strategy = Some(module_id_strategy);
125 self
126 }
127
128 pub fn export_usage(mut self, export_usage: Option<ResolvedVc<BindingUsageInfo>>) -> Self {
129 self.chunking_context.export_usage = export_usage;
130 self
131 }
132
133 pub fn unused_references(mut self, unused_references: ResolvedVc<UnusedReferences>) -> Self {
134 self.chunking_context.unused_references = Some(unused_references);
135 self
136 }
137
138 pub fn chunking_config<T>(mut self, ty: ResolvedVc<T>, chunking_config: ChunkingConfig) -> Self
139 where
140 T: Upcast<Box<dyn ChunkType>>,
141 {
142 self.chunking_context
143 .chunking_configs
144 .push((ResolvedVc::upcast_non_strict(ty), chunking_config));
145 self
146 }
147
148 pub fn debug_ids(mut self, debug_ids: bool) -> Self {
149 self.chunking_context.debug_ids = debug_ids;
150 self
151 }
152
153 pub fn worker_forwarded_globals(mut self, globals: Vec<RcStr>) -> Self {
154 self.chunking_context
155 .worker_forwarded_globals
156 .extend(globals);
157 self
158 }
159
160 pub fn asset_content_hashing(mut self, content_hashing: ContentHashing) -> Self {
161 self.chunking_context.asset_content_hashing = content_hashing;
162 self
163 }
164
165 pub fn hash_salt(mut self, salt: ResolvedVc<RcStr>) -> Self {
166 self.chunking_context.hash_salt = salt;
167 self
168 }
169
170 pub fn shared_runtime_chunk(mut self, shared_runtime_chunk: bool) -> Self {
178 self.chunking_context.shared_runtime_chunk = shared_runtime_chunk;
179 self
180 }
181
182 pub fn build(self) -> Vc<NodeJsChunkingContext> {
184 NodeJsChunkingContext::cell(self.chunking_context)
185 }
186}
187
188#[turbo_tasks::value]
190#[derive(Debug, Clone)]
191pub struct NodeJsChunkingContext {
192 root_path: FileSystemPath,
194 output_root: FileSystemPath,
196 output_root_to_root_path: RcStr,
198 client_root: FileSystemPath,
200 #[bincode(with = "turbo_bincode::indexmap")]
202 client_roots: FxIndexMap<RcStr, FileSystemPath>,
203 chunk_root_path: FileSystemPath,
205 asset_root_path: FileSystemPath,
207 #[bincode(with = "turbo_bincode::indexmap")]
209 asset_root_paths: FxIndexMap<RcStr, FileSystemPath>,
210 asset_prefix: Option<RcStr>,
212 #[bincode(with = "turbo_bincode::indexmap")]
214 asset_prefixes: FxIndexMap<RcStr, RcStr>,
215 #[bincode(with = "turbo_bincode::indexmap")]
217 url_behaviors: FxIndexMap<RcStr, UrlBehavior>,
218 default_url_behavior: Option<UrlBehavior>,
220 environment: ResolvedVc<Environment>,
222 runtime_type: RuntimeType,
224 enable_nested_async_availability: bool,
226 enable_module_merging: bool,
228 enable_dynamic_chunk_content_loading: bool,
230 minify_type: MinifyType,
232 source_maps_type: SourceMapsType,
234 manifest_chunks: bool,
236 module_id_strategy: Option<ResolvedVc<ModuleIdStrategy>>,
238 export_usage: Option<ResolvedVc<BindingUsageInfo>>,
240 unused_references: Option<ResolvedVc<UnusedReferences>>,
242 source_map_source_type: SourceMapSourceType,
244 chunking_configs: Vec<(ResolvedVc<Box<dyn ChunkType>>, ChunkingConfig)>,
246 debug_ids: bool,
248 worker_forwarded_globals: Vec<RcStr>,
250 asset_content_hashing: ContentHashing,
252 hash_salt: ResolvedVc<RcStr>,
254 shared_runtime_chunk: bool,
257}
258
259impl NodeJsChunkingContext {
260 pub fn builder(
262 root_path: FileSystemPath,
263 output_root: FileSystemPath,
264 output_root_to_root_path: RcStr,
265 client_root: FileSystemPath,
266 chunk_root_path: FileSystemPath,
267 asset_root_path: FileSystemPath,
268 environment: ResolvedVc<Environment>,
269 runtime_type: RuntimeType,
270 ) -> NodeJsChunkingContextBuilder {
271 NodeJsChunkingContextBuilder {
272 chunking_context: NodeJsChunkingContext {
273 root_path,
274 output_root,
275 output_root_to_root_path,
276 client_root,
277 client_roots: Default::default(),
278 chunk_root_path,
279 asset_root_path,
280 asset_root_paths: Default::default(),
281 asset_prefix: None,
282 asset_prefixes: Default::default(),
283 url_behaviors: Default::default(),
284 default_url_behavior: None,
285 enable_nested_async_availability: false,
286 enable_module_merging: false,
287 enable_dynamic_chunk_content_loading: false,
288 environment,
289 runtime_type,
290 minify_type: MinifyType::NoMinify,
291 source_maps_type: SourceMapsType::Full,
292 manifest_chunks: false,
293 source_map_source_type: SourceMapSourceType::TurbopackUri,
294 module_id_strategy: None,
295 export_usage: None,
296 unused_references: None,
297 chunking_configs: Default::default(),
298 debug_ids: false,
299 worker_forwarded_globals: vec![],
300 asset_content_hashing: ContentHashing::Direct { length: 13 },
301 hash_salt: ResolvedVc::cell(RcStr::default()),
302 shared_runtime_chunk: false,
303 },
304 }
305 }
306}
307
308#[turbo_tasks::value_impl]
309impl NodeJsChunkingContext {
310 #[turbo_tasks::function]
315 pub fn runtime_type(&self) -> Vc<RuntimeType> {
316 self.runtime_type.cell()
317 }
318
319 #[turbo_tasks::function]
321 pub fn minify_type(&self) -> Vc<MinifyType> {
322 self.minify_type.cell()
323 }
324
325 #[turbo_tasks::function]
326 pub fn hash_salt(&self) -> Vc<RcStr> {
327 *self.hash_salt
328 }
329
330 #[turbo_tasks::function]
331 pub fn asset_prefix(&self) -> Vc<Option<RcStr>> {
332 Vc::cell(self.asset_prefix.clone())
333 }
334
335 #[turbo_tasks::function]
346 pub async fn server_hmr_chunk_list(
347 self: ResolvedVc<Self>,
348 path: FileSystemPath,
349 chunks: Vc<OutputAssets>,
350 ) -> Result<Vc<Box<dyn OutputAsset>>> {
351 #[cfg(debug_assertions)]
352 if !matches!(*self.runtime_type().await?, RuntimeType::Development) {
353 bail!("server_hmr_chunk_list can only be used in development");
354 }
355 Ok(Vc::upcast(EcmascriptBuildNodeChunkList::new(
356 *self, path, chunks,
357 )))
358 }
359
360 #[turbo_tasks::function]
364 pub fn shared_runtime_chunk(&self) -> Vc<bool> {
365 Vc::cell(self.shared_runtime_chunk)
366 }
367}
368
369impl NodeJsChunkingContext {
370 async fn generate_chunk(
371 self: Vc<Self>,
372 chunk: ResolvedVc<Box<dyn Chunk>>,
373 ) -> Result<ResolvedVc<Box<dyn OutputAsset>>> {
374 Ok(
375 if let Some(ecmascript_chunk) = ResolvedVc::try_downcast_type::<EcmascriptChunk>(chunk)
376 {
377 ResolvedVc::upcast(
378 EcmascriptBuildNodeChunk::new(self, *ecmascript_chunk)
379 .to_resolved()
380 .await?,
381 )
382 } else if let Some(output_asset) =
383 ResolvedVc::try_sidecast::<Box<dyn OutputAsset>>(chunk)
384 {
385 output_asset
386 } else {
387 bail!("Unable to generate output asset for chunk");
388 },
389 )
390 }
391}
392
393#[turbo_tasks::value_impl]
394impl ChunkingContext for NodeJsChunkingContext {
395 #[turbo_tasks::function]
396 fn name(&self) -> Vc<RcStr> {
397 Vc::cell(rcstr!("unknown"))
398 }
399
400 #[turbo_tasks::function]
401 fn root_path(&self) -> Vc<FileSystemPath> {
402 self.root_path.clone().cell()
403 }
404
405 #[turbo_tasks::function]
406 fn output_root(&self) -> Vc<FileSystemPath> {
407 self.output_root.clone().cell()
408 }
409
410 #[turbo_tasks::function]
411 fn output_root_to_root_path(&self) -> Vc<RcStr> {
412 Vc::cell(self.output_root_to_root_path.clone())
413 }
414
415 #[turbo_tasks::function]
416 fn environment(&self) -> Vc<Environment> {
417 *self.environment
418 }
419
420 #[turbo_tasks::function]
421 fn is_nested_async_availability_enabled(&self) -> Vc<bool> {
422 Vc::cell(self.enable_nested_async_availability)
423 }
424
425 #[turbo_tasks::function]
426 fn is_module_merging_enabled(&self) -> Vc<bool> {
427 Vc::cell(self.enable_module_merging)
428 }
429
430 #[turbo_tasks::function]
431 fn is_dynamic_chunk_content_loading_enabled(&self) -> Vc<bool> {
432 Vc::cell(self.enable_dynamic_chunk_content_loading)
433 }
434
435 #[turbo_tasks::function]
436 pub fn minify_type(&self) -> Vc<MinifyType> {
437 self.minify_type.cell()
438 }
439
440 #[turbo_tasks::function]
441 async fn asset_url(&self, ident: FileSystemPath, tag: Option<RcStr>) -> Result<Vc<RcStr>> {
442 let asset_path = ident.to_string();
443
444 let client_root = tag
445 .as_ref()
446 .and_then(|tag| self.client_roots.get(tag))
447 .unwrap_or(&self.client_root);
448
449 let asset_prefix = tag
450 .as_ref()
451 .and_then(|tag| self.asset_prefixes.get(tag))
452 .or(self.asset_prefix.as_ref());
453
454 let asset_path = asset_path
455 .strip_prefix(&format!("{}/", client_root.path))
456 .context("expected client root to contain asset path")?;
457
458 Ok(Vc::cell(
459 format!(
460 "{}{}",
461 asset_prefix.map(|s| s.as_str()).unwrap_or("/"),
462 asset_path
463 )
464 .into(),
465 ))
466 }
467
468 #[turbo_tasks::function]
469 fn chunk_root_path(&self) -> Vc<FileSystemPath> {
470 self.chunk_root_path.clone().cell()
471 }
472
473 #[turbo_tasks::function]
474 async fn chunk_path(
475 &self,
476 _asset: Option<Vc<Box<dyn Asset>>>,
477 ident: Vc<AssetIdent>,
478 prefix: Option<RcStr>,
479 extension: RcStr,
480 ) -> Result<Vc<FileSystemPath>> {
481 let root_path = self.chunk_root_path.clone();
482 let name = ident
483 .output_name(self.root_path.clone(), prefix, extension)
484 .owned()
485 .await?;
486 Ok(root_path.join(&name)?.cell())
487 }
488
489 #[turbo_tasks::function]
490 fn reference_chunk_source_maps(&self, _chunk: Vc<Box<dyn OutputAsset>>) -> Vc<bool> {
491 Vc::cell(match self.source_maps_type {
492 SourceMapsType::Full => true,
493 SourceMapsType::Partial => true,
494 SourceMapsType::None => false,
495 })
496 }
497
498 #[turbo_tasks::function]
499 fn reference_module_source_maps(&self, _module: Vc<Box<dyn Module>>) -> Vc<bool> {
500 Vc::cell(match self.source_maps_type {
501 SourceMapsType::Full => true,
502 SourceMapsType::Partial => true,
503 SourceMapsType::None => false,
504 })
505 }
506
507 #[turbo_tasks::function]
508 fn source_map_source_type(&self) -> Vc<SourceMapSourceType> {
509 self.source_map_source_type.cell()
510 }
511
512 #[turbo_tasks::function]
513 fn chunking_configs(&self) -> Result<Vc<ChunkingConfigs>> {
514 Ok(Vc::cell(self.chunking_configs.iter().cloned().collect()))
515 }
516
517 #[turbo_tasks::function]
518 async fn asset_path(
519 self: Vc<Self>,
520 content: Vc<AssetContent>,
521 original_asset_ident: Vc<AssetIdent>,
522 tag: Option<RcStr>,
523 ) -> Result<Vc<FileSystemPath>> {
524 let this = self.await?;
525 let source_path = original_asset_ident.await?.path.clone();
526 let basename = source_path.file_name();
527 let ContentHashing::Direct { length } = this.asset_content_hashing;
528 let hash = content
529 .content_hash(self.hash_salt(), HashAlgorithm::Xxh3Hash128Base38)
530 .await?;
531 let hash = hash
532 .as_ref()
533 .context("Missing content when trying to generate the content hash for static asset")?;
534 let short_hash = &hash[..length as usize];
535 let asset_path = match source_path.extension() {
536 Some(ext) => format!(
537 "{basename}.{short_hash}.{ext}",
538 basename = &basename[..basename.len() - ext.len() - 1],
539 ),
540 None => format!("{basename}.{short_hash}"),
541 };
542
543 let asset_root_path = tag
544 .as_ref()
545 .and_then(|tag| this.asset_root_paths.get(tag))
546 .unwrap_or(&this.asset_root_path);
547
548 Ok(asset_root_path.join(&asset_path)?.cell())
549 }
550
551 #[turbo_tasks::function]
552 fn url_behavior(&self, tag: Option<RcStr>) -> Vc<UrlBehavior> {
553 tag.as_ref()
554 .and_then(|tag| self.url_behaviors.get(tag))
555 .cloned()
556 .or_else(|| self.default_url_behavior.clone())
557 .unwrap_or(UrlBehavior {
558 suffix: AssetSuffix::Inferred,
559 static_suffix: ResolvedVc::cell(None),
560 })
561 .cell()
562 }
563
564 #[turbo_tasks::function]
565 async fn chunk_group(
566 self: ResolvedVc<Self>,
567 ident: Vc<AssetIdent>,
568 chunk_group: ChunkGroup,
569 module_graph: ResolvedVc<ModuleGraph>,
570 availability_info: AvailabilityInfo,
571 ) -> Result<Vc<ChunkGroupResult>> {
572 let span = tracing::info_span!("chunking", name = display(ident.to_string().await?));
573 async move {
574 let MakeChunkGroupResult {
575 chunks,
576 references,
577 availability_info,
578 } = make_chunk_group(
579 chunk_group,
580 module_graph,
581 ResolvedVc::upcast(self),
582 availability_info,
583 )
584 .await?;
585
586 let chunks = chunks.await?;
587
588 let assets = chunks
589 .iter()
590 .map(|chunk| self.generate_chunk(*chunk))
591 .try_join()
592 .await?;
593
594 Ok(ChunkGroupResult {
595 assets: ResolvedVc::cell(assets),
596 referenced_assets: OutputAssets::empty_resolved(),
597 references: ResolvedVc::cell(references),
598 availability_info,
599 chunk_group_bootstrap_params: None,
600 }
601 .cell())
602 }
603 .instrument(span)
604 .await
605 }
606
607 #[turbo_tasks::function]
608 pub async fn entry_chunk_group(
609 self: ResolvedVc<Self>,
610 path: FileSystemPath,
611 chunk_group: ChunkGroup,
612 module_graph: ResolvedVc<ModuleGraph>,
613 extra_chunks: Vc<OutputAssets>,
614 extra_referenced_assets: Vc<OutputAssets>,
615 availability_info: AvailabilityInfo,
616 ) -> Result<Vc<EntryChunkGroupResult>> {
617 let span = tracing::info_span!(
618 "chunking",
619 name = display(path.to_string_ref().await?),
620 chunking_type = "entry",
621 );
622 async move {
623 let MakeChunkGroupResult {
624 chunks,
625 references,
626 availability_info,
627 } = make_chunk_group(
628 chunk_group.clone(),
629 module_graph,
630 ResolvedVc::upcast(self),
631 availability_info,
632 )
633 .await?;
634
635 let chunks = chunks.await?;
636
637 let extra_chunks = extra_chunks.await?;
638 let mut other_chunks = chunks
639 .iter()
640 .map(|chunk| self.generate_chunk(*chunk))
641 .try_join()
642 .await?;
643 other_chunks.extend(extra_chunks.iter().copied());
644
645 let module = chunk_group.entries().last().unwrap();
646 let Some(module) =
647 ResolvedVc::try_sidecast::<Box<dyn EcmascriptChunkPlaceable>>(module)
648 else {
649 bail!("last entry must be EcmascriptChunkPlaceable {:?}", module);
650 };
651
652 let evaluatable_assets = chunk_group
653 .entries()
654 .map(|entry| {
655 ResolvedVc::try_sidecast::<Box<dyn EvaluatableAsset>>(entry).with_context(
656 || {
657 format!(
658 "entry_chunk_group entries must be EvaluatableAssets {:?}",
659 entry
660 )
661 },
662 )
663 })
664 .collect::<Result<Vec<_>>>()?;
665
666 let asset = ResolvedVc::upcast(
667 EcmascriptBuildNodeEntryChunk::new(
668 path,
669 Vc::cell(other_chunks),
670 Vc::cell(evaluatable_assets),
671 *module,
672 extra_referenced_assets,
673 Vc::cell(references),
674 *module_graph,
675 *self,
676 )
677 .to_resolved()
678 .await?,
679 );
680
681 Ok(EntryChunkGroupResult {
682 asset,
683 availability_info,
684 }
685 .cell())
686 }
687 .instrument(span)
688 .await
689 }
690
691 #[turbo_tasks::function]
692 fn evaluated_chunk_group(
693 self: Vc<Self>,
694 _ident: Vc<AssetIdent>,
695 _chunk_group: ChunkGroup,
696 _module_graph: Vc<ModuleGraph>,
697 _extra_chunks: Vc<OutputAssets>,
698 _availability_info: AvailabilityInfo,
699 ) -> Result<Vc<ChunkGroupResult>> {
700 bail!("the Node.js chunking context does not support evaluated chunk groups")
701 }
702
703 #[turbo_tasks::function]
704 fn chunk_item_id_strategy(&self) -> Vc<ModuleIdStrategy> {
705 *self
706 .module_id_strategy
707 .unwrap_or_else(|| ModuleIdStrategy::default().resolved_cell())
708 }
709
710 #[turbo_tasks::function]
711 async fn async_loader_chunk_item(
712 self: Vc<Self>,
713 module: Vc<Box<dyn ChunkableModule>>,
714 module_graph: Vc<ModuleGraph>,
715 availability_info: AvailabilityInfo,
716 ) -> Result<Vc<Box<dyn ChunkItem>>> {
717 let chunking_context: ResolvedVc<Box<dyn ChunkingContext>> =
718 Vc::upcast::<Box<dyn ChunkingContext>>(self)
719 .to_resolved()
720 .await?;
721 let use_manifest = self.await?.manifest_chunks
722 && ResolvedVc::try_downcast::<Box<dyn EcmascriptChunkPlaceable>>(
725 module.to_resolved().await?,
726 )
727 .is_some();
728 Ok(if use_manifest {
729 let manifest_asset = ManifestAsyncModule::new(
730 module,
731 module_graph,
732 *chunking_context,
733 availability_info,
734 )
735 .to_resolved()
736 .await?;
737 let loader_module = ManifestLoaderModule::new(*manifest_asset);
738 loader_module.as_chunk_item(module_graph, *chunking_context)
739 } else {
740 let module = AsyncLoaderModule::new(module, *chunking_context, availability_info);
741 module.as_chunk_item(module_graph, *chunking_context)
742 })
743 }
744
745 #[turbo_tasks::function]
746 async fn standalone_chunk(
747 self: Vc<Self>,
748 chunk_item: ResolvedVc<Box<dyn ChunkItem>>,
749 ) -> Result<Vc<Box<dyn OutputAsset>>> {
750 let chunk_type = chunk_item
751 .into_trait_ref()
752 .await?
753 .ty()
754 .to_resolved()
755 .await?;
756 let chunk = chunk_type
757 .chunk(
758 Vc::upcast(self),
759 vec![ChunkItemOrBatchWithAsyncModuleInfo::ChunkItem(
760 ChunkItemWithAsyncModuleInfo {
761 chunk_item,
762 chunk_type,
763 module: None,
764 async_info: None,
765 },
766 )],
767 Vec::new(),
768 Vec::new(),
769 )
770 .to_resolved()
771 .await?;
772 Ok(*self.generate_chunk(chunk).await?)
773 }
774
775 #[turbo_tasks::function]
776 async fn async_loader_chunk_item_ident(
777 self: Vc<Self>,
778 module: Vc<Box<dyn ChunkableModule>>,
779 ) -> Result<Vc<AssetIdent>> {
780 let use_manifest = self.await?.manifest_chunks
781 && ResolvedVc::try_downcast::<Box<dyn EcmascriptChunkPlaceable>>(
784 module.to_resolved().await?,
785 )
786 .is_some();
787 Ok(if use_manifest {
788 ManifestLoaderModule::asset_ident_for(module)
789 } else {
790 AsyncLoaderModule::asset_ident_for(module)
791 })
792 }
793
794 #[turbo_tasks::function]
795 async fn module_export_usage(
796 &self,
797 module: ResolvedVc<Box<dyn Module>>,
798 ) -> Result<Vc<ModuleExportUsage>> {
799 if let Some(export_usage) = self.export_usage {
800 Ok(export_usage.await?.used_exports(module).await?)
801 } else {
802 Ok(ModuleExportUsage::unknown())
803 }
804 }
805
806 #[turbo_tasks::function]
807 fn unused_references(&self) -> Vc<UnusedReferences> {
808 if let Some(unused_references) = self.unused_references {
809 *unused_references
810 } else {
811 Vc::cell(Default::default())
812 }
813 }
814
815 #[turbo_tasks::function]
816 fn debug_ids_enabled(&self) -> Vc<bool> {
817 Vc::cell(self.debug_ids)
818 }
819
820 #[turbo_tasks::function]
821 fn worker_configuration_options(&self) -> Vc<WorkerConfigurationOptions> {
822 WorkerConfigurationOptions {
823 asset_prefix: None,
824 forwarded_globals: self.worker_forwarded_globals.clone(),
825 }
826 .cell()
827 }
828}