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