1#![feature(box_patterns)]
2#![feature(trivial_bounds)]
3#![feature(min_specialization)]
4#![feature(map_try_insert)]
5#![feature(hash_set_entry)]
6#![recursion_limit = "256"]
7#![feature(arbitrary_self_types)]
8#![feature(arbitrary_self_types_pointers)]
9
10pub mod evaluate_context;
11pub mod global_module_ids;
12mod graph;
13pub mod module_options;
14pub mod transition;
15
16use anyhow::{Result, bail};
17use css::{CssModuleAsset, ModuleCssAsset};
18use ecmascript::{
19 EcmascriptModuleAsset, EcmascriptModuleAssetType, TreeShakingMode,
20 chunk::EcmascriptChunkPlaceable,
21 references::{FollowExportsResult, follow_reexports},
22 side_effect_optimization::facade::module::EcmascriptModuleFacadeModule,
23};
24use graph::{AggregatedGraph, AggregatedGraphNodeContent, aggregate};
25use module_options::{ModuleOptions, ModuleOptionsContext, ModuleRuleEffect, ModuleType};
26use tracing::{Instrument, field::Empty};
27use turbo_rcstr::{RcStr, rcstr};
28use turbo_tasks::{ResolvedVc, ValueToString, Vc};
29use turbo_tasks_fs::{
30 FileSystemPath,
31 glob::{Glob, GlobOptions},
32};
33pub use turbopack_core::condition;
34use turbopack_core::{
35 asset::Asset,
36 chunk::SourceMapsType,
37 compile_time_info::CompileTimeInfo,
38 context::{AssetContext, ProcessResult},
39 ident::Layer,
40 issue::{IssueExt, IssueSource, StyledString, module::ModuleIssue},
41 module::Module,
42 node_addon_module::NodeAddonModule,
43 output::OutputAsset,
44 raw_module::RawModule,
45 reference_type::{
46 CssReferenceSubType, EcmaScriptModulesReferenceSubType, ImportContext, ImportWithType,
47 InnerAssets, ReferenceType,
48 },
49 resolve::{
50 ExternalTraced, ExternalType, ModulePart, ModuleResolveResult, ModuleResolveResultItem,
51 ResolveResult, ResolveResultItem, options::ResolveOptions, origin::PlainResolveOrigin,
52 parse::Request, resolve,
53 },
54 source::Source,
55};
56pub use turbopack_css as css;
57pub use turbopack_ecmascript as ecmascript;
58use turbopack_ecmascript::{
59 references::external_module::{
60 CachedExternalModule, CachedExternalTracingMode, CachedExternalType,
61 },
62 side_effect_optimization::locals::module::EcmascriptModuleLocalsModule,
63 tree_shake::asset::EcmascriptModulePartAsset,
64};
65use turbopack_json::JsonModuleAsset;
66pub use turbopack_resolve::{resolve::resolve_options, resolve_options_context};
67use turbopack_resolve::{resolve_options_context::ResolveOptionsContext, typescript::type_resolve};
68use turbopack_static::{css::StaticUrlCssModule, ecma::StaticUrlJsModule};
69use turbopack_wasm::{module_asset::WebAssemblyModuleAsset, source::WebAssemblySource};
70
71use self::transition::{Transition, TransitionOptions};
72use crate::module_options::{CssOptionsContext, CustomModuleType, EcmascriptOptionsContext};
73
74#[turbo_tasks::function]
75async fn apply_module_type(
76 source: ResolvedVc<Box<dyn Source>>,
77 module_asset_context: Vc<ModuleAssetContext>,
78 module_type: Vc<ModuleType>,
79 part: Option<ModulePart>,
80 inner_assets: Option<ResolvedVc<InnerAssets>>,
81 css_import_context: Option<Vc<ImportContext>>,
82 runtime_code: bool,
83) -> Result<Vc<ProcessResult>> {
84 let module_type = &*module_type.await?;
85 Ok(ProcessResult::Module(match module_type {
86 ModuleType::Ecmascript {
87 preprocess,
88 main,
89 postprocess,
90 options,
91 }
92 | ModuleType::Typescript {
93 preprocess,
94 main,
95 postprocess,
96 tsx: _,
97 analyze_types: _,
98 options,
99 }
100 | ModuleType::TypescriptDeclaration {
101 preprocess,
102 main,
103 postprocess,
104 options,
105 } => {
106 let context_for_module = match module_type {
107 ModuleType::Typescript { analyze_types, .. } if *analyze_types => {
108 module_asset_context.with_types_resolving_enabled()
109 }
110 ModuleType::TypescriptDeclaration { .. } => {
111 module_asset_context.with_types_resolving_enabled()
112 }
113 _ => module_asset_context,
114 }
115 .to_resolved()
116 .await?;
117 let mut builder = EcmascriptModuleAsset::builder(
118 source,
119 ResolvedVc::upcast(context_for_module),
120 preprocess
121 .extend(**main)
122 .extend(**postprocess)
123 .to_resolved()
124 .await?,
125 *options,
126 module_asset_context
127 .compile_time_info()
128 .to_resolved()
129 .await?,
130 );
131 match module_type {
132 ModuleType::Ecmascript { .. } => {
133 builder = builder.with_type(EcmascriptModuleAssetType::Ecmascript)
134 }
135 ModuleType::Typescript {
136 tsx, analyze_types, ..
137 } => {
138 builder = builder.with_type(EcmascriptModuleAssetType::Typescript {
139 tsx: *tsx,
140 analyze_types: *analyze_types,
141 })
142 }
143 ModuleType::TypescriptDeclaration { .. } => {
144 builder = builder.with_type(EcmascriptModuleAssetType::TypescriptDeclaration)
145 }
146 _ => unreachable!(),
147 }
148
149 if let Some(inner_assets) = inner_assets {
150 builder = builder.with_inner_assets(inner_assets);
151 }
152
153 let module = builder.build().to_resolved().await?;
154 if runtime_code {
155 ResolvedVc::upcast(module)
156 } else {
157 if matches!(&part, Some(ModulePart::Evaluation)) {
158 let side_effect_free_packages = module_asset_context
160 .side_effect_free_packages()
161 .resolve()
162 .await?;
163
164 if *module
165 .is_marked_as_side_effect_free(side_effect_free_packages)
166 .await?
167 {
168 return Ok(ProcessResult::Ignore.cell());
169 }
170 }
171
172 let options_value = options.await?;
173 match options_value.tree_shaking_mode {
174 Some(TreeShakingMode::ModuleFragments) => {
175 Vc::upcast(EcmascriptModulePartAsset::select_part(
176 *module,
177 part.unwrap_or(ModulePart::facade()),
178 ))
179 }
180 Some(TreeShakingMode::ReexportsOnly) => {
181 if let Some(part) = part {
182 match part {
183 ModulePart::Evaluation => {
184 if *module.get_exports().split_locals_and_reexports().await? {
185 Vc::upcast(EcmascriptModuleLocalsModule::new(*module))
186 } else {
187 Vc::upcast(*module)
188 }
189 }
190 ModulePart::Export(_) => {
191 let side_effect_free_packages = module_asset_context
192 .side_effect_free_packages()
193 .resolve()
194 .await?;
195
196 if *module.get_exports().split_locals_and_reexports().await? {
197 apply_reexport_tree_shaking(
198 Vc::upcast(
199 EcmascriptModuleFacadeModule::new(
200 Vc::upcast(*module),
201 ModulePart::facade(),
202 )
203 .resolve()
204 .await?,
205 ),
206 part,
207 side_effect_free_packages,
208 )
209 } else {
210 apply_reexport_tree_shaking(
211 Vc::upcast(*module),
212 part,
213 side_effect_free_packages,
214 )
215 }
216 }
217 _ => bail!(
218 "Invalid module part \"{}\" for reexports only tree shaking \
219 mode",
220 part
221 ),
222 }
223 } else if *module.get_exports().split_locals_and_reexports().await? {
224 Vc::upcast(EcmascriptModuleFacadeModule::new(
225 Vc::upcast(*module),
226 ModulePart::facade(),
227 ))
228 } else {
229 Vc::upcast(*module)
230 }
231 }
232 None => Vc::upcast(*module),
233 }
234 .to_resolved()
235 .await?
236 }
237 }
238 ModuleType::Json => ResolvedVc::upcast(JsonModuleAsset::new(*source).to_resolved().await?),
239 ModuleType::Raw => ResolvedVc::upcast(RawModule::new(*source).to_resolved().await?),
240 ModuleType::NodeAddon => {
241 ResolvedVc::upcast(NodeAddonModule::new(*source).to_resolved().await?)
242 }
243 ModuleType::CssModule => ResolvedVc::upcast(
244 ModuleCssAsset::new(*source, Vc::upcast(module_asset_context))
245 .to_resolved()
246 .await?,
247 ),
248
249 ModuleType::Css { ty, environment } => ResolvedVc::upcast(
250 CssModuleAsset::new(
251 *source,
252 Vc::upcast(module_asset_context),
253 *ty,
254 css_import_context,
255 environment.as_deref().copied(),
256 )
257 .to_resolved()
258 .await?,
259 ),
260 ModuleType::StaticUrlJs => {
261 ResolvedVc::upcast(StaticUrlJsModule::new(*source).to_resolved().await?)
262 }
263 ModuleType::StaticUrlCss => {
264 ResolvedVc::upcast(StaticUrlCssModule::new(*source).to_resolved().await?)
265 }
266 ModuleType::WebAssembly { source_ty } => ResolvedVc::upcast(
267 WebAssemblyModuleAsset::new(
268 WebAssemblySource::new(*source, *source_ty),
269 Vc::upcast(module_asset_context),
270 )
271 .to_resolved()
272 .await?,
273 ),
274 ModuleType::Custom(custom) => {
275 custom
276 .create_module(*source, module_asset_context, part)
277 .to_resolved()
278 .await?
279 }
280 })
281 .cell())
282}
283
284#[turbo_tasks::function]
285async fn apply_reexport_tree_shaking(
286 module: Vc<Box<dyn EcmascriptChunkPlaceable>>,
287 part: ModulePart,
288 side_effect_free_packages: Vc<Glob>,
289) -> Result<Vc<Box<dyn Module>>> {
290 if let ModulePart::Export(export) = &part {
291 let FollowExportsResult {
292 module: final_module,
293 export_name: new_export,
294 ..
295 } = &*follow_reexports(module, export.clone(), side_effect_free_packages, true).await?;
296 let module = if let Some(new_export) = new_export {
297 if *new_export == *export {
298 Vc::upcast(**final_module)
299 } else {
300 Vc::upcast(EcmascriptModuleFacadeModule::new(
301 **final_module,
302 ModulePart::renamed_export(new_export.clone(), export.clone()),
303 ))
304 }
305 } else {
306 Vc::upcast(EcmascriptModuleFacadeModule::new(
307 **final_module,
308 ModulePart::renamed_namespace(export.clone()),
309 ))
310 };
311 return Ok(module);
312 }
313 Ok(Vc::upcast(module))
314}
315
316#[turbo_tasks::value]
317#[derive(Debug)]
318pub struct ModuleAssetContext {
319 pub transitions: ResolvedVc<TransitionOptions>,
320 pub compile_time_info: ResolvedVc<CompileTimeInfo>,
321 pub module_options_context: ResolvedVc<ModuleOptionsContext>,
322 pub resolve_options_context: ResolvedVc<ResolveOptionsContext>,
323 pub layer: Layer,
324 transition: Option<ResolvedVc<Box<dyn Transition>>>,
325 replace_externals: bool,
328}
329
330#[turbo_tasks::value_impl]
331impl ModuleAssetContext {
332 #[turbo_tasks::function]
333 pub fn new(
334 transitions: ResolvedVc<TransitionOptions>,
335 compile_time_info: ResolvedVc<CompileTimeInfo>,
336 module_options_context: ResolvedVc<ModuleOptionsContext>,
337 resolve_options_context: ResolvedVc<ResolveOptionsContext>,
338 layer: Layer,
339 ) -> Vc<Self> {
340 Self::cell(ModuleAssetContext {
341 transitions,
342 compile_time_info,
343 module_options_context,
344 resolve_options_context,
345 transition: None,
346 layer,
347 replace_externals: true,
348 })
349 }
350
351 #[turbo_tasks::function]
352 pub fn new_transition(
353 transitions: ResolvedVc<TransitionOptions>,
354 compile_time_info: ResolvedVc<CompileTimeInfo>,
355 module_options_context: ResolvedVc<ModuleOptionsContext>,
356 resolve_options_context: ResolvedVc<ResolveOptionsContext>,
357 layer: Layer,
358 transition: ResolvedVc<Box<dyn Transition>>,
359 ) -> Vc<Self> {
360 Self::cell(ModuleAssetContext {
361 transitions,
362 compile_time_info,
363 module_options_context,
364 resolve_options_context,
365 layer,
366 transition: Some(transition),
367 replace_externals: true,
368 })
369 }
370
371 #[turbo_tasks::function]
372 fn new_without_replace_externals(
373 transitions: ResolvedVc<TransitionOptions>,
374 compile_time_info: ResolvedVc<CompileTimeInfo>,
375 module_options_context: ResolvedVc<ModuleOptionsContext>,
376 resolve_options_context: ResolvedVc<ResolveOptionsContext>,
377 layer: Layer,
378 ) -> Vc<Self> {
379 Self::cell(ModuleAssetContext {
380 transitions,
381 compile_time_info,
382 module_options_context,
383 resolve_options_context,
384 transition: None,
385 layer,
386 replace_externals: false,
387 })
388 }
389
390 #[turbo_tasks::function]
391 pub fn module_options_context(&self) -> Vc<ModuleOptionsContext> {
392 *self.module_options_context
393 }
394
395 #[turbo_tasks::function]
396 pub fn resolve_options_context(&self) -> Vc<ResolveOptionsContext> {
397 *self.resolve_options_context
398 }
399
400 #[turbo_tasks::function]
401 pub async fn is_types_resolving_enabled(&self) -> Result<Vc<bool>> {
402 let resolve_options_context = self.resolve_options_context.await?;
403 Ok(Vc::cell(
404 resolve_options_context.enable_types && resolve_options_context.enable_typescript,
405 ))
406 }
407
408 #[turbo_tasks::function]
409 pub async fn with_types_resolving_enabled(self: Vc<Self>) -> Result<Vc<ModuleAssetContext>> {
410 if *self.is_types_resolving_enabled().await? {
411 return Ok(self);
412 }
413 let this = self.await?;
414 let resolve_options_context = this
415 .resolve_options_context
416 .with_types_enabled()
417 .resolve()
418 .await?;
419
420 Ok(ModuleAssetContext::new(
421 *this.transitions,
422 *this.compile_time_info,
423 *this.module_options_context,
424 resolve_options_context,
425 this.layer.clone(),
426 ))
427 }
428}
429
430impl ModuleAssetContext {
431 async fn process_with_transition_rules(
432 self: Vc<Self>,
433 source: ResolvedVc<Box<dyn Source>>,
434 reference_type: ReferenceType,
435 ) -> Result<Vc<ProcessResult>> {
436 let this = self.await?;
437 Ok(
438 if let Some(transition) = this
439 .transitions
440 .await?
441 .get_by_rules(source, &reference_type)
442 .await?
443 {
444 transition.process(*source, self, reference_type)
445 } else {
446 self.process_default(source, reference_type).await?
447 },
448 )
449 }
450
451 async fn process_default(
452 self: Vc<Self>,
453 source: ResolvedVc<Box<dyn Source>>,
454 reference_type: ReferenceType,
455 ) -> Result<Vc<ProcessResult>> {
456 process_default(self, source, reference_type, Vec::new()).await
457 }
458}
459
460async fn process_default(
461 module_asset_context: Vc<ModuleAssetContext>,
462 source: ResolvedVc<Box<dyn Source>>,
463 reference_type: ReferenceType,
464 processed_rules: Vec<usize>,
465) -> Result<Vc<ProcessResult>> {
466 let span = tracing::info_span!(
467 "process module",
468 name = %source.ident().to_string().await?,
469 layer = Empty,
470 reference_type = display(&reference_type)
471 );
472 if !span.is_disabled() {
473 let module_asset_context_ref = module_asset_context.await?;
475 span.record("layer", module_asset_context_ref.layer.name().as_str());
476 }
477 process_default_internal(
478 module_asset_context,
479 source,
480 reference_type,
481 processed_rules,
482 )
483 .instrument(span)
484 .await
485}
486
487async fn process_default_internal(
488 module_asset_context: Vc<ModuleAssetContext>,
489 source: ResolvedVc<Box<dyn Source>>,
490 reference_type: ReferenceType,
491 processed_rules: Vec<usize>,
492) -> Result<Vc<ProcessResult>> {
493 let ident = source.ident().resolve().await?;
494 let path_ref = ident.path().await?;
495 let options = ModuleOptions::new(
496 ident.path().await?.parent(),
497 module_asset_context.module_options_context(),
498 module_asset_context.resolve_options_context(),
499 );
500
501 let part: Option<ModulePart> = match &reference_type {
502 ReferenceType::EcmaScriptModules(EcmaScriptModulesReferenceSubType::ImportPart(part)) => {
503 Some(part.clone())
504 }
505 _ => None,
506 };
507 let inner_assets = match &reference_type {
508 ReferenceType::Internal(inner_assets) => Some(*inner_assets),
509 _ => None,
510 };
511
512 let mut has_type_attribute = false;
513
514 let mut current_source = source;
515 let mut current_module_type = match &reference_type {
516 ReferenceType::EcmaScriptModules(EcmaScriptModulesReferenceSubType::ImportWithType(ty)) => {
517 has_type_attribute = true;
518
519 match ty {
520 ImportWithType::Json => Some(ModuleType::Json),
521 }
522 }
523 _ => None,
524 };
525
526 for (i, rule) in options.await?.rules.iter().enumerate() {
527 if has_type_attribute && current_module_type.is_some() {
528 continue;
529 }
530 if processed_rules.contains(&i) {
531 continue;
532 }
533 if rule.matches(source, &path_ref, &reference_type).await? {
534 for effect in rule.effects() {
535 match effect {
536 ModuleRuleEffect::Ignore => {
537 return Ok(ProcessResult::Ignore.cell());
538 }
539 ModuleRuleEffect::SourceTransforms(transforms) => {
540 current_source =
541 transforms.transform(*current_source).to_resolved().await?;
542 if current_source.ident().resolve().await? != ident {
543 if let Some(transition) = module_asset_context
545 .await?
546 .transitions
547 .await?
548 .get_by_rules(current_source, &reference_type)
549 .await?
550 {
551 return Ok(transition.process(
552 *current_source,
553 module_asset_context,
554 reference_type,
555 ));
556 } else {
557 let mut processed_rules = processed_rules.clone();
558 processed_rules.push(i);
559 return Box::pin(process_default(
560 module_asset_context,
561 current_source,
562 reference_type,
563 processed_rules,
564 ))
565 .await;
566 }
567 }
568 }
569 ModuleRuleEffect::ModuleType(module) => {
570 current_module_type = Some(module.clone());
571 }
572 ModuleRuleEffect::ExtendEcmascriptTransforms {
573 preprocess: extend_preprocess,
574 main: extend_main,
575 postprocess: extend_postprocess,
576 } => {
577 current_module_type = match current_module_type {
578 Some(ModuleType::Ecmascript {
579 preprocess,
580 main,
581 postprocess,
582 options,
583 }) => Some(ModuleType::Ecmascript {
584 preprocess: extend_preprocess
585 .extend(*preprocess)
586 .to_resolved()
587 .await?,
588 main: extend_main.extend(*main).to_resolved().await?,
589 postprocess: postprocess
590 .extend(**extend_postprocess)
591 .to_resolved()
592 .await?,
593 options,
594 }),
595 Some(ModuleType::Typescript {
596 preprocess,
597 main,
598 postprocess,
599 tsx,
600 analyze_types,
601 options,
602 }) => Some(ModuleType::Typescript {
603 preprocess: extend_preprocess
604 .extend(*preprocess)
605 .to_resolved()
606 .await?,
607 main: extend_main.extend(*main).to_resolved().await?,
608 postprocess: postprocess
609 .extend(**extend_postprocess)
610 .to_resolved()
611 .await?,
612 tsx,
613 analyze_types,
614 options,
615 }),
616 Some(module_type) => {
617 ModuleIssue {
618 ident: ident.to_resolved().await?,
619 title: StyledString::Text(rcstr!("Invalid module type"))
620 .resolved_cell(),
621 description: StyledString::Text(rcstr!(
622 "The module type must be Ecmascript or Typescript to add \
623 Ecmascript transforms"
624 ))
625 .resolved_cell(),
626 source: Some(IssueSource::from_source_only(current_source)),
627 }
628 .resolved_cell()
629 .emit();
630 Some(module_type)
631 }
632 None => {
633 ModuleIssue {
634 ident: ident.to_resolved().await?,
635 title: StyledString::Text(rcstr!("Missing module type"))
636 .resolved_cell(),
637 description: StyledString::Text(rcstr!(
638 "The module type effect must be applied before adding \
639 Ecmascript transforms"
640 ))
641 .resolved_cell(),
642 source: Some(IssueSource::from_source_only(current_source)),
643 }
644 .resolved_cell()
645 .emit();
646 None
647 }
648 };
649 }
650 }
651 }
652 }
653 }
654
655 let Some(module_type) = current_module_type else {
656 return Ok(ProcessResult::Unknown(current_source).cell());
657 };
658
659 Ok(apply_module_type(
660 *current_source,
661 module_asset_context,
662 module_type.cell(),
663 part,
664 inner_assets.map(|v| *v),
665 if let ReferenceType::Css(CssReferenceSubType::AtImport(import)) = reference_type {
666 import.map(|v| *v)
667 } else {
668 None
669 },
670 matches!(reference_type, ReferenceType::Runtime),
671 ))
672}
673
674#[turbo_tasks::function]
675async fn externals_tracing_module_context(
676 ty: ExternalType,
677 compile_time_info: Vc<CompileTimeInfo>,
678) -> Result<Vc<ModuleAssetContext>> {
679 let resolve_options = ResolveOptionsContext {
680 enable_node_native_modules: true,
681 emulate_environment: Some(compile_time_info.await?.environment),
682 loose_errors: true,
683 custom_conditions: match ty {
684 ExternalType::CommonJs => vec![rcstr!("require"), rcstr!("node")],
685 ExternalType::EcmaScriptModule => vec![rcstr!("import"), rcstr!("node")],
686 ExternalType::Url | ExternalType::Global | ExternalType::Script => vec![rcstr!("node")],
687 },
688 ..Default::default()
689 };
690
691 Ok(ModuleAssetContext::new_without_replace_externals(
692 Default::default(),
693 compile_time_info,
694 ModuleOptionsContext {
698 ecmascript: EcmascriptOptionsContext {
699 source_maps: SourceMapsType::None,
702 ..Default::default()
703 },
704 css: CssOptionsContext {
705 source_maps: SourceMapsType::None,
706 enable_raw_css: true,
707 ..Default::default()
708 },
709 environment: None,
712 is_tracing: true,
713 ..Default::default()
714 }
715 .cell(),
716 resolve_options.cell(),
717 Layer::new(rcstr!("externals-tracing")),
718 ))
719}
720
721#[turbo_tasks::value_impl]
722impl AssetContext for ModuleAssetContext {
723 #[turbo_tasks::function]
724 fn compile_time_info(&self) -> Vc<CompileTimeInfo> {
725 *self.compile_time_info
726 }
727
728 fn layer(&self) -> Layer {
729 self.layer.clone()
730 }
731
732 #[turbo_tasks::function]
733 async fn resolve_options(
734 self: Vc<Self>,
735 origin_path: FileSystemPath,
736 _reference_type: ReferenceType,
737 ) -> Result<Vc<ResolveOptions>> {
738 let this = self.await?;
739 let module_asset_context = if let Some(transition) = this.transition {
740 transition.process_context(self)
741 } else {
742 self
743 };
744 Ok(resolve_options(
746 origin_path.parent(),
747 *module_asset_context.await?.resolve_options_context,
748 ))
749 }
750
751 #[turbo_tasks::function]
752 async fn resolve_asset(
753 self: Vc<Self>,
754 origin_path: FileSystemPath,
755 request: Vc<Request>,
756 resolve_options: Vc<ResolveOptions>,
757 reference_type: ReferenceType,
758 ) -> Result<Vc<ModuleResolveResult>> {
759 let context_path = origin_path.parent();
760
761 let result = resolve(
762 context_path,
763 reference_type.clone(),
764 request,
765 resolve_options,
766 );
767
768 let mut result = self.process_resolve_result(result.resolve().await?, reference_type);
769
770 if *self.is_types_resolving_enabled().await? {
771 let types_result = type_resolve(
772 Vc::upcast(PlainResolveOrigin::new(Vc::upcast(self), origin_path)),
773 request,
774 );
775
776 result = ModuleResolveResult::alternatives(vec![result, types_result]);
777 }
778
779 Ok(result)
780 }
781
782 #[turbo_tasks::function]
783 async fn process_resolve_result(
784 self: Vc<Self>,
785 result: Vc<ResolveResult>,
786 reference_type: ReferenceType,
787 ) -> Result<Vc<ModuleResolveResult>> {
788 let this = self.await?;
789
790 let replace_externals = this.replace_externals;
791 let import_externals = this
792 .module_options_context
793 .await?
794 .ecmascript
795 .import_externals;
796
797 let result = result.await?;
798
799 let result = result
800 .map_primary_items(|item| {
801 let reference_type = reference_type.clone();
802 async move {
803 Ok(match item {
804 ResolveResultItem::Source(source) => {
805 match &*self.process(*source, reference_type).await? {
806 ProcessResult::Module(module) => {
807 ModuleResolveResultItem::Module(*module)
808 }
809 ProcessResult::Unknown(source) => {
810 ModuleResolveResultItem::Unknown(*source)
811 }
812 ProcessResult::Ignore => ModuleResolveResultItem::Ignore,
813 }
814 }
815 ResolveResultItem::External { name, ty, traced } => {
816 let replacement = if replace_externals {
817 let tracing_mode = if traced == ExternalTraced::Traced
818 && let Some(options) = &self
819 .module_options_context()
820 .await?
821 .enable_externals_tracing
822 {
823 let options = options.await?;
828 CachedExternalTracingMode::Traced {
829 externals_context: ResolvedVc::upcast(
830 externals_tracing_module_context(
831 ty,
832 *options.compile_time_info,
833 )
834 .to_resolved()
835 .await?,
836 ),
837 root_origin: options.tracing_root.join("_")?,
838 }
839 } else {
840 CachedExternalTracingMode::Untraced
841 };
842
843 replace_external(&name, ty, import_externals, tracing_mode).await?
844 } else {
845 None
846 };
847
848 replacement
849 .unwrap_or_else(|| ModuleResolveResultItem::External { name, ty })
850 }
851 ResolveResultItem::Ignore => ModuleResolveResultItem::Ignore,
852 ResolveResultItem::Empty => ModuleResolveResultItem::Empty,
853 ResolveResultItem::Error(e) => ModuleResolveResultItem::Error(e),
854 ResolveResultItem::Custom(u8) => ModuleResolveResultItem::Custom(u8),
855 })
856 }
857 })
858 .await?;
859
860 Ok(result.cell())
861 }
862
863 #[turbo_tasks::function]
864 async fn process(
865 self: Vc<Self>,
866 asset: ResolvedVc<Box<dyn Source>>,
867 reference_type: ReferenceType,
868 ) -> Result<Vc<ProcessResult>> {
869 let this = self.await?;
870 if let Some(transition) = this.transition {
871 Ok(transition.process(*asset, self, reference_type))
872 } else {
873 Ok(self
874 .process_with_transition_rules(asset, reference_type)
875 .await?)
876 }
877 }
878
879 #[turbo_tasks::function]
880 async fn with_transition(&self, transition: RcStr) -> Result<Vc<Box<dyn AssetContext>>> {
881 Ok(
882 if let Some(transition) = self.transitions.await?.get_named(transition) {
883 Vc::upcast(ModuleAssetContext::new_transition(
884 *self.transitions,
885 *self.compile_time_info,
886 *self.module_options_context,
887 *self.resolve_options_context,
888 self.layer.clone(),
889 *transition,
890 ))
891 } else {
892 Vc::upcast(ModuleAssetContext::new(
894 *self.transitions,
895 *self.compile_time_info,
896 *self.module_options_context,
897 *self.resolve_options_context,
898 self.layer.clone(),
899 ))
900 },
901 )
902 }
903
904 #[turbo_tasks::function]
905 async fn side_effect_free_packages(&self) -> Result<Vc<Glob>> {
906 let pkgs = &self.module_options_context.await?.side_effect_free_packages;
907
908 let mut globs = String::new();
909 globs.push_str("**/node_modules/{");
910 globs.push_str(&pkgs.join(","));
911 globs.push_str("}/**");
912
913 Ok(Glob::new(globs.into(), GlobOptions::default()))
914 }
915}
916
917#[turbo_tasks::function]
918pub async fn emit_with_completion(
919 asset: Vc<Box<dyn OutputAsset>>,
920 output_dir: FileSystemPath,
921) -> Result<()> {
922 emit_assets_aggregated(asset, output_dir)
923 .as_side_effect()
924 .await
925}
926
927#[turbo_tasks::function(operation)]
928pub fn emit_with_completion_operation(
929 asset: ResolvedVc<Box<dyn OutputAsset>>,
930 output_dir: FileSystemPath,
931) -> Vc<()> {
932 emit_with_completion(*asset, output_dir)
933}
934
935#[turbo_tasks::function]
936async fn emit_assets_aggregated(
937 asset: Vc<Box<dyn OutputAsset>>,
938 output_dir: FileSystemPath,
939) -> Result<()> {
940 let aggregated = aggregate(asset);
941 emit_aggregated_assets(aggregated, output_dir)
942 .as_side_effect()
943 .await
944}
945
946#[turbo_tasks::function]
947async fn emit_aggregated_assets(
948 aggregated: Vc<AggregatedGraph>,
949 output_dir: FileSystemPath,
950) -> Result<()> {
951 match &*aggregated.content().await? {
952 AggregatedGraphNodeContent::Asset(asset) => {
953 emit_asset_into_dir(**asset, output_dir)
954 .as_side_effect()
955 .await?;
956 }
957 AggregatedGraphNodeContent::Children(children) => {
958 for aggregated in children {
959 emit_aggregated_assets(**aggregated, output_dir.clone())
960 .as_side_effect()
961 .await?;
962 }
963 }
964 }
965 Ok(())
966}
967
968#[turbo_tasks::function]
969pub async fn emit_asset(asset: Vc<Box<dyn OutputAsset>>) -> Result<()> {
970 asset
971 .content()
972 .write(asset.path().owned().await?)
973 .as_side_effect()
974 .await?;
975
976 Ok(())
977}
978
979#[turbo_tasks::function]
980pub async fn emit_asset_into_dir(
981 asset: Vc<Box<dyn OutputAsset>>,
982 output_dir: FileSystemPath,
983) -> Result<()> {
984 let dir = output_dir.clone();
985 if asset.path().await?.is_inside_ref(&dir) {
986 emit_asset(asset).as_side_effect().await?;
987 }
988 Ok(())
989}
990
991pub async fn replace_external(
993 name: &RcStr,
994 ty: ExternalType,
995 import_externals: bool,
996 tracing_mode: CachedExternalTracingMode,
997) -> Result<Option<ModuleResolveResultItem>> {
998 let external_type = match ty {
999 ExternalType::CommonJs => CachedExternalType::CommonJs,
1000 ExternalType::EcmaScriptModule => {
1001 if import_externals {
1002 CachedExternalType::EcmaScriptViaImport
1003 } else {
1004 CachedExternalType::EcmaScriptViaRequire
1005 }
1006 }
1007 ExternalType::Global => CachedExternalType::Global,
1008 ExternalType::Script => CachedExternalType::Script,
1009 ExternalType::Url => {
1010 return Ok(None);
1012 }
1013 };
1014
1015 let module = CachedExternalModule::new(name.clone(), external_type, tracing_mode)
1016 .to_resolved()
1017 .await?;
1018
1019 Ok(Some(ModuleResolveResultItem::Module(ResolvedVc::upcast(
1020 module,
1021 ))))
1022}
1023
1024pub fn register() {
1025 turbo_tasks::register();
1026 turbo_tasks_fs::register();
1027 turbopack_core::register();
1028 turbopack_css::register();
1029 turbopack_ecmascript::register();
1030 turbopack_node::register();
1031 turbopack_env::register();
1032 turbopack_mdx::register();
1033 turbopack_json::register();
1034 turbopack_resolve::register();
1035 turbopack_static::register();
1036 turbopack_wasm::register();
1037 include!(concat!(env!("OUT_DIR"), "/register.rs"));
1038}