1#![feature(trivial_bounds)]
2#![feature(min_specialization)]
3#![recursion_limit = "256"]
4#![feature(arbitrary_self_types)]
5#![feature(arbitrary_self_types_pointers)]
6
7pub mod evaluate_context;
8pub mod global_module_ids;
9pub mod module_options;
10pub mod runtime_asset_context;
11pub mod transition;
12
13use anyhow::{Context as _, Result, bail};
14use module_options::{
15 ConfiguredModuleType, ModuleOptions, ModuleOptionsContext, ModuleRule, ModuleRuleEffect,
16 ModuleType, RuleCondition,
17};
18pub use runtime_asset_context::get_runtime_asset_context;
19use tracing::{Instrument, field::Empty};
20use turbo_rcstr::{RcStr, rcstr};
21use turbo_tasks::{ResolvedVc, TryJoinIterExt, ValueToString, Vc};
22use turbo_tasks_fs::{FileSystemPath, glob::Glob};
23pub use turbopack_core::condition;
24use turbopack_core::{
25 asset::Asset,
26 chunk::SourceMapsType,
27 compile_time_info::CompileTimeInfo,
28 context::{AssetContext, ProcessResult},
29 ident::{AssetIdent, Layer},
30 issue::{IssueExt, IssueSource, module::ModuleIssue},
31 module::{Module, ModuleSideEffects},
32 node_addon_module::NodeAddonModule,
33 output::{ExpandedOutputAssets, OutputAsset},
34 raw_module::RawModule,
35 reference_type::{
36 CssReferenceSubType, EcmaScriptModulesReferenceSubType, InnerAssets, ReferenceType,
37 },
38 resolve::{
39 ExternalTraced, ExternalType, ModulePart, ModuleResolveResult, ModuleResolveResultItem,
40 ResolveResult, ResolveResultItem,
41 options::{ConditionValue, ResolveOptions},
42 origin::PlainResolveOrigin,
43 parse::Request,
44 resolve,
45 },
46 source::Source,
47 source_transform::SourceTransforms,
48};
49use turbopack_css::{CssModule, EcmascriptCssModule};
50use turbopack_ecmascript::{
51 AnalyzeMode, EcmascriptInputTransforms, EcmascriptModuleAsset, EcmascriptModuleAssetType,
52 EcmascriptOptions,
53 async_chunk::proxy::LazyCompilationProxyModule,
54 module_canonicalization::{EcmascriptModuleCanonicalization, canonicalize_ecmascript_module},
55 references::external_module::{
56 CachedExternalModule, CachedExternalTracingMode, CachedExternalType,
57 },
58};
59use turbopack_node::transforms::webpack::{WebpackLoaderItem, WebpackLoaderItems, WebpackLoaders};
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 evaluate_context::{config_tracing_module_context, node_evaluate_asset_context},
69 module_options::{
70 CssOptionsContext, CustomModuleType, EcmascriptOptionsContext, TypescriptTransformOptions,
71 package_import_map_from_context, package_import_map_from_import_mapping,
72 },
73 transition::{Transition, TransitionOptions},
74};
75
76async fn apply_module_type(
77 source: ResolvedVc<Box<dyn Source>>,
78 module_asset_context: Vc<ModuleAssetContext>,
79 module_type: Vc<ModuleType>,
80 reference_type: ReferenceType,
81 inner_assets: Option<ResolvedVc<InnerAssets>>,
82) -> Result<Vc<ProcessResult>> {
83 let module_options = module_asset_context.module_options_context().await?;
84 let follow_reexports = module_options.follow_reexports;
85 let module_fragments_enabled = module_options.module_fragments_enabled;
86 let part = match &reference_type {
87 ReferenceType::EcmaScriptModules(EcmaScriptModulesReferenceSubType::ImportPart(part)) => {
88 Some(part)
89 }
90 _ => None,
91 };
92 let css_import_context = match reference_type {
93 ReferenceType::Css(CssReferenceSubType::AtImport(import)) => import,
94 _ => None,
95 };
96 let is_evaluation = matches!(&part, Some(ModulePart::Evaluation));
97 let is_lazy_dynamic_import = matches!(
98 &reference_type,
99 ReferenceType::EcmaScriptModules(EcmaScriptModulesReferenceSubType::LazyDynamicImport)
100 );
101
102 let module_type = &*module_type.await?;
103 let module = match module_type {
104 ModuleType::Ecmascript {
105 preprocess,
106 main,
107 postprocess,
108 options,
109 }
110 | ModuleType::EcmascriptExtensionless {
111 preprocess,
112 main,
113 postprocess,
114 options,
115 }
116 | ModuleType::Typescript {
117 preprocess,
118 main,
119 postprocess,
120 tsx: _,
121 analyze_types: _,
122 options,
123 }
124 | ModuleType::TypescriptDeclaration {
125 preprocess,
126 main,
127 postprocess,
128 options,
129 } => {
130 let context_for_module = match module_type {
131 ModuleType::Typescript { analyze_types, .. } if *analyze_types => {
132 module_asset_context.with_types_resolving_enabled()
133 }
134 ModuleType::TypescriptDeclaration { .. } => {
135 module_asset_context.with_types_resolving_enabled()
136 }
137 _ => module_asset_context,
138 }
139 .to_resolved()
140 .await?;
141 let side_effect_free_packages = module_asset_context
142 .module_options_context()
143 .await?
144 .side_effect_free_packages;
145 let mut builder = EcmascriptModuleAsset::builder(
146 source,
147 ResolvedVc::upcast(context_for_module),
148 preprocess
149 .extend(**main)
150 .extend(**postprocess)
151 .to_resolved()
152 .await?,
153 *options,
154 module_asset_context
155 .compile_time_info()
156 .to_resolved()
157 .await?,
158 side_effect_free_packages,
159 );
160 match module_type {
161 ModuleType::Ecmascript { .. } => {
162 builder = builder.with_type(EcmascriptModuleAssetType::Ecmascript)
163 }
164 ModuleType::EcmascriptExtensionless { .. } => {
165 builder = builder.with_type(EcmascriptModuleAssetType::EcmascriptExtensionless)
166 }
167 ModuleType::Typescript {
168 tsx, analyze_types, ..
169 } => {
170 builder = builder.with_type(EcmascriptModuleAssetType::Typescript {
171 tsx: *tsx,
172 analyze_types: *analyze_types,
173 })
174 }
175 ModuleType::TypescriptDeclaration { .. } => {
176 builder = builder.with_type(EcmascriptModuleAssetType::TypescriptDeclaration)
177 }
178 _ => unreachable!(),
179 }
180
181 if let Some(inner_assets) = inner_assets {
182 builder = builder.with_inner_assets(inner_assets);
183 }
184
185 let module = builder.build().to_resolved().await?;
186 if matches!(reference_type, ReferenceType::Runtime) {
187 ResolvedVc::upcast(module)
188 } else {
189 if (follow_reexports || module_fragments_enabled) && is_evaluation {
194 if *module.side_effects().await? == ModuleSideEffects::SideEffectFree {
197 return Ok(ProcessResult::Ignore.cell());
198 }
199 }
200
201 let canonicalization = if module_fragments_enabled {
202 EcmascriptModuleCanonicalization::ModuleFragments(
203 part.cloned().unwrap_or_else(ModulePart::facade),
204 )
205 } else if follow_reexports {
206 EcmascriptModuleCanonicalization::FollowReexports(part.cloned())
207 } else {
208 EcmascriptModuleCanonicalization::None
209 };
210
211 if is_lazy_dynamic_import {
212 ResolvedVc::upcast(
213 LazyCompilationProxyModule::new_deferred(*module, canonicalization)
214 .to_resolved()
215 .await?,
216 )
217 } else {
218 ResolvedVc::upcast(
219 canonicalize_ecmascript_module(*module, canonicalization)
220 .to_resolved()
221 .await?,
222 )
223 }
224 }
225 }
226 ModuleType::Raw => ResolvedVc::upcast(RawModule::new(*source).to_resolved().await?),
227 ModuleType::NodeAddon => {
228 ResolvedVc::upcast(NodeAddonModule::new(*source).to_resolved().await?)
229 }
230 ModuleType::CssModule => ResolvedVc::upcast(
231 EcmascriptCssModule::new(*source, Vc::upcast(module_asset_context))
232 .to_resolved()
233 .await?,
234 ),
235
236 ModuleType::Css {
237 ty,
238 environment,
239 lightningcss_features,
240 module_css_debuggable_idents,
241 } => ResolvedVc::upcast(
242 CssModule::new(
243 *source,
244 Vc::upcast(module_asset_context),
245 *ty,
246 css_import_context.map(|c| *c),
247 environment.as_deref().copied(),
248 *lightningcss_features,
249 *module_css_debuggable_idents,
250 )
251 .to_resolved()
252 .await?,
253 ),
254 ModuleType::StaticUrlJs { tag } => ResolvedVc::upcast(
255 StaticUrlJsModule::new(*source, tag.clone())
256 .to_resolved()
257 .await?,
258 ),
259 ModuleType::StaticUrlCss { tag } => ResolvedVc::upcast(
260 StaticUrlCssModule::new(*source, tag.clone())
261 .to_resolved()
262 .await?,
263 ),
264 ModuleType::WebAssembly { source_ty } => ResolvedVc::upcast(
265 WebAssemblyModuleAsset::new(
266 WebAssemblySource::new(*source, *source_ty),
267 Vc::upcast(module_asset_context),
268 )
269 .to_resolved()
270 .await?,
271 ),
272 ModuleType::Custom(custom) => {
273 custom
274 .create_module(*source, module_asset_context, reference_type)
275 .to_resolved()
276 .await?
277 }
278 };
279
280 if (follow_reexports || module_fragments_enabled) && is_evaluation {
281 if *module.side_effects().await? == ModuleSideEffects::SideEffectFree {
284 return Ok(ProcessResult::Ignore.cell());
285 }
286 }
287
288 Ok(ProcessResult::Module(module).cell())
289}
290
291#[turbo_tasks::value]
292#[derive(Debug)]
293pub struct ModuleAssetContext {
294 pub transitions: ResolvedVc<TransitionOptions>,
295 pub compile_time_info: ResolvedVc<CompileTimeInfo>,
296 pub module_options_context: ResolvedVc<ModuleOptionsContext>,
297 pub resolve_options_context: ResolvedVc<ResolveOptionsContext>,
298 pub layer: Layer,
299 transition: Option<ResolvedVc<Box<dyn Transition>>>,
300 replace_externals: bool,
303}
304
305#[turbo_tasks::value_impl]
306impl ModuleAssetContext {
307 #[turbo_tasks::function]
308 pub fn new(
309 transitions: ResolvedVc<TransitionOptions>,
310 compile_time_info: ResolvedVc<CompileTimeInfo>,
311 module_options_context: ResolvedVc<ModuleOptionsContext>,
312 resolve_options_context: ResolvedVc<ResolveOptionsContext>,
313 layer: Layer,
314 ) -> Vc<Self> {
315 Self::cell(ModuleAssetContext {
316 transitions,
317 compile_time_info,
318 module_options_context,
319 resolve_options_context,
320 transition: None,
321 layer,
322 replace_externals: true,
323 })
324 }
325
326 #[turbo_tasks::function]
327 pub fn new_transition(
328 transitions: ResolvedVc<TransitionOptions>,
329 compile_time_info: ResolvedVc<CompileTimeInfo>,
330 module_options_context: ResolvedVc<ModuleOptionsContext>,
331 resolve_options_context: ResolvedVc<ResolveOptionsContext>,
332 layer: Layer,
333 transition: ResolvedVc<Box<dyn Transition>>,
334 ) -> Vc<Self> {
335 Self::cell(ModuleAssetContext {
336 transitions,
337 compile_time_info,
338 module_options_context,
339 resolve_options_context,
340 layer,
341 transition: Some(transition),
342 replace_externals: true,
343 })
344 }
345
346 #[turbo_tasks::function]
348 pub fn new_without_replace_externals(
349 transitions: ResolvedVc<TransitionOptions>,
350 compile_time_info: ResolvedVc<CompileTimeInfo>,
351 module_options_context: ResolvedVc<ModuleOptionsContext>,
352 resolve_options_context: ResolvedVc<ResolveOptionsContext>,
353 layer: Layer,
354 ) -> Vc<Self> {
355 Self::cell(ModuleAssetContext {
356 transitions,
357 compile_time_info,
358 module_options_context,
359 resolve_options_context,
360 transition: None,
361 layer,
362 replace_externals: false,
363 })
364 }
365
366 #[turbo_tasks::function]
367 pub fn module_options_context(&self) -> Vc<ModuleOptionsContext> {
368 *self.module_options_context
369 }
370
371 #[turbo_tasks::function]
372 pub fn resolve_options_context(&self) -> Vc<ResolveOptionsContext> {
373 *self.resolve_options_context
374 }
375
376 #[turbo_tasks::function]
377 pub async fn with_types_resolving_enabled(self: Vc<Self>) -> Result<Vc<ModuleAssetContext>> {
378 let this = self.await?;
379 if this.is_types_resolving_enabled().await? {
380 return Ok(self);
381 }
382 let resolve_options_context = *this
383 .resolve_options_context
384 .with_types_enabled()
385 .to_resolved()
386 .await?;
387
388 Ok(ModuleAssetContext::new(
389 *this.transitions,
390 *this.compile_time_info,
391 *this.module_options_context,
392 resolve_options_context,
393 this.layer.clone(),
394 ))
395 }
396}
397
398impl ModuleAssetContext {
399 async fn is_types_resolving_enabled(&self) -> Result<bool> {
400 let resolve_options_context = self.resolve_options_context.await?;
401 Ok(resolve_options_context.enable_types && resolve_options_context.enable_typescript)
402 }
403 async fn process_with_transition_rules(
404 self: Vc<Self>,
405 source: ResolvedVc<Box<dyn Source>>,
406 reference_type: ReferenceType,
407 ) -> Result<Vc<ProcessResult>> {
408 let this = self.await?;
409 Ok(
410 if let Some(transition) = this
411 .transitions
412 .await?
413 .get_by_rules(source, &reference_type)
414 .await?
415 {
416 transition.process(*source, self, reference_type)
417 } else {
418 self.process_default(source, reference_type).await?
419 },
420 )
421 }
422
423 async fn process_default(
424 self: Vc<Self>,
425 source: ResolvedVc<Box<dyn Source>>,
426 reference_type: ReferenceType,
427 ) -> Result<Vc<ProcessResult>> {
428 process_default(self, source, reference_type, Vec::new()).await
429 }
430}
431
432async fn process_default(
433 module_asset_context: Vc<ModuleAssetContext>,
434 source: ResolvedVc<Box<dyn Source>>,
435 reference_type: ReferenceType,
436 processed_rules: Vec<usize>,
437) -> Result<Vc<ProcessResult>> {
438 let span = tracing::info_span!(
439 "process module",
440 name = %source.ident().to_string().await?,
441 layer = Empty,
442 reference_type = display(&reference_type)
443 );
444 if !span.is_disabled() {
445 span.record("layer", module_asset_context.await?.layer.name().as_str());
447 }
448
449 process_default_internal(
450 module_asset_context,
451 source,
452 reference_type,
453 processed_rules,
454 )
455 .instrument(span)
456 .await
457}
458
459async fn apply_module_rule_transforms(
464 module_type: &mut ModuleType,
465 collected_preprocess: &mut Vec<ResolvedVc<EcmascriptInputTransforms>>,
466 collected_main: &mut Vec<ResolvedVc<EcmascriptInputTransforms>>,
467 collected_postprocess: &mut Vec<ResolvedVc<EcmascriptInputTransforms>>,
468 ident: ResolvedVc<AssetIdent>,
469 current_source: ResolvedVc<Box<dyn Source>>,
470) -> Result<()> {
471 let has_transforms = !collected_preprocess.is_empty()
472 || !collected_main.is_empty()
473 || !collected_postprocess.is_empty();
474
475 if !has_transforms {
477 return Ok(());
478 }
479
480 match module_type {
481 ModuleType::Ecmascript {
482 preprocess,
483 main,
484 postprocess,
485 ..
486 }
487 | ModuleType::Typescript {
488 preprocess,
489 main,
490 postprocess,
491 ..
492 }
493 | ModuleType::TypescriptDeclaration {
494 preprocess,
495 main,
496 postprocess,
497 ..
498 }
499 | ModuleType::EcmascriptExtensionless {
500 preprocess,
501 main,
502 postprocess,
503 ..
504 } => {
505 let mut final_preprocess = EcmascriptInputTransforms::empty();
507 for vc in collected_preprocess.drain(..) {
508 final_preprocess = final_preprocess.extend(*vc);
509 }
510 final_preprocess = final_preprocess.extend(**preprocess);
511 *preprocess = final_preprocess.to_resolved().await?;
512
513 let mut final_main = EcmascriptInputTransforms::empty();
514 for vc in collected_main.drain(..) {
515 final_main = final_main.extend(*vc);
516 }
517 final_main = final_main.extend(**main);
518 *main = final_main.to_resolved().await?;
519
520 let mut final_postprocess = **postprocess;
522 for vc in collected_postprocess.drain(..) {
523 final_postprocess = final_postprocess.extend(*vc);
524 }
525 *postprocess = final_postprocess.to_resolved().await?;
526 }
527 ModuleType::Custom(custom_module_type) => {
528 if has_transforms {
529 let mut combined_preprocess = EcmascriptInputTransforms::empty();
531 for vc in collected_preprocess.drain(..) {
532 combined_preprocess = combined_preprocess.extend(*vc);
533 }
534 let mut combined_main = EcmascriptInputTransforms::empty();
535 for vc in collected_main.drain(..) {
536 combined_main = combined_main.extend(*vc);
537 }
538 let mut combined_postprocess = EcmascriptInputTransforms::empty();
539 for vc in collected_postprocess.drain(..) {
540 combined_postprocess = combined_postprocess.extend(*vc);
541 }
542
543 match custom_module_type
544 .extend_ecmascript_transforms(
545 combined_preprocess,
546 combined_main,
547 combined_postprocess,
548 )
549 .to_resolved()
550 .await
551 {
552 Ok(new_custom_module_type) => {
553 *custom_module_type = new_custom_module_type;
554 }
555 Err(_) => {
556 ModuleIssue::new(
557 *ident,
558 rcstr!("Invalid module type"),
559 rcstr!(
560 "The custom module type didn't accept the additional Ecmascript \
561 transforms"
562 ),
563 Some(IssueSource::from_source_only(current_source)),
564 )
565 .to_resolved()
566 .await?
567 .emit();
568 }
569 }
570 }
571 }
572 other => {
573 if has_transforms {
574 ModuleIssue::new(
575 *ident,
576 rcstr!("Invalid module type"),
577 format!(
578 "The module type must be Ecmascript or Typescript to add Ecmascript \
579 transforms (got {})",
580 other
581 )
582 .into(),
583 Some(IssueSource::from_source_only(current_source)),
584 )
585 .to_resolved()
586 .await?
587 .emit();
588 collected_preprocess.clear();
589 collected_main.clear();
590 collected_postprocess.clear();
591 }
592 }
593 }
594 Ok(())
595}
596
597async fn process_default_internal(
598 module_asset_context: Vc<ModuleAssetContext>,
599 source: ResolvedVc<Box<dyn Source>>,
600 reference_type: ReferenceType,
601 processed_rules: Vec<usize>,
602) -> Result<Vc<ProcessResult>> {
603 let ident = source.ident().to_resolved().await?;
604 let ident_ref = ident.await?;
605 let path_ref = &ident_ref.path;
606 let options = ModuleOptions::new(
607 path_ref.parent(),
608 module_asset_context.module_options_context(),
609 module_asset_context.resolve_options_context(),
610 );
611
612 let inner_assets = match &reference_type {
613 ReferenceType::Internal(inner_assets) => Some(*inner_assets),
614 _ => None,
615 };
616 let mut current_source = source;
617 let mut current_module_type = None;
618
619 if let ReferenceType::EcmaScriptModules(
621 EcmaScriptModulesReferenceSubType::ImportWithTurbopackUse {
622 ref loader,
623 ref rename_as,
624 ref module_type,
625 },
626 ) = reference_type
627 {
628 let module_options_context = module_asset_context.module_options_context().await?;
629 let webpack_loaders_options = module_options_context
630 .enable_webpack_loaders
631 .as_ref()
632 .context(
633 "turbopackUse import assertions require webpack loaders to be enabled \
634 (enable_webpack_loaders)",
635 )?
636 .await?;
637 let execution_context = module_options_context
638 .execution_context
639 .context("execution_context is required for turbopackUse import assertions")?;
640 let execution_context_value = execution_context.await?;
641
642 let resolve_options_context = module_asset_context
643 .resolve_options_context()
644 .to_resolved()
645 .await?;
646 let source_maps = matches!(
647 module_options_context.ecmascript.source_maps,
648 SourceMapsType::Full
649 );
650
651 let loader_runner_package = webpack_loaders_options.loader_runner_package;
653
654 let import_map = if let Some(loader_runner_package) = loader_runner_package {
655 package_import_map_from_import_mapping(rcstr!("loader-runner"), *loader_runner_package)
656 } else {
657 package_import_map_from_context(
658 rcstr!("loader-runner"),
659 execution_context_value.project_path.clone(),
660 )
661 };
662
663 let evaluate_context = node_evaluate_asset_context(
664 *execution_context,
665 Some(import_map),
666 None,
667 Layer::new(rcstr!("webpack_loaders")),
668 false,
669 )
670 .to_resolved()
671 .await?;
672
673 let loader_request = execution_context_value
674 .project_path
675 .get_relative_request_to(&loader.loader)
676 .context("Loader path must be on project filesystem")?;
677 let webpack_loader_item = WebpackLoaderItem {
678 loader: loader_request,
679 options: loader.options.clone(),
680 };
681 let loaders_vc = WebpackLoaderItems(vec![webpack_loader_item]).cell();
682 let webpack_loaders = WebpackLoaders::new(
683 *evaluate_context,
684 *execution_context,
685 loaders_vc,
686 *webpack_loaders_options.target,
687 webpack_loaders_options.mode.clone(),
688 rename_as.clone(),
689 *resolve_options_context,
690 source_maps,
691 config_tracing_module_context(*execution_context),
692 )
693 .to_resolved()
694 .await?;
695
696 let transforms = Vc::<SourceTransforms>::cell(vec![ResolvedVc::upcast(webpack_loaders)]);
697 current_source = transforms
698 .transform(*current_source, Vc::upcast(module_asset_context))
699 .to_resolved()
700 .await?;
701
702 if let Some(type_str) = module_type {
706 let empty_transforms = EcmascriptInputTransforms::empty().to_resolved().await?;
707 let default_options = EcmascriptOptions::default().resolved_cell();
708 let effect = ConfiguredModuleType::parse(type_str)?
709 .into_effect(
710 empty_transforms,
711 empty_transforms,
712 empty_transforms,
713 default_options,
714 None,
715 Default::default(),
716 )
717 .await?;
718 match effect {
719 ModuleRuleEffect::ModuleType(module_type) => {
720 return apply_module_type(
721 current_source,
722 module_asset_context,
723 module_type.cell(),
724 reference_type,
725 inner_assets,
726 )
727 .await;
728 }
729 ModuleRuleEffect::SourceTransforms(transforms) => {
730 current_source = transforms
731 .transform(*current_source, Vc::upcast(module_asset_context))
732 .to_resolved()
733 .await?;
734 }
736 _ => bail!("Unexpected module rule effect for turbopackModuleType"),
737 }
738 }
739
740 if current_source.ident().to_resolved().await? != ident {
745 let plain_reference_type =
746 ReferenceType::EcmaScriptModules(EcmaScriptModulesReferenceSubType::Import);
747 if let Some(transition) = module_asset_context
748 .await?
749 .transitions
750 .await?
751 .get_by_rules(current_source, &plain_reference_type)
752 .await?
753 {
754 return Ok(transition.process(
755 *current_source,
756 module_asset_context,
757 plain_reference_type,
758 ));
759 } else {
760 return Box::pin(process_default(
761 module_asset_context,
762 current_source,
763 plain_reference_type,
764 processed_rules,
765 ))
766 .await;
767 }
768 }
769 }
770
771 let mut collected_preprocess: Vec<ResolvedVc<EcmascriptInputTransforms>> = Vec::new();
774 let mut collected_main: Vec<ResolvedVc<EcmascriptInputTransforms>> = Vec::new();
775 let mut collected_postprocess: Vec<ResolvedVc<EcmascriptInputTransforms>> = Vec::new();
776
777 let options_value = options.await?;
778 'outer: for (i, rule) in options_value.rules.iter().enumerate() {
779 if processed_rules.contains(&i) {
780 continue;
781 }
782 if rule.matches(source, path_ref, &reference_type).await? {
783 for effect in rule.effects() {
784 match effect {
785 ModuleRuleEffect::Ignore => {
786 return Ok(ProcessResult::Ignore.cell());
787 }
788 ModuleRuleEffect::SourceTransforms(transforms) => {
789 current_source = transforms
790 .transform(*current_source, Vc::upcast(module_asset_context))
791 .to_resolved()
792 .await?;
793 if current_source.ident().to_resolved().await? != ident {
794 if let Some(transition) = module_asset_context
796 .await?
797 .transitions
798 .await?
799 .get_by_rules(current_source, &reference_type)
800 .await?
801 {
802 return Ok(transition.process(
803 *current_source,
804 module_asset_context,
805 reference_type,
806 ));
807 } else {
808 let mut processed_rules = processed_rules.clone();
809 processed_rules.push(i);
810 return Box::pin(process_default(
811 module_asset_context,
812 current_source,
813 reference_type,
814 processed_rules,
815 ))
816 .await;
817 }
818 }
819 }
820 ModuleRuleEffect::ModuleType(module) => {
821 let mut module = module.clone();
825 apply_module_rule_transforms(
826 &mut module,
827 &mut collected_preprocess,
828 &mut collected_main,
829 &mut collected_postprocess,
830 ident,
831 current_source,
832 )
833 .await?;
834 current_module_type = Some(module);
835 break 'outer;
836 }
837 ModuleRuleEffect::ExtendEcmascriptTransforms {
838 preprocess: extend_preprocess,
839 main: extend_main,
840 postprocess: extend_postprocess,
841 } => {
842 collected_preprocess.push(*extend_preprocess);
844 collected_main.push(*extend_main);
845 collected_postprocess.push(*extend_postprocess);
846 }
847 }
848 }
849 }
850 }
851
852 let Some(module_type) = current_module_type else {
853 return Ok(ProcessResult::Unknown(current_source).cell());
854 };
855
856 let module = apply_module_type(
857 current_source,
858 module_asset_context,
859 module_type.cell(),
860 reference_type,
861 inner_assets,
862 )
863 .await?;
864
865 Ok(module)
866}
867
868#[turbo_tasks::function]
871pub async fn externals_tracing_module_context(
872 compile_time_info: Vc<CompileTimeInfo>,
873 resolve_typescript: bool,
874 prune: Option<(FileSystemPath, ResolvedVc<Glob>)>,
875 trace_file_references: bool,
876) -> Result<Vc<ModuleAssetContext>> {
877 let mut extensions = vec![rcstr!(".js"), rcstr!(".node"), rcstr!(".json")];
878 if resolve_typescript {
879 extensions.insert(0, rcstr!(".ts"));
880 }
881
882 let prune_rules = match prune {
883 Some((base, glob)) => vec![ModuleRule::new(
884 RuleCondition::ResourcePathGlob {
885 base,
886 glob: glob.await?,
887 },
888 vec![ModuleRuleEffect::Ignore],
889 )],
890 None => vec![],
891 };
892
893 let resolve_options = ResolveOptionsContext {
894 custom_extensions: Some(extensions),
895 emulate_environment: Some(compile_time_info.await?.environment),
896 loose_errors: true,
897 collect_affecting_sources: true,
898 custom_conditions: vec![rcstr!("node")],
899 module_sync: ConditionValue::Unknown,
900 ..Default::default()
901 };
902
903 Ok(ModuleAssetContext::new_without_replace_externals(
904 Default::default(),
905 compile_time_info,
906 ModuleOptionsContext {
912 ecmascript: EcmascriptOptionsContext {
913 enable_typescript_transform: Some(
914 TypescriptTransformOptions::default().resolved_cell(),
915 ),
916 source_maps: SourceMapsType::None,
919 ..Default::default()
920 },
921 css: CssOptionsContext {
922 source_maps: SourceMapsType::None,
923 enable_raw_css: true,
924 ..Default::default()
925 },
926 environment: None,
929 analyze_mode: AnalyzeMode {
930 is_codegen: false,
931 trace_file_references,
932 },
933 module_rules: prune_rules,
934 ..Default::default()
937 }
938 .cell(),
939 resolve_options.cell(),
940 Layer::new(rcstr!("externals-tracing")),
941 ))
942}
943
944#[turbo_tasks::value_impl]
945impl AssetContext for ModuleAssetContext {
946 #[turbo_tasks::function]
947 fn compile_time_info(&self) -> Vc<CompileTimeInfo> {
948 *self.compile_time_info
949 }
950
951 fn layer(&self) -> Layer {
952 self.layer.clone()
953 }
954
955 #[turbo_tasks::function]
956 async fn resolve_options(
957 self: Vc<Self>,
958 origin_path: FileSystemPath,
959 ) -> Result<Vc<ResolveOptions>> {
960 let this = self.await?;
961 let module_asset_context = if let Some(transition) = this.transition {
962 transition.process_context(self)
963 } else {
964 self
965 };
966 let options = resolve_options(
968 origin_path.parent(),
969 *module_asset_context.await?.resolve_options_context,
970 );
971 let runtime_import_map = turbopack_ecmascript_runtime::turbopack_runtime_import_map()
975 .to_resolved()
976 .await?;
977 Ok(options.with_extended_import_map(*runtime_import_map))
978 }
979
980 #[turbo_tasks::function]
981 async fn resolve_asset(
982 self: Vc<Self>,
983 origin_path: FileSystemPath,
984 request: Vc<Request>,
985 resolve_options: Vc<ResolveOptions>,
986 reference_type: ReferenceType,
987 ) -> Result<Vc<ModuleResolveResult>> {
988 let context_path = origin_path.parent();
989
990 let result = resolve(
991 context_path,
992 reference_type.clone(),
993 request,
994 resolve_options,
995 );
996
997 let mut result = self.process_resolve_result(*result.to_resolved().await?, reference_type);
998 let this = self.await?;
999 if this.is_types_resolving_enabled().await? {
1000 let types_result = type_resolve(
1001 Vc::upcast(PlainResolveOrigin::new(Vc::upcast(self), origin_path)),
1002 request,
1003 );
1004
1005 result = ModuleResolveResult::alternatives(vec![result, types_result]);
1006 }
1007
1008 Ok(result)
1009 }
1010
1011 #[turbo_tasks::function]
1012 async fn process_resolve_result(
1013 self: Vc<Self>,
1014 result: Vc<ResolveResult>,
1015 reference_type: ReferenceType,
1016 ) -> Result<Vc<ModuleResolveResult>> {
1017 let this = self.await?;
1018
1019 let replace_externals = this.replace_externals;
1020 let import_externals = this
1021 .module_options_context
1022 .await?
1023 .ecmascript
1024 .import_externals;
1025
1026 let result = result.await?;
1027
1028 let result = result
1029 .map_primary_items(|item| {
1030 let reference_type = reference_type.clone();
1031 async move {
1032 Ok(match item {
1033 ResolveResultItem::Source(source) => {
1034 match &*self.process(*source, reference_type).await? {
1035 ProcessResult::Module(module) => {
1036 ModuleResolveResultItem::Module(*module)
1037 }
1038 ProcessResult::Unknown(source) => {
1039 ModuleResolveResultItem::Unknown(*source)
1040 }
1041 ProcessResult::Ignore => ModuleResolveResultItem::Ignore,
1042 }
1043 }
1044 ResolveResultItem::External {
1045 name,
1046 ty,
1047 traced,
1048 target,
1049 } => {
1050 let replacement = if replace_externals {
1051 let target = if let Some(mut target) = target {
1054 loop {
1055 let parent = target.parent();
1056 if parent.is_root() {
1057 break;
1058 }
1059 if parent.file_name() == "node_modules" {
1060 break;
1061 }
1062 if parent.file_name().starts_with("@")
1063 && parent.parent().file_name() == "node_modules"
1064 {
1065 break;
1066 }
1067 target = parent;
1068 }
1069 Some(target)
1070 } else {
1071 None
1072 };
1073
1074 let analyze_mode = if traced == ExternalTraced::Traced
1075 && let Some(options) = &self
1076 .module_options_context()
1077 .await?
1078 .enable_externals_tracing
1079 {
1080 let options = options.await?;
1085 let origin = PlainResolveOrigin::new(
1086 Vc::upcast(externals_tracing_module_context(
1087 *options.compile_time_info,
1088 false,
1089 None,
1090 true,
1091 )),
1092 target
1097 .as_ref()
1098 .unwrap_or(&options.tracing_root)
1099 .join("_")?,
1100 );
1101 CachedExternalTracingMode::Traced {
1102 origin: ResolvedVc::upcast(origin.to_resolved().await?),
1103 }
1104 } else {
1105 CachedExternalTracingMode::Untraced
1106 };
1107
1108 replace_external(&name, ty, target, import_externals, analyze_mode)
1109 .await?
1110 } else {
1111 None
1112 };
1113
1114 replacement
1115 .unwrap_or_else(|| ModuleResolveResultItem::External { name, ty })
1116 }
1117 ResolveResultItem::Ignore => ModuleResolveResultItem::Ignore,
1118 ResolveResultItem::Empty => ModuleResolveResultItem::Empty,
1119 ResolveResultItem::Error(e) => ModuleResolveResultItem::Error(e),
1120 ResolveResultItem::Custom(u8) => ModuleResolveResultItem::Custom(u8),
1121 })
1122 }
1123 })
1124 .await?;
1125
1126 Ok(result.cell())
1127 }
1128
1129 #[turbo_tasks::function]
1130 async fn process(
1131 self: Vc<Self>,
1132 asset: ResolvedVc<Box<dyn Source>>,
1133 reference_type: ReferenceType,
1134 ) -> Result<Vc<ProcessResult>> {
1135 let this = self.await?;
1136 if let Some(transition) = this.transition {
1137 Ok(transition.process(*asset, self, reference_type))
1138 } else {
1139 Ok(self
1140 .process_with_transition_rules(asset, reference_type)
1141 .await?)
1142 }
1143 }
1144
1145 #[turbo_tasks::function]
1146 async fn with_transition(&self, transition: RcStr) -> Result<Vc<Box<dyn AssetContext>>> {
1147 Ok(
1148 if let Some(transition) = self.transitions.await?.get_named(transition) {
1149 Vc::upcast(ModuleAssetContext::new_transition(
1150 *self.transitions,
1151 *self.compile_time_info,
1152 *self.module_options_context,
1153 *self.resolve_options_context,
1154 self.layer.clone(),
1155 *transition,
1156 ))
1157 } else {
1158 Vc::upcast(ModuleAssetContext::new(
1160 *self.transitions,
1161 *self.compile_time_info,
1162 *self.module_options_context,
1163 *self.resolve_options_context,
1164 self.layer.clone(),
1165 ))
1166 },
1167 )
1168 }
1169}
1170
1171#[turbo_tasks::function]
1172pub async fn emit_asset(asset: Vc<Box<dyn OutputAsset>>) -> Result<()> {
1173 asset
1174 .content()
1175 .write(asset.path().owned().await?)
1176 .as_side_effect()
1177 .await?;
1178
1179 Ok(())
1180}
1181
1182#[turbo_tasks::function]
1183pub async fn emit_assets_into_dir(
1184 assets: Vc<ExpandedOutputAssets>,
1185 output_dir: FileSystemPath,
1186) -> Result<()> {
1187 let assets = assets.await?;
1188 let paths = assets.iter().map(|&asset| asset.path()).try_join().await?;
1189 for (&asset, path) in assets.iter().zip(paths.iter()) {
1190 if path.is_inside_ref(&output_dir) {
1191 emit_asset(*asset).as_side_effect().await?;
1192 }
1193 }
1194 Ok(())
1195}
1196
1197#[turbo_tasks::function(operation, root)]
1198pub async fn emit_assets_into_dir_operation(
1199 assets: ResolvedVc<ExpandedOutputAssets>,
1200 output_dir: FileSystemPath,
1201) -> Result<()> {
1202 emit_assets_into_dir(*assets, output_dir)
1203 .as_side_effect()
1204 .await?;
1205 Ok(())
1206}
1207
1208pub async fn replace_external(
1210 name: &RcStr,
1211 ty: ExternalType,
1212 target: Option<FileSystemPath>,
1213 import_externals: bool,
1214 analyze_mode: CachedExternalTracingMode,
1215) -> Result<Option<ModuleResolveResultItem>> {
1216 let external_type = match ty {
1217 ExternalType::CommonJs => CachedExternalType::CommonJs,
1218 ExternalType::EcmaScriptModule => {
1219 if import_externals {
1220 CachedExternalType::EcmaScriptViaImport
1221 } else {
1222 CachedExternalType::EcmaScriptViaRequire
1223 }
1224 }
1225 ExternalType::Global => CachedExternalType::Global,
1226 ExternalType::Script => CachedExternalType::Script,
1227 ExternalType::Url => {
1228 return Ok(None);
1230 }
1231 };
1232
1233 let module = CachedExternalModule::new(name.clone(), target, external_type, analyze_mode)
1234 .to_resolved()
1235 .await?;
1236
1237 Ok(Some(ModuleResolveResultItem::Module(ResolvedVc::upcast(
1238 module,
1239 ))))
1240}