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