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