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