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