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