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