turbopack/
lib.rs

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                    // Skip the evaluation part if the module is marked as side effect free.
146                    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    /// Whether to replace external resolutions with CachedExternalModules. Used with
318    /// ModuleOptionsContext.enable_externals_tracing to handle transitive external dependencies.
319    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        // Need to use record, otherwise future is not Send for some reason.
466        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                            // The ident has been changed, so we need to apply new rules.
536                            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        // Keep these options more or less in sync with
673        // turbopack/crates/turbopack/tests/node-file-trace.rs to ensure that the NFT unit tests
674        // are actually representative of what Turbopack does.
675        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 is not passed in order to avoid downleveling JS / CSS for
685            // node-file-trace.
686            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        // TODO move `apply_commonjs/esm_resolve_options` etc. to here
719        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                                    // result.affecting_sources can be ignored for tracing, as this
798                                    // request will later be resolved relative to tracing_root
799                                    // anyway.
800
801                                    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                // TODO report issue
863                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
962/// Replaces the externals in the result with `ExternalModuleAsset` instances.
963pub 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            // we don't want to wrap url externals.
982            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}