From 85e4b758263d6b91a5a6b27ac76b33c87f2e1d20 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Fri, 8 Aug 2025 02:39:41 +0200 Subject: [PATCH 1/3] pass ModulePart correctly for FreeVarReference::EcmaScriptModule --- .../crates/turbopack-ecmascript/src/references/mod.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/turbopack/crates/turbopack-ecmascript/src/references/mod.rs b/turbopack/crates/turbopack-ecmascript/src/references/mod.rs index c5115fe9e7fd1..a35ce6298ba79 100644 --- a/turbopack/crates/turbopack-ecmascript/src/references/mod.rs +++ b/turbopack/crates/turbopack-ecmascript/src/references/mod.rs @@ -434,7 +434,6 @@ struct AnalysisState<'a> { // There can be many references to import.meta, but only the first should hoist // the object allocation. first_import_meta: bool, - tree_shaking_mode: Option, import_externals: bool, ignore_dynamic_requests: bool, url_rewrite_behavior: Option, @@ -989,7 +988,6 @@ pub(crate) async fn analyse_ecmascript_module_internal( fun_args_values: Default::default(), var_cache: Default::default(), first_import_meta: true, - tree_shaking_mode: options.tree_shaking_mode, import_externals: options.import_externals, ignore_dynamic_requests: options.ignore_dynamic_requests, url_rewrite_behavior: options.url_rewrite_behavior, @@ -2601,12 +2599,7 @@ async fn handle_free_var_reference( span.hi.to_u32(), ), Default::default(), - match state.tree_shaking_mode { - Some( - TreeShakingMode::ModuleFragments | TreeShakingMode::ReexportsOnly, - ) => export.clone().map(ModulePart::export), - None => None, - }, + export.clone().map(ModulePart::export), state.import_externals, ) .resolved_cell()) From 6ae4a80397a5d54241e206b2fa9e6a0d753a0979 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Fri, 8 Aug 2025 02:59:49 +0200 Subject: [PATCH 2/3] code simplification --- turbopack/crates/turbopack/src/lib.rs | 48 +++++++++++---------------- 1 file changed, 19 insertions(+), 29 deletions(-) diff --git a/turbopack/crates/turbopack/src/lib.rs b/turbopack/crates/turbopack/src/lib.rs index f5cc389700c98..4fcfbd90c95fa 100644 --- a/turbopack/crates/turbopack/src/lib.rs +++ b/turbopack/crates/turbopack/src/lib.rs @@ -174,22 +174,18 @@ async fn apply_module_type( )) } Some(TreeShakingMode::ReexportsOnly) => { - if let Some(part) = part { - match part { - ModulePart::Evaluation => { - if *module.get_exports().split_locals_and_reexports().await? { + if *module.get_exports().split_locals_and_reexports().await? { + if let Some(part) = part { + match part { + ModulePart::Evaluation => { Vc::upcast(EcmascriptModuleLocalsModule::new(*module)) - } else { - Vc::upcast(*module) } - } - ModulePart::Export(_) => { - let side_effect_free_packages = module_asset_context - .side_effect_free_packages() - .resolve() - .await?; + ModulePart::Export(_) => { + let side_effect_free_packages = module_asset_context + .side_effect_free_packages() + .resolve() + .await?; - if *module.get_exports().split_locals_and_reexports().await? { apply_reexport_tree_shaking( Vc::upcast( EcmascriptModuleFacadeModule::new( @@ -202,25 +198,19 @@ async fn apply_module_type( part, side_effect_free_packages, ) - } else { - apply_reexport_tree_shaking( - Vc::upcast(*module), - part, - side_effect_free_packages, - ) } + _ => bail!( + "Invalid module part \"{}\" for reexports only tree \ + shaking mode", + part + ), } - _ => bail!( - "Invalid module part \"{}\" for reexports only tree shaking \ - mode", - part - ), + } else { + Vc::upcast(EcmascriptModuleFacadeModule::new( + Vc::upcast(*module), + ModulePart::facade(), + )) } - } else if *module.get_exports().split_locals_and_reexports().await? { - Vc::upcast(EcmascriptModuleFacadeModule::new( - Vc::upcast(*module), - ModulePart::facade(), - )) } else { Vc::upcast(*module) } From 52d60b27314ffc8ec6f6f14b93c4de1a72d5a6cd Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Fri, 8 Aug 2025 03:00:34 +0200 Subject: [PATCH 3/3] use EsmExport in FindExportFromReexportsResult --- .../src/references/esm/export.rs | 121 ++++++++++++------ 1 file changed, 80 insertions(+), 41 deletions(-) diff --git a/turbopack/crates/turbopack-ecmascript/src/references/esm/export.rs b/turbopack/crates/turbopack-ecmascript/src/references/esm/export.rs index 288e76e53751d..5f90bc2d074cf 100644 --- a/turbopack/crates/turbopack-ecmascript/src/references/esm/export.rs +++ b/turbopack/crates/turbopack-ecmascript/src/references/esm/export.rs @@ -1,6 +1,7 @@ use std::{borrow::Cow, collections::BTreeMap, ops::ControlFlow}; use anyhow::{Result, bail}; +use indexmap::map::Entry; use rustc_hash::FxHashSet; use serde::{Deserialize, Serialize}; use smallvec::{SmallVec, smallvec}; @@ -189,30 +190,44 @@ pub async fn follow_reexports( // Try to find the export in the star exports if !exports_ref.star_exports.is_empty() && &*export_name != "default" { let result = find_export_from_reexports(*module, export_name.clone()).await?; - if let Some(m) = result.esm_export { - module = m; - continue; - } - return match &result.dynamic_exporting_modules[..] { - [] => Ok(FollowExportsResult { - module, - export_name: Some(export_name), - ty: FoundExportType::NotFound, + match &*result { + FindExportFromReexportsResult::NotFound => { + return Ok(FollowExportsResult::cell(FollowExportsResult { + module, + export_name: Some(export_name), + ty: FoundExportType::NotFound, + })); } - .cell()), - [module] => Ok(FollowExportsResult { - module: *module, - export_name: Some(export_name), - ty: FoundExportType::Dynamic, + FindExportFromReexportsResult::EsmExport(esm_export) => { + match handle_declared_export(module, export_name, esm_export).await? { + ControlFlow::Continue((m, n)) => { + module = m.to_resolved().await?; + export_name = n; + continue; + } + ControlFlow::Break(result) => { + return Ok(result.cell()); + } + } } - .cell()), - _ => Ok(FollowExportsResult { - module, - export_name: Some(export_name), - ty: FoundExportType::Dynamic, + FindExportFromReexportsResult::Dynamic(dynamic_exporting_modules) => { + return match &dynamic_exporting_modules[..] { + [] => unreachable!(), + [module] => Ok(FollowExportsResult { + module: *module, + export_name: Some(export_name), + ty: FoundExportType::Dynamic, + } + .cell()), + _ => Ok(FollowExportsResult { + module, + export_name: Some(export_name), + ty: FoundExportType::Dynamic, + } + .cell()), + }; } - .cell()), - }; + } } return Ok(FollowExportsResult::cell(FollowExportsResult { @@ -270,9 +285,10 @@ async fn handle_declared_export( } #[turbo_tasks::value] -struct FindExportFromReexportsResult { - esm_export: Option>>, - dynamic_exporting_modules: Vec>>, +enum FindExportFromReexportsResult { + NotFound, + EsmExport(EsmExport), + Dynamic(Vec>>), } #[turbo_tasks::function] @@ -301,17 +317,25 @@ async fn find_export_from_reexports( } let all_export_names = get_all_export_names(*module).await?; - let esm_export = all_export_names.esm_exports.get(&export_name).copied(); - Ok(FindExportFromReexportsResult { - esm_export, - dynamic_exporting_modules: all_export_names.dynamic_exporting_modules.clone(), - } - .cell()) + Ok( + if let Some(esm_export) = all_export_names.esm_exports.get(&export_name) { + FindExportFromReexportsResult::EsmExport(esm_export.clone()) + } else if all_export_names.dynamic_exporting_modules.is_empty() { + FindExportFromReexportsResult::NotFound + } else { + FindExportFromReexportsResult::Dynamic( + all_export_names.dynamic_exporting_modules.clone(), + ) + } + .cell(), + ) } #[turbo_tasks::value] struct AllExportNamesResult { - esm_exports: FxIndexMap>>, + /// A map from export name to the immediate referenced module. + esm_exports: FxIndexMap, + /// A list of all direct or indirectly referenced modules that are dynamically exporting dynamic_exporting_modules: Vec>>, } @@ -331,7 +355,12 @@ async fn get_all_export_names( let exports = exports.await?; let mut esm_exports = FxIndexMap::default(); let mut dynamic_exporting_modules = Vec::new(); - esm_exports.extend(exports.exports.keys().cloned().map(|n| (n, module))); + esm_exports.extend( + exports + .exports + .iter() + .map(|(name, esm_export)| (name.clone(), esm_export.clone())), + ); let star_export_names = exports .star_exports .iter() @@ -340,7 +369,7 @@ async fn get_all_export_names( if let ReferencedAsset::Some(m) = *ReferencedAsset::from_resolve_result(esm_ref.resolve_reference()).await? { - Some(expand_star_exports(*m)) + Some(expand_star_exports(**esm_ref, *m)) } else { None }, @@ -354,7 +383,7 @@ async fn get_all_export_names( star_export_names .esm_exports .iter() - .map(|(k, &v)| (k.clone(), v)), + .map(|(k, v)| (k.clone(), v.clone())), ); dynamic_exporting_modules .extend(star_export_names.dynamic_exporting_modules.iter().copied()); @@ -369,35 +398,45 @@ async fn get_all_export_names( #[turbo_tasks::value] pub struct ExpandStarResult { - pub esm_exports: FxIndexMap>>, + pub esm_exports: FxIndexMap, pub dynamic_exporting_modules: Vec>>, } #[turbo_tasks::function] pub async fn expand_star_exports( + root_reference: ResolvedVc>, root_module: ResolvedVc>, ) -> Result> { let mut esm_exports = FxIndexMap::default(); let mut dynamic_exporting_modules = Vec::new(); let mut checked_modules = FxHashSet::default(); checked_modules.insert(root_module); - let mut queue = vec![(root_module, root_module.get_exports())]; - while let Some((asset, exports)) = queue.pop() { + let mut queue = vec![(root_reference, root_module, root_module.get_exports())]; + while let Some((reference, asset, exports)) = queue.pop() { match &*exports.await? { EcmascriptExports::EsmExports(exports) => { let exports = exports.await?; - for key in exports.exports.keys() { + for (key, esm_export) in exports.exports.iter() { if key == "default" { continue; } - esm_exports.entry(key.clone()).or_insert_with(|| asset); + if let Entry::Vacant(entry) = esm_exports.entry(key.clone()) { + entry.insert(match esm_export { + &EsmExport::LocalBinding(_, mutable) => EsmExport::ImportedBinding( + ResolvedVc::upcast(reference), + key.clone(), + mutable, + ), + _ => esm_export.clone(), + }); + } } for esm_ref in exports.star_exports.iter() { if let ReferencedAsset::Some(asset) = &*ReferencedAsset::from_resolve_result(esm_ref.resolve_reference()).await? && checked_modules.insert(*asset) { - queue.push((*asset, asset.get_exports())); + queue.push((*esm_ref, *asset, asset.get_exports())); } } } @@ -518,7 +557,7 @@ impl EsmExports { continue; }; - let export_info = expand_star_exports(**asset).await?; + let export_info = expand_star_exports(*esm_ref, **asset).await?; for export in export_info.esm_exports.keys() { if export == "default" {