From 0f5d217a33371a55377d3c8752c341c4b0ff9713 Mon Sep 17 00:00:00 2001 From: Gengkun Date: Wed, 31 Jul 2024 21:01:15 +0800 Subject: [PATCH] refactor: copiable export info (#7390) --- crates/rspack_collections/src/ukey.rs | 6 +- .../src/chunk_graph/chunk_graph_module.rs | 4 +- .../make/cutout/has_module_graph_change.rs | 6 +- .../src/compiler/make/repair/factorize.rs | 27 +- crates/rspack_core/src/concatenated_module.rs | 66 +- .../src/dependency/runtime_template.rs | 7 +- crates/rspack_core/src/exports_info.rs | 1244 ++++++++--------- crates/rspack_core/src/module.rs | 5 +- crates/rspack_core/src/module_graph/mod.rs | 89 +- crates/rspack_core/src/module_graph/module.rs | 8 +- .../rspack_core/src/module_graph/vec_map.rs | 33 - .../src/parser_and_generator/mod.rs | 6 +- .../common_js_export_require_dependency.rs | 57 +- .../commonjs/common_js_exports_dependency.rs | 1 - .../common_js_full_require_dependency.rs | 1 - .../common_js_self_reference_dependency.rs | 1 - .../esm/harmony_compatibility_dependency.rs | 5 +- .../harmony_export_expression_dependency.rs | 1 - ...ny_export_imported_specifier_dependency.rs | 149 +- .../harmony_export_specifier_dependency.rs | 4 +- .../esm/harmony_import_dependency.rs | 19 +- .../src/dependency/esm/provide_dependency.rs | 4 +- .../src/dependency/export_info_dependency.rs | 19 +- .../dependency/pure_expression_dependency.rs | 2 +- .../plugin/flag_dependency_exports_plugin.rs | 80 +- .../plugin/flag_dependency_usage_plugin.rs | 51 +- .../src/plugin/mangle_exports_plugin.rs | 107 +- .../src/plugin/module_concatenation_plugin.rs | 38 +- .../src/plugin/side_effects_flag_plugin.rs | 10 +- crates/rspack_plugin_json/src/lib.rs | 32 +- .../src/assign_library_plugin.rs | 8 +- .../src/export_property_library_plugin.rs | 15 +- .../src/modern_module_library_plugin.rs | 9 +- .../src/module_library_plugin.rs | 9 +- .../src/lib.rs | 2 +- .../src/parser_and_generator.rs | 1 - 36 files changed, 988 insertions(+), 1138 deletions(-) delete mode 100644 crates/rspack_core/src/module_graph/vec_map.rs diff --git a/crates/rspack_collections/src/ukey.rs b/crates/rspack_collections/src/ukey.rs index 1aa1ef7bef2..a1fecb7e8e3 100644 --- a/crates/rspack_collections/src/ukey.rs +++ b/crates/rspack_collections/src/ukey.rs @@ -2,8 +2,10 @@ use std::collections::HashSet; use std::hash::Hash; use std::{collections::HashMap, fmt::Debug, hash::BuildHasherDefault}; +use dashmap::{DashMap, DashSet}; use indexmap::{IndexMap, IndexSet}; use rayon::prelude::*; +use serde::{Deserialize, Serialize}; #[macro_export] macro_rules! impl_item_ukey { @@ -18,16 +20,18 @@ macro_rules! impl_item_ukey { pub type UkeyMap = HashMap>; pub type UkeyIndexMap = IndexMap>; +pub type UkeyDashMap = DashMap>; pub type UkeySet = HashSet>; pub type UkeyIndexSet = IndexSet>; +pub type UkeyDashSet = DashSet>; pub trait ItemUkey { fn ukey(&self) -> Ukey; } /// Ukey stands for Unique key -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] pub struct Ukey(u32); impl Ukey { diff --git a/crates/rspack_core/src/chunk_graph/chunk_graph_module.rs b/crates/rspack_core/src/chunk_graph/chunk_graph_module.rs index 26304cbbd08..0a263e94b02 100644 --- a/crates/rspack_core/src/chunk_graph/chunk_graph_module.rs +++ b/crates/rspack_core/src/chunk_graph/chunk_graph_module.rs @@ -4,7 +4,7 @@ use std::hash::Hasher; use rspack_collections::{IdentifierMap, UkeySet}; use rspack_util::ext::DynHash; -use rustc_hash::{FxHashSet as HashSet, FxHasher}; +use rustc_hash::FxHasher; use crate::update_hash::{UpdateHashContext, UpdateRspackHash}; use crate::ChunkGraph; @@ -186,7 +186,7 @@ impl ChunkGraph { module_graph .get_exports_info(&module.identifier()) - .export_info_hash(&mut hasher, module_graph, &mut HashSet::default()); + .export_info_hash(&mut hasher, module_graph, &mut UkeySet::default()); module .get_blocks() diff --git a/crates/rspack_core/src/compiler/make/cutout/has_module_graph_change.rs b/crates/rspack_core/src/compiler/make/cutout/has_module_graph_change.rs index 89350ced7ac..3ee4c4ac9c4 100644 --- a/crates/rspack_core/src/compiler/make/cutout/has_module_graph_change.rs +++ b/crates/rspack_core/src/compiler/make/cutout/has_module_graph_change.rs @@ -128,7 +128,7 @@ mod t { use crate::{ compiler::make::cutout::has_module_graph_change::ModuleDeps, AsContextDependency, BuildInfo, BuildMeta, CodeGenerationResult, Compilation, ConcatenationScope, Context, DependenciesBlock, - Dependency, DependencyId, DependencyTemplate, ExportsInfoId, FactoryMeta, Module, + Dependency, DependencyId, DependencyTemplate, ExportsInfo, FactoryMeta, Module, ModuleDependency, ModuleGraph, ModuleGraphModule, ModuleGraphPartial, ModuleIdentifier, ModuleType, RuntimeSpec, SourceType, }; @@ -304,9 +304,9 @@ mod t { let module1_id = module1.id; mg.add_module(module_orig); - mg.add_module_graph_module(ModuleGraphModule::new(module_orig_id, ExportsInfoId::new())); + mg.add_module_graph_module(ModuleGraphModule::new(module_orig_id, ExportsInfo::new())); mg.add_module(module1); - mg.add_module_graph_module(ModuleGraphModule::new(module1_id, ExportsInfoId::new())); + mg.add_module_graph_module(ModuleGraphModule::new(module1_id, ExportsInfo::new())); mg.add_dependency(dep1); mg.set_resolved_module(Some(module_orig_id), dep1_id, module1_id) .unwrap(); diff --git a/crates/rspack_core/src/compiler/make/repair/factorize.rs b/crates/rspack_core/src/compiler/make/repair/factorize.rs index 0669cba715e..6ea6e013daa 100644 --- a/crates/rspack_core/src/compiler/make/repair/factorize.rs +++ b/crates/rspack_core/src/compiler/make/repair/factorize.rs @@ -9,9 +9,9 @@ use super::{add::AddTask, MakeTaskContext}; use crate::{ module_graph::ModuleGraphModule, utils::task_loop::{Task, TaskResult, TaskType}, - BoxDependency, CompilerOptions, Context, DependencyId, ExportInfo, ExportsInfo, ModuleFactory, - ModuleFactoryCreateData, ModuleFactoryResult, ModuleIdentifier, ModuleLayer, ModuleProfile, - Resolve, + BoxDependency, CompilerOptions, Context, DependencyId, ExportInfoData, ExportsInfoData, + ModuleFactory, ModuleFactoryCreateData, ModuleFactoryResult, ModuleIdentifier, ModuleLayer, + ModuleProfile, Resolve, }; #[derive(Debug)] @@ -58,9 +58,9 @@ impl Task for FactorizeTask { .or(self.issuer_layer.as_ref()) .cloned(); - let other_exports_info = ExportInfo::new(None, None); - let side_effects_only_info = ExportInfo::new(Some("*side effects only*".into()), None); - let exports_info = ExportsInfo::new(other_exports_info.id, side_effects_only_info.id); + let other_exports_info = ExportInfoData::new(None, None); + let side_effects_only_info = ExportInfoData::new(Some("*side effects only*".into()), None); + let exports_info = ExportsInfoData::new(other_exports_info.id(), side_effects_only_info.id()); let factorize_result_task = FactorizeResultTask { // dependency: dep_id, original_module_identifier: self.original_module_identifier, @@ -141,9 +141,9 @@ impl Task for FactorizeTask { /// a struct temporarily used creating ExportsInfo #[derive(Debug)] pub struct ExportsInfoRelated { - pub exports_info: ExportsInfo, - pub other_exports_info: ExportInfo, - pub side_effects_info: ExportInfo, + pub exports_info: ExportsInfoData, + pub other_exports_info: ExportInfoData, + pub side_effects_info: ExportInfoData, } #[derive(Debug)] @@ -250,19 +250,20 @@ impl Task for FactorizeResultTask { return Ok(vec![]); }; let module_identifier = module.identifier(); - let mut mgm = ModuleGraphModule::new(module.identifier(), exports_info_related.exports_info.id); + let mut mgm = + ModuleGraphModule::new(module.identifier(), exports_info_related.exports_info.id()); mgm.set_issuer_if_unset(original_module_identifier); module_graph.set_exports_info( - exports_info_related.exports_info.id, + exports_info_related.exports_info.id(), exports_info_related.exports_info, ); module_graph.set_export_info( - exports_info_related.side_effects_info.id, + exports_info_related.side_effects_info.id(), exports_info_related.side_effects_info, ); module_graph.set_export_info( - exports_info_related.other_exports_info.id, + exports_info_related.other_exports_info.id(), exports_info_related.other_exports_info, ); tracing::trace!("Module created: {}", &module_identifier); diff --git a/crates/rspack_core/src/concatenated_module.rs b/crates/rspack_core/src/concatenated_module.rs index 155dab82525..1e759d8a65f 100644 --- a/crates/rspack_core/src/concatenated_module.rs +++ b/crates/rspack_core/src/concatenated_module.rs @@ -42,7 +42,7 @@ use crate::{ ChunkInitFragments, CodeGenerationDataTopLevelDeclarations, CodeGenerationExportsFinalNames, CodeGenerationResult, Compilation, ConcatenatedModuleIdent, ConcatenationScope, ConnectionId, ConnectionState, Context, DependenciesBlock, DependencyId, DependencyTemplate, DependencyType, - ErrorSpan, ExportInfoId, ExportInfoProvided, ExportsArgument, ExportsType, FactoryMeta, + ErrorSpan, ExportInfo, ExportInfoProvided, ExportsArgument, ExportsType, FactoryMeta, IdentCollector, LibIdentOptions, Module, ModuleDependency, ModuleGraph, ModuleGraphConnection, ModuleIdentifier, ModuleLayer, ModuleType, Resolve, RuntimeCondition, RuntimeGlobals, RuntimeSpec, SourceType, SpanExt, Template, UsageState, UsedName, DEFAULT_EXPORT, @@ -923,13 +923,18 @@ impl Module for ConcatenatedModule { let exports_info = module_graph.get_exports_info(&root_module_id); let mut exports_final_names: Vec<(String, String)> = vec![]; - for (_, export_info_id) in exports_info.exports.iter() { - let export_info = export_info_id.get_export_info(&module_graph); - let name = export_info.name.clone().unwrap_or("".into()); - if matches!(export_info.provided, Some(ExportInfoProvided::False)) { + for export_info in exports_info.ordered_exports(&module_graph) { + let name = export_info + .name(&module_graph) + .cloned() + .unwrap_or("".into()); + if matches!( + export_info.provided(&module_graph), + Some(ExportInfoProvided::False) + ) { continue; } - let used_name = export_info.get_used_name(None, runtime); + let used_name = export_info.get_used_name(&module_graph, None, runtime); let Some(used_name) = used_name else { unused_exports.insert(name); @@ -952,7 +957,7 @@ impl Module for ConcatenatedModule { exports_final_names.push((used_name.to_string(), final_name.clone())); format!( "/* {} */ {}", - if export_info.is_reexport() { + if export_info.is_reexport(&module_graph) { "reexport" } else { "binding" @@ -969,8 +974,8 @@ impl Module for ConcatenatedModule { if compilation .get_module_graph() .get_exports_info(&self.id()) - .other_exports_info - .get_used(&compilation.get_module_graph(), runtime) + .other_exports_info(&module_graph) + .get_used(&module_graph, runtime) != UsageState::Unused { should_add_harmony_flag = true @@ -1071,17 +1076,22 @@ impl Module for ConcatenatedModule { let mut ns_obj = Vec::new(); let exports_info = module_graph.get_exports_info(module_info_id); - for (_name, export_info_id) in exports_info.exports.iter() { - let export_info = export_info_id.get_export_info(&module_graph); - if matches!(export_info.provided, Some(ExportInfoProvided::False)) { + for export_info in exports_info.ordered_exports(&module_graph) { + if matches!( + export_info.provided(&module_graph), + Some(ExportInfoProvided::False) + ) { continue; } - if let Some(used_name) = export_info.get_used_name(None, runtime) { + if let Some(used_name) = export_info.get_used_name(&module_graph, None, runtime) { let final_name = Self::get_final_name( &compilation.get_module_graph(), module_info_id, - vec![export_info.name.clone().unwrap_or("".into())], + vec![export_info + .name(&module_graph) + .cloned() + .unwrap_or("".into())], &mut module_to_info_map, runtime, &mut needed_namespace_objects, @@ -1822,7 +1832,7 @@ impl ConcatenatedModule { as_call: bool, strict_harmony_module: bool, asi_safe: Option, - already_visited: &mut HashSet, + already_visited: &mut HashSet, ) -> Binding { let info = module_to_info_map .get(info_id) @@ -1984,12 +1994,9 @@ impl ConcatenatedModule { let exports_info = mg.get_exports_info(&info.id()); // webpack use get_exports_info here, https://github.com/webpack/webpack/blob/ac7e531436b0d47cd88451f497cdfd0dad41535d/lib/optimize/ConcatenatedModule.js#L377-L377 // But in our arch, there is no way to modify module graph during code_generation phase - let export_info_id = exports_info - .id - .get_read_only_export_info(&export_name[0], mg) - .id; + let export_info = exports_info.get_read_only_export_info(mg, &export_name[0]); - if already_visited.contains(&export_info_id) { + if already_visited.contains(&export_info) { return Binding::Raw(RawBinding { raw_name: "/* circular reexport */ Object(function x() { x() }())".into(), ids: Vec::new(), @@ -1999,13 +2006,15 @@ impl ConcatenatedModule { }); } - already_visited.insert(export_info_id); + already_visited.insert(export_info); match info { ModuleInfo::Concatenated(info) => { let export_id = export_name.first().cloned(); - let export_info = export_info_id.get_export_info(mg); - if matches!(export_info.provided, Some(crate::ExportInfoProvided::False)) { + if matches!( + export_info.provided(mg), + Some(crate::ExportInfoProvided::False) + ) { needed_namespace_objects.insert(info.module); return Binding::Raw(RawBinding { raw_name: info @@ -2024,9 +2033,7 @@ impl ConcatenatedModule { && let Some(direct_export) = info.export_map.as_ref().and_then(|map| map.get(export_id)) { if let Some(used_name) = - exports_info - .id - .get_used_name(mg, runtime, UsedName::Vec(export_name.clone())) + exports_info.get_used_name(mg, runtime, UsedName::Vec(export_name.clone())) { // https://github.com/webpack/webpack/blob/1f99ad6367f2b8a6ef17cce0e058f7a67fb7db18/lib/optimize/ConcatenatedModule.js#L402-L404 let used_name = used_name.to_used_name_vec(); @@ -2064,7 +2071,7 @@ impl ConcatenatedModule { }); } - let reexport = export_info_id.find_target( + let reexport = export_info.find_target( mg, Arc::new(|module: &ModuleIdentifier| module_to_info_map.contains_key(module)), ); @@ -2106,7 +2113,6 @@ impl ConcatenatedModule { if info.namespace_export_symbol.is_some() { // That's how webpack write https://github.com/webpack/webpack/blob/1f99ad6367f2b8a6ef17cce0e058f7a67fb7db18/lib/optimize/ConcatenatedModule.js#L463-L471 let used_name = exports_info - .id .get_used_name(mg, runtime, UsedName::Vec(export_name.clone())) .expect("should have export name"); let used_name = used_name.to_used_name_vec(); @@ -2131,9 +2137,7 @@ impl ConcatenatedModule { } ModuleInfo::External(info) => { if let Some(used_name) = - exports_info - .id - .get_used_name(mg, runtime, UsedName::Vec(export_name.clone())) + exports_info.get_used_name(mg, runtime, UsedName::Vec(export_name.clone())) { let used_name = used_name.to_used_name_vec(); let comment = if used_name == export_name { diff --git a/crates/rspack_core/src/dependency/runtime_template.rs b/crates/rspack_core/src/dependency/runtime_template.rs index 9850b3a191e..2c172f1570e 100644 --- a/crates/rspack_core/src/dependency/runtime_template.rs +++ b/crates/rspack_core/src/dependency/runtime_template.rs @@ -206,11 +206,10 @@ pub fn export_from_import( if !export_name.is_empty() { let used_name: Cow> = { - let exports_info_id = compilation + let exports_info = compilation .get_module_graph() - .get_exports_info(&module_identifier) - .id; - let used = exports_info_id.get_used_name( + .get_exports_info(&module_identifier); + let used = exports_info.get_used_name( &compilation.get_module_graph(), *runtime, crate::UsedName::Vec(export_name.clone()), diff --git a/crates/rspack_core/src/exports_info.rs b/crates/rspack_core/src/exports_info.rs index 754a006db9d..3491d994f56 100644 --- a/crates/rspack_core/src/exports_info.rs +++ b/crates/rspack_core/src/exports_info.rs @@ -1,20 +1,22 @@ use std::borrow::Cow; -use std::collections::hash_map::DefaultHasher; use std::collections::hash_map::Entry; use std::collections::BTreeMap; use std::hash::Hasher; -use std::ops::Deref; use std::sync::atomic::AtomicU32; use std::sync::atomic::Ordering::Relaxed; use std::sync::Arc; -use dashmap::DashMap; use itertools::Itertools; use once_cell::sync::Lazy; +use rspack_collections::impl_item_ukey; +use rspack_collections::Ukey; +use rspack_collections::UkeyDashMap; +use rspack_collections::UkeySet; use rspack_util::atom::Atom; use rspack_util::ext::DynHash; use rustc_hash::FxHashMap as HashMap; use rustc_hash::FxHashSet as HashSet; +use rustc_hash::FxHasher; use serde::Serialize; use crate::{ @@ -27,23 +29,25 @@ pub trait ExportsHash { &self, hasher: &mut dyn Hasher, module_graph: &ModuleGraph, - already_visited: &mut HashSet, + already_visited: &mut UkeySet, ); } -static EXPORTS_INFO_HASH: Lazy> = Lazy::new(DashMap::new); +static EXPORTS_INFO_HASH: Lazy> = Lazy::new(UkeyDashMap::default); #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Ord, PartialOrd, Serialize)] -pub struct ExportsInfoId(u32); +pub struct ExportsInfo(Ukey); -pub static EXPORTS_INFO_ID: AtomicU32 = AtomicU32::new(0); +static NEXT_EXPORTS_INFO_UKEY: AtomicU32 = AtomicU32::new(0); -impl ExportsHash for ExportsInfoId { +impl_item_ukey!(ExportsInfo); + +impl ExportsHash for ExportsInfo { fn export_info_hash( &self, hasher: &mut dyn Hasher, module_graph: &ModuleGraph, - already_visited: &mut HashSet, + already_visited: &mut UkeySet, ) { if let Some(exports_info) = module_graph.try_get_exports_info_by_id(self) { exports_info.export_info_hash(hasher, module_graph, already_visited); @@ -51,42 +55,52 @@ impl ExportsHash for ExportsInfoId { } } -impl Deref for ExportsInfoId { - type Target = u32; +impl ExportsInfo { + #[allow(clippy::new_without_default)] + pub fn new() -> Self { + Self(NEXT_EXPORTS_INFO_UKEY.fetch_add(1, Relaxed).into()) + } - fn deref(&self) -> &Self::Target { - &self.0 + pub fn owned_exports<'a>(&self, mg: &'a ModuleGraph) -> impl Iterator + 'a { + self.as_exports_info(mg).exports.values().copied() } -} -impl Default for ExportsInfoId { - fn default() -> Self { - Self::new() + pub fn exports<'a>(&self, mg: &'a ModuleGraph) -> impl Iterator + 'a { + // TODO: handle redirectTo here + self.as_exports_info(mg).exports.values().copied() } -} -impl ExportsInfoId { - pub fn new() -> Self { - Self(EXPORTS_INFO_ID.fetch_add(1, Relaxed)) + pub fn ordered_exports<'a>(&self, mg: &'a ModuleGraph) -> impl Iterator + 'a { + // TODO: handle redirectTo here + // We use BTreeMap here, so exports is already ordered + self.as_exports_info(mg).exports.values().copied() + } + + pub fn other_exports_info(&self, mg: &ModuleGraph) -> ExportInfo { + let info = self.as_exports_info(mg); + if let Some(redirect_to) = info.redirect_to { + return redirect_to.other_exports_info(mg); + } + info.other_exports_info } - pub fn get_exports_info<'a>(&self, mg: &'a ModuleGraph) -> &'a ExportsInfo { + pub fn as_exports_info<'a>(&self, mg: &'a ModuleGraph) -> &'a ExportsInfoData { mg.get_exports_info_by_id(self) } - pub fn get_exports_info_mut<'a>(&self, mg: &'a mut ModuleGraph) -> &'a mut ExportsInfo { + pub fn as_exports_info_mut<'a>(&self, mg: &'a mut ModuleGraph) -> &'a mut ExportsInfoData { mg.get_exports_info_mut_by_id(self) } - pub fn is_export_provided(&self, names: &[Atom], mg: &ModuleGraph) -> Option { + pub fn is_export_provided(&self, mg: &ModuleGraph, names: &[Atom]) -> Option { let name = names.first()?; - let info = self.get_read_only_export_info(name, mg); - if let Some(exports_info) = info.exports_info + let info = self.get_read_only_export_info(mg, name); + if let Some(exports_info) = info.exports_info(mg) && names.len() > 1 { - return exports_info.is_export_provided(&names[1..], mg); + return exports_info.is_export_provided(mg, &names[1..]); } - match info.provided? { + match info.provided(mg)? { ExportInfoProvided::True => { if names.len() == 1 { Some(ExportProvided::True) @@ -100,13 +114,13 @@ impl ExportsInfoId { } pub fn is_module_used(&self, mg: &ModuleGraph, runtime: Option<&RuntimeSpec>) -> bool { - if self.is_used(runtime, mg) { + if self.is_used(mg, runtime) { return true; } - let exports_info = self.get_exports_info(mg); + let exports_info = self.as_exports_info(mg); if !matches!( - exports_info._side_effects_only_info.get_used(mg, runtime), + exports_info.side_effects_only_info.get_used(mg, runtime), UsageState::Unused ) { return true; @@ -143,7 +157,7 @@ impl ExportsInfoId { } } - pub fn set_redirect_name_to(&self, mg: &mut ModuleGraph, id: Option) -> bool { + pub fn set_redirect_name_to(&self, mg: &mut ModuleGraph, id: Option) -> bool { let exports_info = mg.get_exports_info_mut_by_id(self); if exports_info.redirect_to == id { return false; @@ -163,9 +177,9 @@ impl ExportsInfoId { ) -> bool { let mut changed = false; - if let Some(ref exclude_exports) = exclude_exports { + if let Some(exclude_exports) = &exclude_exports { for name in exclude_exports { - self.get_export_info(name, mg); + self.get_export_info(mg, name); } } @@ -173,35 +187,33 @@ impl ExportsInfoId { let redirect_to = exports_info.redirect_to; let other_exports_info = exports_info.other_exports_info; let exports_id_list = exports_info.exports.values().cloned().collect::>(); - for export_info_id in exports_id_list { - let export_info = mg.get_export_info_mut_by_id(&export_info_id); - - if !can_mangle && export_info.can_mangle_provide != Some(false) { - export_info.can_mangle_provide = Some(false); + for export_info in exports_id_list { + if !can_mangle && export_info.can_mangle_provide(mg) != Some(false) { + export_info.set_can_mangle_provide(mg, Some(false)); changed = true; } - if let Some(ref exclude_exports) = exclude_exports { - if let Some(ref export_name) = export_info.name + if let Some(exclude_exports) = &exclude_exports { + if let Some(export_name) = export_info.name(mg) && exclude_exports.contains(export_name) { continue; } } if !matches!( - export_info.provided, + export_info.provided(mg), Some(ExportInfoProvided::True | ExportInfoProvided::Null) ) { - export_info.provided = Some(ExportInfoProvided::Null); + export_info.set_provided(mg, Some(ExportInfoProvided::Null)); changed = true; } if let Some(target_key) = target_key { export_info.set_target( + mg, Some(target_key), target_module, export_info - .name - .clone() - .map(|name| Nullable::Value(vec![name])) + .name(mg) + .map(|name| Nullable::Value(vec![name.clone()])) .as_ref(), priority, ); @@ -221,59 +233,57 @@ impl ExportsInfoId { changed = true; } } else { - let other_exports_info = mg.get_export_info_mut_by_id(&other_exports_info); if !matches!( - other_exports_info.provided, + other_exports_info.provided(mg), Some(ExportInfoProvided::True | ExportInfoProvided::Null) ) { - other_exports_info.provided = Some(ExportInfoProvided::Null); + other_exports_info.set_provided(mg, Some(ExportInfoProvided::Null)); changed = true; } if let Some(target_key) = target_key { - other_exports_info.set_target(Some(target_key), target_module, None, priority); + other_exports_info.set_target(mg, Some(target_key), target_module, None, priority); } - if !can_mangle && other_exports_info.can_mangle_provide != Some(false) { - other_exports_info.can_mangle_provide = Some(false); + if !can_mangle && other_exports_info.can_mangle_provide(mg) != Some(false) { + other_exports_info.set_can_mangle_provide(mg, Some(false)); changed = true; } } changed } - pub fn get_read_only_export_info_recursive<'a>( + pub fn get_read_only_export_info_recursive( &self, + mg: &ModuleGraph, names: &[Atom], - mg: &'a ModuleGraph, - ) -> Option<&'a ExportInfo> { + ) -> Option { if names.is_empty() { return None; } - let export_info = self.get_read_only_export_info(&names[0], mg); + let export_info = self.get_read_only_export_info(mg, &names[0]); if names.len() == 1 { return Some(export_info); } - let exports_info = export_info.exports_info?; - exports_info.get_read_only_export_info_recursive(&names[1..], mg) + let exports_info = export_info.exports_info(mg)?; + exports_info.get_read_only_export_info_recursive(mg, &names[1..]) } - pub fn get_read_only_export_info<'a>(&self, name: &Atom, mg: &'a ModuleGraph) -> &'a ExportInfo { + pub fn get_read_only_export_info(&self, mg: &ModuleGraph, name: &Atom) -> ExportInfo { let exports_info = mg.get_exports_info_by_id(self); - let redirect_id = exports_info.redirect_to; - let other_exports_info_id = exports_info.other_exports_info; - let export_info_id = exports_info.exports.get(name); - if let Some(export_info_id) = export_info_id { - let export_info = mg.get_export_info_by_id(export_info_id); - return export_info; + let redirect_to = exports_info.redirect_to; + let other_exports_info = exports_info.other_exports_info; + let export_info = exports_info.exports.get(name); + if let Some(export_info) = export_info { + return *export_info; } - if let Some(redirect_id) = redirect_id { - return redirect_id.get_read_only_export_info(name, mg); + if let Some(redirect_to) = redirect_to { + return redirect_to.get_read_only_export_info(mg, name); } - mg.get_export_info_by_id(&other_exports_info_id) + other_exports_info } - pub fn get_export_info(&self, name: &Atom, mg: &mut ModuleGraph) -> ExportInfoId { + pub fn get_export_info(&self, mg: &mut ModuleGraph, name: &Atom) -> ExportInfo { let exports_info = mg.get_exports_info_by_id(self); let redirect_id = exports_info.redirect_to; let other_exports_info_id = exports_info.other_exports_info; @@ -282,31 +292,30 @@ impl ExportsInfoId { return *export_info_id; } if let Some(redirect_id) = redirect_id { - return redirect_id.get_export_info(name, mg); + return redirect_id.get_export_info(mg, name); } let other_export_info = mg.get_export_info_by_id(&other_exports_info_id); - let new_info = ExportInfo::new(Some(name.clone()), Some(other_export_info)); + let new_info = ExportInfoData::new(Some(name.clone()), Some(other_export_info)); let new_info_id = new_info.id; mg.set_export_info(new_info_id, new_info); let exports_info = mg.get_exports_info_mut_by_id(self); - exports_info._exports_are_ordered = false; exports_info.exports.insert(name.clone(), new_info_id); new_info_id } pub fn get_nested_exports_info( &self, - name: Option>, mg: &ModuleGraph, - ) -> Option { + name: Option>, + ) -> Option { if let Some(name) = name && !name.is_empty() { - let info = self.get_read_only_export_info(&name[0], mg); - if let Some(exports_info) = info.exports_info { - return exports_info.get_nested_exports_info(Some(name[1..].to_vec()), mg); + let info = self.get_read_only_export_info(mg, &name[0]); + if let Some(exports_info) = info.exports_info(mg) { + return exports_info.get_nested_exports_info(mg, Some(name[1..].to_vec())); } else { return None; } @@ -316,7 +325,7 @@ impl ExportsInfoId { pub fn set_has_use_info(&self, mg: &mut ModuleGraph) { let exports_info = mg.get_exports_info_by_id(self); - let side_effects_only_info_id = exports_info._side_effects_only_info; + let side_effects_only_info_id = exports_info.side_effects_only_info; let redirect_to_id = exports_info.redirect_to; let other_exports_info_id = exports_info.other_exports_info; // this clone aiming to avoid use the mutable ref and immutable ref at the same time. @@ -371,7 +380,7 @@ impl ExportsInfoId { let exports_info = mg.get_exports_info_mut_by_id(self); let export_info_id_list = exports_info.exports.values().cloned().collect::>(); for export_info_id in export_info_id_list { - let export_info = export_info_id.get_export_info_mut(mg); + let export_info = export_info_id.as_export_info_mut(mg); if !matches!(export_info.provided, Some(ExportInfoProvided::True)) { continue; } @@ -423,7 +432,7 @@ impl ExportsInfoId { runtime: Option<&RuntimeSpec>, ) -> bool { let exports_info = mg.get_exports_info_by_id(self); - let side_effects_only_info_id = exports_info._side_effects_only_info; + let side_effects_only_info_id = exports_info.side_effects_only_info; side_effects_only_info_id.set_used_conditionally( mg, Box::new(|value| value == &UsageState::Unused), @@ -441,18 +450,20 @@ impl ExportsInfoId { ) -> Option { match name { UsedName::Str(name) => { - let info = self.get_read_only_export_info(&name, mg); - info.get_used_name(Some(&name), runtime).map(UsedName::Str) + let info = self.get_read_only_export_info(mg, &name); + info + .get_used_name(mg, Some(&name), runtime) + .map(UsedName::Str) } UsedName::Vec(names) => { if names.is_empty() { - if !self.is_used(runtime, mg) { + if !self.is_used(mg, runtime) { return None; } return Some(UsedName::Vec(names)); } - let export_info = self.get_read_only_export_info(&names[0], mg); - let x = export_info.get_used_name(Some(&names[0]), runtime)?; + let export_info = self.get_read_only_export_info(mg, &names[0]); + let x = export_info.get_used_name(mg, Some(&names[0]), runtime)?; let names_len = names.len(); let mut arr = if x == names[0] && names.len() == 1 { names.clone() @@ -462,8 +473,8 @@ impl ExportsInfoId { if names_len == 1 { return Some(UsedName::Vec(arr)); } - if let Some(exports_info) = export_info.exports_info - && export_info.get_used(runtime) == UsageState::OnlyPropertiesUsed + if let Some(exports_info) = export_info.exports_info(mg) + && export_info.get_used(mg, runtime) == UsageState::OnlyPropertiesUsed { let nested = exports_info.get_used_name(mg, runtime, UsedName::Vec(names[1..].to_vec())); let nested = nested?; @@ -479,81 +490,10 @@ impl ExportsInfoId { } } - fn is_used(&self, runtime: Option<&RuntimeSpec>, mg: &ModuleGraph) -> bool { - let exports_info = mg.get_exports_info_by_id(self); - exports_info.is_used(runtime, mg) - } -} - -#[derive(Debug, Clone)] -pub struct ExportsInfo { - pub exports: BTreeMap, - pub other_exports_info: ExportInfoId, - pub _side_effects_only_info: ExportInfoId, - pub _exports_are_ordered: bool, - pub redirect_to: Option, - pub id: ExportsInfoId, -} - -impl ExportsHash for ExportsInfo { - fn export_info_hash( - &self, - hasher: &mut dyn Hasher, - module_graph: &ModuleGraph, - already_visited: &mut HashSet, - ) { - if let Some(hash) = EXPORTS_INFO_HASH.get(&self.id) { - hash.dyn_hash(hasher); - return; - }; - let mut default_hash = DefaultHasher::default(); - for (name, export_info_id) in &self.exports { - name.dyn_hash(&mut default_hash); - export_info_id.export_info_hash(&mut default_hash, module_graph, already_visited); - } - self - .other_exports_info - .export_info_hash(&mut default_hash, module_graph, already_visited); - self - ._side_effects_only_info - .export_info_hash(&mut default_hash, module_graph, already_visited); - self._exports_are_ordered.dyn_hash(&mut default_hash); - - if let Some(redirect_to) = self.redirect_to { - redirect_to.export_info_hash(&mut default_hash, module_graph, already_visited); - } - let hash = default_hash.finish(); - EXPORTS_INFO_HASH.insert(self.id, hash); - hash.dyn_hash(hasher); - } -} - -pub enum ProvidedExports { - Null, - True, - Vec(Vec), -} - -pub enum UsedExports { - Null, - Bool(bool), - Vec(Vec), -} -impl ExportsInfo { - pub fn new(other_exports_info: ExportInfoId, _side_effects_only_info: ExportInfoId) -> Self { - Self { - exports: BTreeMap::default(), - other_exports_info, - _side_effects_only_info, - _exports_are_ordered: false, - redirect_to: None, - id: ExportsInfoId::new(), - } - } - pub fn get_provided_exports(&self, mg: &ModuleGraph) -> ProvidedExports { - if let Some(_redirect_to) = self.redirect_to { - match self.other_exports_info.get_export_info(mg).provided { + let info = self.as_exports_info(mg); + if let Some(_redirect_to) = info.redirect_to { + match info.other_exports_info.provided(mg) { Some(ExportInfoProvided::Null) => { return ProvidedExports::True; } @@ -567,8 +507,8 @@ impl ExportsInfo { } } let mut ret = vec![]; - for export_info_id in self.exports.values() { - let export_info = export_info_id.get_export_info(mg); + for export_info_id in info.exports.values() { + let export_info = export_info_id.as_export_info(mg); match export_info.provided { Some(ExportInfoProvided::True) | Some(ExportInfoProvided::Null) | None => { ret.push(export_info.name.clone().unwrap_or("".into())); @@ -576,8 +516,7 @@ impl ExportsInfo { _ => {} } } - if let Some(id) = self.redirect_to { - let exports_info = id.get_exports_info(mg); + if let Some(exports_info) = info.redirect_to { let provided_exports = exports_info.get_provided_exports(mg); let inner = match provided_exports { ProvidedExports::Null => return ProvidedExports::Null, @@ -594,8 +533,9 @@ impl ExportsInfo { } pub fn get_used_exports(&self, mg: &ModuleGraph, runtime: Option<&RuntimeSpec>) -> UsedExports { - if self.redirect_to.is_none() { - match self.other_exports_info.get_used(mg, runtime) { + let info = self.as_exports_info(mg); + if info.redirect_to.is_none() { + match info.other_exports_info.get_used(mg, runtime) { UsageState::NoInfo => return UsedExports::Null, UsageState::Unknown | UsageState::OnlyPropertiesUsed | UsageState::Used => { return UsedExports::Bool(true); @@ -605,12 +545,12 @@ impl ExportsInfo { } let mut res = vec![]; - for export_info_id in self.exports.values() { + for export_info_id in info.exports.values() { match export_info_id.get_used(mg, runtime) { UsageState::NoInfo => return UsedExports::Null, UsageState::Unknown => return UsedExports::Bool(true), UsageState::OnlyPropertiesUsed | UsageState::Used => { - if let Some(name) = export_info_id.get_export_info(mg).name.to_owned() { + if let Some(name) = export_info_id.as_export_info(mg).name.to_owned() { res.push(name); } } @@ -618,8 +558,8 @@ impl ExportsInfo { } } - if let Some(redirect) = self.redirect_to { - let inner = redirect.get_exports_info(mg).get_used_exports(mg, runtime); + if let Some(redirect) = info.redirect_to { + let inner = redirect.get_used_exports(mg, runtime); match inner { UsedExports::Vec(v) => res.extend(v), UsedExports::Null | UsedExports::Bool(true) => return inner, @@ -628,7 +568,7 @@ impl ExportsInfo { } if res.is_empty() { - match self._side_effects_only_info.get_used(mg, runtime) { + match info.side_effects_only_info.get_used(mg, runtime) { UsageState::NoInfo => return UsedExports::Null, UsageState::Unused => return UsedExports::Bool(false), _ => (), @@ -641,70 +581,60 @@ impl ExportsInfo { /// exports that are relevant (not unused and potential provided) pub fn get_relevant_exports( &self, - runtime: Option<&RuntimeSpec>, mg: &ModuleGraph, - ) -> Vec { + runtime: Option<&RuntimeSpec>, + ) -> Vec { + let info = self.as_exports_info(mg); let mut list = vec![]; - for export_info_id in self.exports.values() { - let export_info = export_info_id.get_export_info(mg); - let used = export_info.get_used(runtime); + for export_info in info.exports.values() { + let used = export_info.get_used(mg, runtime); if matches!(used, UsageState::Unused) { continue; } - if matches!(export_info.provided, Some(ExportInfoProvided::False)) { + if matches!(export_info.provided(mg), Some(ExportInfoProvided::False)) { continue; } - list.push(*export_info_id); + list.push(*export_info); } - if let Some(redirect_to) = self.redirect_to { - for id in redirect_to - .get_exports_info(mg) - .get_relevant_exports(runtime, mg) - { - let name = id.get_export_info(mg).name.as_ref(); - if !self.exports.contains_key(name.unwrap_or(&"".into())) { + if let Some(redirect_to) = info.redirect_to { + for id in redirect_to.get_relevant_exports(mg, runtime) { + let name = id.name(mg); + if !info.exports.contains_key(name.unwrap_or(&"".into())) { list.push(id); } } } - let other_export_info = self.other_exports_info.get_export_info(mg); - if !matches!(other_export_info.provided, Some(ExportInfoProvided::False)) - && other_export_info.get_used(runtime) != UsageState::Unused + let other_export_info = info.other_exports_info; + if !matches!( + other_export_info.provided(mg), + Some(ExportInfoProvided::False) + ) && other_export_info.get_used(mg, runtime) != UsageState::Unused { - list.push(self.other_exports_info); + list.push(info.other_exports_info); } list } - /// only used for old version tree shaking - pub fn old_get_used_exports(&self) -> HashSet { - self.exports.keys().cloned().collect::>() - } - - pub fn owned_exports(&self) -> impl Iterator { - self.exports.values() - } - - pub fn is_equally_used(&self, a: &RuntimeSpec, b: &RuntimeSpec, mg: &ModuleGraph) -> bool { - if let Some(redirect_to) = self.redirect_to { - let redirect_to = redirect_to.get_exports_info(mg); - if redirect_to.is_equally_used(a, b, mg) { + pub fn is_equally_used(&self, mg: &ModuleGraph, a: &RuntimeSpec, b: &RuntimeSpec) -> bool { + let info = self.as_exports_info(mg); + if let Some(redirect_to) = info.redirect_to { + if redirect_to.is_equally_used(mg, a, b) { return false; } } else { - let other_exports_info = &self.other_exports_info.get_export_info(mg); - if other_exports_info.get_used(Some(a)) != other_exports_info.get_used(Some(b)) { + let other_exports_info = info.other_exports_info; + if other_exports_info.get_used(mg, Some(a)) != other_exports_info.get_used(mg, Some(b)) { return false; } } - let side_effects_only_info = self._side_effects_only_info.get_export_info(mg); - if side_effects_only_info.get_used(Some(a)) != side_effects_only_info.get_used(Some(b)) { + let side_effects_only_info = info.side_effects_only_info; + if side_effects_only_info.get_used(mg, Some(a)) != side_effects_only_info.get_used(mg, Some(b)) + { return false; } - for export_info in self.owned_exports() { - let export_info = export_info.get_export_info(mg); - if export_info.get_used(Some(a)) != export_info.get_used(Some(b)) { + for export_info in self.owned_exports(mg) { + if export_info.get_used(mg, Some(a)) != export_info.get_used(mg, Some(b)) { return false; } } @@ -713,88 +643,123 @@ impl ExportsInfo { pub fn get_used( &self, + mg: &ModuleGraph, name: UsedName, runtime: Option<&RuntimeSpec>, - module_graph: &ModuleGraph, ) -> UsageState { match &name { UsedName::Str(value) => { - let info = self.id.get_read_only_export_info(value, module_graph); - info.get_used(runtime) + let info = self.get_read_only_export_info(mg, value); + info.get_used(mg, runtime) } UsedName::Vec(value) => { if value.is_empty() { - return self - .other_exports_info - .get_export_info(module_graph) - .get_used(runtime); + return self.other_exports_info(mg).get_used(mg, runtime); } - let info = self.id.get_read_only_export_info(&value[0], module_graph); - if let Some(exports_info) = info - .exports_info - .map(|id| id.get_exports_info(module_graph)) + let info = self.get_read_only_export_info(mg, &value[0]); + if let Some(exports_info) = info.exports_info(mg) && value.len() > 1 { return exports_info.get_used( + mg, UsedName::Vec(value.iter().skip(1).cloned().collect::>()), runtime, - module_graph, ); } - info.get_used(runtime) + info.get_used(mg, runtime) } } } - pub fn is_used(&self, runtime: Option<&RuntimeSpec>, mg: &ModuleGraph) -> bool { - if let Some(redirect_to) = self.redirect_to { - if redirect_to.is_used(runtime, mg) { + pub fn is_used(&self, mg: &ModuleGraph, runtime: Option<&RuntimeSpec>) -> bool { + let info = self.as_exports_info(mg); + if let Some(redirect_to) = info.redirect_to { + if redirect_to.is_used(mg, runtime) { return true; } } else { - let other_exports_info = mg.get_export_info_by_id(&self.other_exports_info); - if other_exports_info.get_used(runtime) != UsageState::Unused { + let other_exports_info = &info.other_exports_info; + if other_exports_info.get_used(mg, runtime) != UsageState::Unused { return true; } } - for export_info_id in self.exports.values() { - let export_info = mg.get_export_info_by_id(export_info_id); - if export_info.get_used(runtime) != UsageState::Unused { + for export_info in info.exports.values() { + if export_info.get_used(mg, runtime) != UsageState::Unused { return true; } } false } +} - pub fn get_ordered_exports(&self) -> impl Iterator { - // TODO need order - self.exports.values() - } - pub fn set_redirect_name_to(&mut self) {} +#[derive(Debug, Clone)] +pub struct ExportsInfoData { + exports: BTreeMap, + other_exports_info: ExportInfo, + side_effects_only_info: ExportInfo, + redirect_to: Option, + id: ExportsInfo, +} - pub fn set_has_provide_info(&mut self, mg: &mut ModuleGraph) { - for export_info_id in self.exports.values() { - let export_info = mg.get_export_info_mut_by_id(export_info_id); - if export_info.provided.is_none() { - export_info.provided = Some(ExportInfoProvided::False); - } - if export_info.can_mangle_provide.is_none() { - export_info.can_mangle_provide = Some(true); - } +impl ExportsHash for ExportsInfoData { + fn export_info_hash( + &self, + hasher: &mut dyn Hasher, + module_graph: &ModuleGraph, + already_visited: &mut UkeySet, + ) { + if let Some(hash) = EXPORTS_INFO_HASH.get(&self.id) { + hash.dyn_hash(hasher); + return; + }; + let mut default_hash = FxHasher::default(); + for (name, export_info_id) in &self.exports { + name.dyn_hash(&mut default_hash); + export_info_id.export_info_hash(&mut default_hash, module_graph, already_visited); } - if let Some(ref mut redirect_to) = self.redirect_to { - redirect_to.set_has_provide_info(mg); - } else { - let other_export_info = mg.get_export_info_mut_by_id(&self.other_exports_info); - if other_export_info.provided.is_none() { - other_export_info.provided = Some(ExportInfoProvided::False); - } - if other_export_info.can_mangle_provide.is_none() { - other_export_info.can_mangle_provide = Some(true); - } + self + .other_exports_info + .export_info_hash(&mut default_hash, module_graph, already_visited); + self + .side_effects_only_info + .export_info_hash(&mut default_hash, module_graph, already_visited); + + if let Some(redirect_to) = self.redirect_to { + redirect_to.export_info_hash(&mut default_hash, module_graph, already_visited); + } + let hash = default_hash.finish(); + EXPORTS_INFO_HASH.insert(self.id, hash); + hash.dyn_hash(hasher); + } +} + +pub enum ProvidedExports { + Null, + True, + Vec(Vec), +} + +pub enum UsedExports { + Null, + Bool(bool), + Vec(Vec), +} + +impl ExportsInfoData { + pub fn new(other_exports_info: ExportInfo, _side_effects_only_info: ExportInfo) -> Self { + Self { + exports: BTreeMap::default(), + other_exports_info, + side_effects_only_info: _side_effects_only_info, + redirect_to: None, + id: ExportsInfo::new(), } } + + pub fn id(&self) -> ExportsInfo { + self.id + } } #[derive(Debug, Clone)] @@ -830,16 +795,18 @@ pub struct ExportInfoTargetValue { } #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Ord, PartialOrd, Serialize)] -pub struct ExportInfoId(u32); +pub struct ExportInfo(Ukey); -pub static EXPORT_INFO_ID: AtomicU32 = AtomicU32::new(0); +static NEXT_EXPORT_INFO_UKEY: AtomicU32 = AtomicU32::new(0); -impl ExportsHash for ExportInfoId { +impl_item_ukey!(ExportInfo); + +impl ExportsHash for ExportInfo { fn export_info_hash( &self, hasher: &mut dyn Hasher, module_graph: &ModuleGraph, - already_visited: &mut HashSet, + already_visited: &mut UkeySet, ) { if already_visited.contains(self) { return; @@ -852,13 +819,69 @@ impl ExportsHash for ExportInfoId { } } -impl ExportInfoId { - pub fn new() -> Self { - Self(EXPORT_INFO_ID.fetch_add(1, Relaxed)) +impl ExportInfo { + fn new() -> Self { + Self(NEXT_EXPORT_INFO_UKEY.fetch_add(1, Relaxed).into()) + } + + pub fn name<'a>(&self, mg: &'a ModuleGraph) -> Option<&'a Atom> { + self.as_export_info(mg).name.as_ref() + } + + pub fn provided<'a>(&self, mg: &'a ModuleGraph) -> Option<&'a ExportInfoProvided> { + self.as_export_info(mg).provided.as_ref() + } + + pub fn set_provided(&self, mg: &mut ModuleGraph, value: Option) { + self.as_export_info_mut(mg).provided = value; + } + + pub fn can_mangle_provide(&self, mg: &ModuleGraph) -> Option { + self.as_export_info(mg).can_mangle_provide + } + + pub fn set_can_mangle_provide(&self, mg: &mut ModuleGraph, value: Option) { + self.as_export_info_mut(mg).can_mangle_provide = value; + } + + pub fn can_mangle_use(&self, mg: &ModuleGraph) -> Option { + self.as_export_info(mg).can_mangle_use + } + + pub fn set_can_mangle_use(&self, mg: &mut ModuleGraph, value: Option) { + self.as_export_info_mut(mg).can_mangle_use = value; + } + + pub fn terminal_binding(&self, mg: &ModuleGraph) -> bool { + self.as_export_info(mg).terminal_binding + } + + pub fn set_terminal_binding(&self, mg: &mut ModuleGraph, value: bool) { + self.as_export_info_mut(mg).terminal_binding = value; + } + + pub fn exports_info_owned(&self, mg: &ModuleGraph) -> bool { + self.as_export_info(mg).exports_info_owned + } + + pub fn exports_info(&self, mg: &ModuleGraph) -> Option { + self.as_export_info(mg).exports_info + } + + pub fn set_exports_info(&self, mg: &mut ModuleGraph, value: Option) { + self.as_export_info_mut(mg).exports_info = value; + } + + pub fn as_export_info<'a>(&self, mg: &'a ModuleGraph) -> &'a ExportInfoData { + mg.get_export_info_by_id(self) + } + + pub fn as_export_info_mut<'a>(&self, mg: &'a mut ModuleGraph) -> &'a mut ExportInfoData { + mg.get_export_info_mut_by_id(self) } pub fn get_provided_info(&self, mg: &ModuleGraph) -> &'static str { - let export_info = self.get_export_info(mg); + let export_info = self.as_export_info(mg); match export_info.provided { Some(ExportInfoProvided::False) => "not provided", Some(ExportInfoProvided::Null) => "maybe provided (runtime-defined)", @@ -868,7 +891,7 @@ impl ExportInfoId { } pub fn get_used_info(&self, mg: &ModuleGraph) -> Cow { - let export_info = self.get_export_info(mg); + let export_info = self.as_export_info(mg); if let Some(global_used) = export_info.global_used { return match global_used { UsageState::Unused => "unused".into(), @@ -889,13 +912,17 @@ impl ExportInfoId { .iter() .map(|(used, runtimes)| match used { UsageState::NoInfo => format!("no usage info in {}", runtimes.iter().join(", ")), - UsageState::Unknown => format!("maybe used in {} (runtime-defined)", runtimes.iter().join(", ")), + UsageState::Unknown => format!( + "maybe used in {} (runtime-defined)", + runtimes.iter().join(", ") + ), UsageState::Used => format!("used in {}", runtimes.iter().join(", ")), UsageState::OnlyPropertiesUsed => { format!("only properties used in {}", runtimes.iter().join(", ")) } UsageState::Unused => { - unreachable!("https://github.com/webpack/webpack/blob/1f99ad6367f2b8a6ef17cce0e058f7a67fb7db18/lib/ExportsInfo.js#L1470-L1481") + // https://github.com/webpack/webpack/blob/1f99ad6367f2b8a6ef17cce0e058f7a67fb7db18/lib/ExportsInfo.js#L1470-L1481 + unreachable!() } }) .collect(); @@ -911,32 +938,95 @@ impl ExportInfoId { "no usage info".into() } } - pub fn get_export_info<'a>(&self, mg: &'a ModuleGraph) -> &'a ExportInfo { - mg.get_export_info_by_id(self) - } - pub fn get_export_info_mut<'a>(&self, mg: &'a mut ModuleGraph) -> &'a mut ExportInfo { - mg.get_export_info_mut_by_id(self) + pub fn get_used(&self, mg: &ModuleGraph, runtime: Option<&RuntimeSpec>) -> UsageState { + let info = self.as_export_info(mg); + if !info.has_use_in_runtime_info { + return UsageState::NoInfo; + } + if let Some(global_used) = info.global_used { + return global_used; + } + if let Some(used_in_runtime) = info.used_in_runtime.as_ref() { + let mut max = UsageState::Unused; + if let Some(runtime) = runtime { + for item in runtime.iter() { + let Some(usage) = used_in_runtime.get(item.as_ref()) else { + continue; + }; + match usage { + UsageState::Used => return UsageState::Used, + _ => { + max = std::cmp::max(max, *usage); + } + } + } + } else { + for usage in used_in_runtime.values() { + match usage { + UsageState::Used => return UsageState::Used, + _ => { + max = std::cmp::max(max, *usage); + } + } + } + } + max + } else { + UsageState::Unused + } } - // facade of `ExportInfo.get_used` - pub fn get_used(&self, mg: &ModuleGraph, runtime: Option<&RuntimeSpec>) -> UsageState { - self.get_export_info(mg).get_used(runtime) + /// Webpack returns `false | string`, we use `Option` to avoid declare a redundant enum + /// type + pub fn get_used_name( + &self, + mg: &ModuleGraph, + fallback_name: Option<&Atom>, + runtime: Option<&RuntimeSpec>, + ) -> Option { + let info = self.as_export_info(mg); + if info.has_use_in_runtime_info { + if let Some(usage) = info.global_used { + if matches!(usage, UsageState::Unused) { + return None; + } + } else if let Some(used_in_runtime) = info.used_in_runtime.as_ref() { + if let Some(runtime) = runtime { + if runtime + .iter() + .all(|item| !used_in_runtime.contains_key(item.as_ref())) + { + return None; + } + } + } else { + return None; + } + } + if let Some(used_name) = info.used_name.as_ref() { + return Some(used_name.clone()); + } + if let Some(name) = info.name.as_ref() { + Some(name.clone()) + } else { + fallback_name.cloned() + } } - pub fn create_nested_exports_info(&self, mg: &mut ModuleGraph) -> ExportsInfoId { - let export_info = self.get_export_info(mg); + pub fn create_nested_exports_info(&self, mg: &mut ModuleGraph) -> ExportsInfo { + let export_info = self.as_export_info(mg); if export_info.exports_info_owned { return export_info .exports_info .expect("should have exports_info when exports_info is true"); } - let export_info_mut = self.get_export_info_mut(mg); + let export_info_mut = self.as_export_info_mut(mg); export_info_mut.exports_info_owned = true; - let other_exports_info = ExportInfo::new(None, None); - let side_effects_only_info = ExportInfo::new(Some("*side effects only*".into()), None); - let new_exports_info = ExportsInfo::new(other_exports_info.id, side_effects_only_info.id); + let other_exports_info = ExportInfoData::new(None, None); + let side_effects_only_info = ExportInfoData::new(Some("*side effects only*".into()), None); + let new_exports_info = ExportsInfoData::new(other_exports_info.id, side_effects_only_info.id); let new_exports_info_id = new_exports_info.id; let old_exports_info = export_info_mut.exports_info; @@ -954,6 +1044,11 @@ impl ExportInfoId { new_exports_info_id } + pub fn get_nested_exports_info(&self, mg: &ModuleGraph) -> Option { + let export_info = mg.get_export_info_by_id(self); + export_info.exports_info + } + fn set_has_use_info(&self, mg: &mut ModuleGraph) { let export_info = mg.get_export_info_mut_by_id(self); if !export_info.has_use_in_runtime_info { @@ -969,14 +1064,98 @@ impl ExportInfoId { } } - pub fn get_target( + pub fn is_reexport(&self, mg: &ModuleGraph) -> bool { + let info = self.as_export_info(mg); + !info.terminal_binding && info.target_is_set && !info.target.is_empty() + } + + pub fn get_terminal_binding(&self, mg: &ModuleGraph) -> Option { + let info = self.as_export_info(mg); + if info.terminal_binding { + return Some(TerminalBinding::ExportInfo(*self)); + } + let target = self.get_target(mg, None)?; + let exports_info = mg.get_exports_info(&target.module); + let Some(export) = target.export else { + return Some(TerminalBinding::ExportsInfo(exports_info)); + }; + exports_info + .get_read_only_export_info_recursive(mg, &export) + .map(TerminalBinding::ExportInfo) + } + + pub fn unset_target(&self, mg: &mut ModuleGraph, key: &DependencyId) -> bool { + let info = self.as_export_info_mut(mg); + if !info.target_is_set { + false + } else { + info.target.remove(&Some(*key)).is_some() + } + } + + pub fn set_target( + &self, + mg: &mut ModuleGraph, + key: Option, + connection_inner_dep_id: Option, + export_name: Option<&Nullable>>, + priority: Option, + ) -> bool { + let export_name = match export_name { + Some(Nullable::Null) => None, + Some(Nullable::Value(vec)) => Some(vec), + None => None, + }; + let normalized_priority = priority.unwrap_or(0); + let info = self.as_export_info_mut(mg); + if !info.target_is_set { + info.target.insert( + key, + ExportInfoTargetValue { + connection: connection_inner_dep_id, + export: export_name.cloned(), + priority: normalized_priority, + }, + ); + info.target_is_set = true; + return true; + } + let Some(old_target) = info.target.get_mut(&key) else { + if connection_inner_dep_id.is_none() { + return false; + } + + info.target.insert( + key, + ExportInfoTargetValue { + connection: connection_inner_dep_id, + export: export_name.cloned(), + priority: normalized_priority, + }, + ); + return true; + }; + if old_target.connection != connection_inner_dep_id + || old_target.priority != normalized_priority + || old_target.export.as_ref() != export_name + { + old_target.export = export_name.cloned(); + old_target.priority = normalized_priority; + old_target.connection = connection_inner_dep_id; + return true; + } + + false + } + + pub fn get_target( &self, mg: &ModuleGraph, resolve_filter: Option, ) -> Option { let filter = resolve_filter.unwrap_or(Arc::new(|_, _| true)); - let mut already_visited = HashSet::default(); + let mut already_visited = UkeySet::default(); match self._get_target(mg, filter, &mut already_visited) { Some(ResolvedExportInfoTargetWithCircular::Circular) => None, Some(ResolvedExportInfoTargetWithCircular::Target(target)) => Some(target), @@ -984,11 +1163,11 @@ impl ExportInfoId { } } - pub fn _get_target( + fn _get_target( &self, mg: &ModuleGraph, resolve_filter: ResolveFilterFnTy, - already_visited: &mut HashSet, + already_visited: &mut UkeySet, ) -> Option { let self_export_info = mg.get_export_info_by_id(self); if !self_export_info.target_is_set || self_export_info.target.is_empty() { @@ -999,14 +1178,13 @@ impl ExportInfoId { } already_visited.insert(*self); - let max_target = self_export_info.get_max_target(); + let max_target = self.get_max_target(mg); let mut values = max_target.values().map(|item| UnResolvedExportInfoTarget { connection: item.connection, export: item.export.clone(), }); - let target = - ExportInfo::resolve_target(values.next(), already_visited, resolve_filter.clone(), mg); + let target = resolve_target(values.next(), already_visited, resolve_filter.clone(), mg); match target { Some(ResolvedExportInfoTargetWithCircular::Circular) => { @@ -1016,7 +1194,7 @@ impl ExportInfoId { Some(ResolvedExportInfoTargetWithCircular::Target(target)) => { for val in values { let resolved_target = - ExportInfo::resolve_target(Some(val), already_visited, resolve_filter.clone(), mg); + resolve_target(Some(val), already_visited, resolve_filter.clone(), mg); match resolved_target { Some(ResolvedExportInfoTargetWithCircular::Circular) => { return Some(ResolvedExportInfoTargetWithCircular::Circular); @@ -1037,6 +1215,32 @@ impl ExportInfoId { } } + fn get_max_target<'a>( + &self, + mg: &'a ModuleGraph, + ) -> Cow<'a, HashMap, ExportInfoTargetValue>> { + let info = self.as_export_info(mg); + if info.target.len() <= 1 { + return Cow::Borrowed(&info.target); + } + let mut max_priority = u8::MIN; + let mut min_priority = u8::MAX; + for value in info.target.values() { + max_priority = max_priority.max(value.priority); + min_priority = min_priority.min(value.priority); + } + if max_priority == min_priority { + return Cow::Borrowed(&info.target); + } + let mut map = HashMap::default(); + for (k, v) in info.target.iter() { + if max_priority == v.priority { + map.insert(*k, v.clone()); + } + } + Cow::Owned(map) + } + fn set_used_without_info(&self, mg: &mut ModuleGraph, runtime: Option<&RuntimeSpec>) -> bool { let mut changed = false; let flag = self.set_used(mg, UsageState::NoInfo, runtime); @@ -1103,15 +1307,14 @@ impl ExportInfoId { resolve_filter: ResolveFilterFnTy, update_original_connection: UpdateOriginalFunctionTy, ) -> Option { - let target = self._get_target(mg, resolve_filter, &mut HashSet::default()); + let target = self._get_target(mg, resolve_filter, &mut UkeySet::default()); let target = match target { Some(ResolvedExportInfoTargetWithCircular::Circular) => return None, Some(ResolvedExportInfoTargetWithCircular::Target(target)) => target, None => return None, }; - let export_info_mut = self.get_export_info_mut(mg); - let max_target = export_info_mut.get_max_target(); + let max_target = self.get_max_target(mg); let original_target = max_target .values() .next() @@ -1121,12 +1324,13 @@ impl ExportInfoId { { return None; } + let export_info_mut = self.as_export_info_mut(mg); export_info_mut.target.clear(); let updated_connection = update_original_connection(&target, mg); // shadowning `export_info_mut` to reduce `&mut ModuleGraph` borrow life time, since // `update_original_connection` also needs `&mut ModuleGraph` - let export_info_mut = self.get_export_info_mut(mg); + let export_info_mut = self.as_export_info_mut(mg); export_info_mut.target.insert( None, ExportInfoTargetValue { @@ -1195,11 +1399,6 @@ impl ExportInfoId { false } - pub fn get_nested_exports_info(&self, mg: &ModuleGraph) -> Option { - let export_info = mg.get_export_info_by_id(self); - export_info.exports_info - } - fn set_used_in_unknown_way(&self, mg: &mut ModuleGraph, runtime: Option<&RuntimeSpec>) -> bool { let mut changed = false; @@ -1219,8 +1418,12 @@ impl ExportInfoId { changed } + pub fn has_used_name(&self, mg: &ModuleGraph) -> bool { + self.as_export_info(mg).used_name.is_some() + } + pub fn set_used_name(&self, mg: &mut ModuleGraph, name: Atom) { - mg.get_export_info_mut_by_id(self).set_used_name(name) + self.as_export_info_mut(mg).used_name = Some(name) } pub fn find_target( @@ -1228,21 +1431,21 @@ impl ExportInfoId { mg: &ModuleGraph, valid_target_module_filter: Arc bool>, ) -> FindTargetRetEnum { - self._find_target(mg, valid_target_module_filter, &mut HashSet::default()) + self._find_target(mg, valid_target_module_filter, &mut UkeySet::default()) } fn _find_target( &self, mg: &ModuleGraph, valid_target_module_filter: Arc bool>, - visited: &mut HashSet, + visited: &mut UkeySet, ) -> FindTargetRetEnum { - let export_info = self.get_export_info(mg); + let export_info = self.as_export_info(mg); if !export_info.target_is_set || export_info.target.is_empty() { return FindTargetRetEnum::Undefined; } - let max_target = export_info.get_max_target(); + let max_target = self.get_max_target(mg); let raw_target = max_target.values().next(); let Some(raw_target) = raw_target else { return FindTargetRetEnum::Undefined; @@ -1261,15 +1464,12 @@ impl ExportInfoId { } let exports_info = mg.get_exports_info(&target.module); let export_info = exports_info - .id - .get_read_only_export_info(&target.export.as_ref().expect("should have export")[0], mg); - if visited.contains(&export_info.id) { + .get_read_only_export_info(mg, &target.export.as_ref().expect("should have export")[0]); + if visited.contains(&export_info) { return FindTargetRetEnum::Undefined; } - visited.insert(export_info.id); - let new_target = export_info - .id - ._find_target(mg, valid_target_module_filter.clone(), visited); + visited.insert(export_info); + let new_target = export_info._find_target(mg, valid_target_module_filter.clone(), visited); let new_target = match new_target { FindTargetRetEnum::Undefined => return FindTargetRetEnum::False, FindTargetRetEnum::False => return FindTargetRetEnum::False, @@ -1301,59 +1501,53 @@ impl ExportInfoId { } } } -} -impl Default for ExportInfoId { - fn default() -> Self { - Self::new() - } -} - -impl std::ops::Deref for ExportInfoId { - type Target = u32; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} -impl From for ExportInfoId { - fn from(id: u32) -> Self { - Self(id) + pub fn can_mangle(&self, mg: &ModuleGraph) -> Option { + let info = self.as_export_info(mg); + match info.can_mangle_provide { + Some(true) => info.can_mangle_use, + Some(false) => Some(false), + None => { + if info.can_mangle_use == Some(false) { + Some(false) + } else { + None + } + } + } } } -#[derive(Debug, Clone, Default)] -pub struct ExportInfo { +#[derive(Debug, Clone)] +pub struct ExportInfoData { // the name could be `null` you could refer https://github.com/webpack/webpack/blob/ac7e531436b0d47cd88451f497cdfd0dad4153d/lib/ExportsInfo.js#L78 - pub name: Option, - module_identifier: Option, - pub usage_state: UsageState, + name: Option, + usage_state: UsageState, /// this is mangled name, https://github.com/webpack/webpack/blob/1f99ad6367f2b8a6ef17cce0e058f7a67fb7db18/lib/ExportsInfo.js#L1181-L1188 used_name: Option, target: HashMap, ExportInfoTargetValue>, /// This is rspack only variable, it is used to flag if the target has been initialized target_is_set: bool, - pub provided: Option, - pub can_mangle_provide: Option, - pub terminal_binding: bool, - pub id: ExportInfoId, - pub exports_info: Option, - pub exports_info_owned: bool, - pub has_use_in_runtime_info: bool, - pub can_mangle_use: Option, - pub global_used: Option, - pub used_in_runtime: Option, UsageState>>, + provided: Option, + can_mangle_provide: Option, + terminal_binding: bool, + id: ExportInfo, + exports_info: Option, + exports_info_owned: bool, + has_use_in_runtime_info: bool, + can_mangle_use: Option, + global_used: Option, + used_in_runtime: Option, UsageState>>, } -impl ExportsHash for ExportInfo { +impl ExportsHash for ExportInfoData { fn export_info_hash( &self, hasher: &mut dyn Hasher, module_graph: &ModuleGraph, - already_visited: &mut HashSet, + already_visited: &mut UkeySet, ) { self.name.dyn_hash(hasher); - self.module_identifier.dyn_hash(hasher); self.usage_state.dyn_hash(hasher); self.used_name.dyn_hash(hasher); for (name, value) in &self.target { @@ -1388,8 +1582,8 @@ pub enum ExportProvided { #[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)] pub enum TerminalBinding { - ExportInfo(ExportInfoId), - ExportsInfo(ExportsInfoId), + ExportInfo(ExportInfo), + ExportsInfo(ExportsInfo), } #[derive(Clone, Debug)] @@ -1431,8 +1625,8 @@ pub type ResolveFilterFnTy = Arc = Box bool>; -impl ExportInfo { - pub fn new(name: Option, init_from: Option<&ExportInfo>) -> Self { +impl ExportInfoData { + pub fn new(name: Option, init_from: Option<&ExportInfoData>) -> Self { let used_name = init_from.and_then(|init_from| init_from.used_name.clone()); let global_used = init_from.and_then(|init_from| init_from.global_used); let used_in_runtime = init_from.and_then(|init_from| init_from.used_in_runtime.clone()); @@ -1479,7 +1673,6 @@ impl ExportInfo { .unwrap_or_default(); Self { name, - module_identifier: None, usage_state: UsageState::Unknown, used_name, used_in_runtime, @@ -1488,7 +1681,7 @@ impl ExportInfo { can_mangle_provide, terminal_binding, target_is_set: init_from.map(|init| init.target_is_set).unwrap_or_default(), - id: ExportInfoId::new(), + id: ExportInfo::new(), exports_info: None, exports_info_owned: false, has_use_in_runtime_info, @@ -1497,282 +1690,80 @@ impl ExportInfo { } } - pub fn is_reexport(&self) -> bool { - !self.terminal_binding && self.target_is_set && !self.target.is_empty() + pub fn id(&self) -> ExportInfo { + self.id } +} - pub fn get_terminal_binding(&self, module_graph: &ModuleGraph) -> Option { - if self.terminal_binding { - return Some(TerminalBinding::ExportInfo(self.id)); - } - let target = self.id.get_target(module_graph, None)?; - let exports_info = module_graph.get_exports_info(&target.module); - let Some(export) = target.export else { - return Some(TerminalBinding::ExportsInfo(exports_info.id)); +fn resolve_target( + input_target: Option, + already_visited: &mut UkeySet, + resolve_filter: ResolveFilterFnTy, + mg: &ModuleGraph, +) -> Option { + if let Some(input_target) = input_target { + let mut target = ResolvedExportInfoTarget { + module: *input_target + .connection + .as_ref() + .and_then(|dep_id| mg.connection_by_dependency(dep_id)) + .expect("should have connection") + .module_identifier(), + export: input_target.export, + connection: input_target.connection.expect("should have connection"), }; - exports_info - .id - .get_read_only_export_info_recursive(&export, module_graph) - .map(|r| TerminalBinding::ExportInfo(r.id)) - } - - pub fn can_mangle(&self) -> Option { - match self.can_mangle_provide { - Some(true) => self.can_mangle_use, - Some(false) => Some(false), - None => { - if self.can_mangle_use == Some(false) { - Some(false) - } else { - None - } - } - } - } - - pub fn get_used(&self, runtime: Option<&RuntimeSpec>) -> UsageState { - if !self.has_use_in_runtime_info { - return UsageState::NoInfo; + if target.export.is_none() { + return Some(ResolvedExportInfoTargetWithCircular::Target(target)); } - if let Some(global_used) = self.global_used { - return global_used; - } - if let Some(used_in_runtime) = self.used_in_runtime.as_ref() { - let mut max = UsageState::Unused; - if let Some(runtime) = runtime { - for item in runtime.iter() { - let Some(usage) = used_in_runtime.get(item.as_ref()) else { - continue; - }; - match usage { - UsageState::Used => return UsageState::Used, - _ => { - max = std::cmp::max(max, *usage); - } - } - } - } else { - for usage in used_in_runtime.values() { - match usage { - UsageState::Used => return UsageState::Used, - _ => { - max = std::cmp::max(max, *usage); - } - } - } - } - max - } else { - UsageState::Unused + if !resolve_filter(&target, mg) { + return Some(ResolvedExportInfoTargetWithCircular::Target(target)); } - } - - /// Webpack returns `false | string`, we use `Option` to avoid declare a redundant enum - /// type - pub fn get_used_name( - &self, - fallback_name: Option<&Atom>, - runtime: Option<&RuntimeSpec>, - ) -> Option { - if self.has_use_in_runtime_info { - if let Some(usage) = self.global_used { - if matches!(usage, UsageState::Unused) { - return None; - } - } else if let Some(used_in_runtime) = self.used_in_runtime.as_ref() { - if let Some(runtime) = runtime { - if runtime - .iter() - .all(|item| !used_in_runtime.contains_key(item.as_ref())) - { - return None; - } - } + loop { + let name = if let Some(export) = target.export.as_ref().and_then(|exports| exports.first()) { + export } else { - return None; - } - } - if let Some(used_name) = self.used_name.as_ref() { - return Some(used_name.clone()); - } - if let Some(name) = self.name.as_ref() { - Some(name.clone()) - } else { - fallback_name.cloned() - } - } - - pub fn get_exports_info<'a>(&self, module_graph: &'a ModuleGraph) -> Option<&'a ExportsInfo> { - self - .module_identifier - .map(|id| module_graph.get_exports_info(&id)) - } - - pub fn unset_target(&mut self, key: &DependencyId) -> bool { - if !self.target_is_set { - false - } else { - self.target.remove(&Some(*key)).is_some() - } - } - - // NOTE: - // used when the module graph is immutable - // to make sure that the max target can be get - fn get_max_target(&self) -> Cow, ExportInfoTargetValue>> { - if self.target.len() <= 1 { - return Cow::Borrowed(&self.target); - } - let mut max_priority = u8::MIN; - let mut min_priority = u8::MAX; - for value in self.target.values() { - max_priority = max_priority.max(value.priority); - min_priority = min_priority.min(value.priority); - } - if max_priority == min_priority { - return Cow::Borrowed(&self.target); - } - let mut map = HashMap::default(); - for (k, v) in self.target.iter() { - if max_priority == v.priority { - map.insert(*k, v.clone()); - } - } - Cow::Owned(map) - } - - fn resolve_target( - input_target: Option, - already_visited: &mut HashSet, - resolve_filter: ResolveFilterFnTy, - mg: &ModuleGraph, - ) -> Option { - if let Some(input_target) = input_target { - let mut target = ResolvedExportInfoTarget { - module: *input_target - .connection - .as_ref() - .and_then(|dep_id| mg.connection_by_dependency(dep_id)) - .expect("should have connection") - .module_identifier(), - export: input_target.export, - connection: input_target.connection.expect("should have connection"), - }; - if target.export.is_none() { - return Some(ResolvedExportInfoTargetWithCircular::Target(target)); - } - if !resolve_filter(&target, mg) { return Some(ResolvedExportInfoTargetWithCircular::Target(target)); + }; + + let exports_info = mg.get_exports_info(&target.module); + let export_info = exports_info.get_read_only_export_info(mg, name); + if already_visited.contains(&export_info) { + return Some(ResolvedExportInfoTargetWithCircular::Circular); } - loop { - let name = if let Some(export) = target.export.as_ref().and_then(|exports| exports.first()) - { - export - } else { - return Some(ResolvedExportInfoTargetWithCircular::Target(target)); - }; + let new_target = export_info._get_target(mg, resolve_filter.clone(), already_visited); - let exports_info = mg.get_exports_info(&target.module); - let export_info_id = exports_info.id.get_read_only_export_info(name, mg).id; - if already_visited.contains(&export_info_id) { + match new_target { + Some(ResolvedExportInfoTargetWithCircular::Circular) => { return Some(ResolvedExportInfoTargetWithCircular::Circular); } - let new_target = export_info_id._get_target(mg, resolve_filter.clone(), already_visited); - - match new_target { - Some(ResolvedExportInfoTargetWithCircular::Circular) => { - return Some(ResolvedExportInfoTargetWithCircular::Circular); - } - None => return Some(ResolvedExportInfoTargetWithCircular::Target(target)), - Some(ResolvedExportInfoTargetWithCircular::Target(t)) => { - // SAFETY: if the target.exports is None, program will not reach here - let target_exports = target.export.as_ref().expect("should have exports"); - if target_exports.len() == 1 { - target = t; - if target.export.is_none() { - return Some(ResolvedExportInfoTargetWithCircular::Target(target)); - } + None => return Some(ResolvedExportInfoTargetWithCircular::Target(target)), + Some(ResolvedExportInfoTargetWithCircular::Target(t)) => { + // SAFETY: if the target.exports is None, program will not reach here + let target_exports = target.export.as_ref().expect("should have exports"); + if target_exports.len() == 1 { + target = t; + if target.export.is_none() { + return Some(ResolvedExportInfoTargetWithCircular::Target(target)); + } + } else { + target.module = t.module; + target.connection = t.connection; + target.export = if let Some(mut exports) = t.export { + exports.extend_from_slice(&target_exports[1..]); + Some(exports) } else { - target.module = t.module; - target.connection = t.connection; - target.export = if let Some(mut exports) = t.export { - exports.extend_from_slice(&target_exports[1..]); - Some(exports) - } else { - Some(target_exports[1..].to_vec()) - } + Some(target_exports[1..].to_vec()) } } } - if !resolve_filter(&target, mg) { - return Some(ResolvedExportInfoTargetWithCircular::Target(target)); - } - already_visited.insert(export_info_id); } - } else { - None - } - } - - pub fn set_target( - &mut self, - key: Option, - connection_inner_dep_id: Option, - export_name: Option<&Nullable>>, - priority: Option, - ) -> bool { - let export_name = match export_name { - Some(Nullable::Null) => None, - Some(Nullable::Value(vec)) => Some(vec), - None => None, - }; - let normalized_priority = priority.unwrap_or(0); - if !self.target_is_set { - self.target.insert( - key, - ExportInfoTargetValue { - connection: connection_inner_dep_id, - export: export_name.cloned(), - priority: normalized_priority, - }, - ); - self.target_is_set = true; - return true; - } - let Some(old_target) = self.target.get_mut(&key) else { - if connection_inner_dep_id.is_none() { - return false; + if !resolve_filter(&target, mg) { + return Some(ResolvedExportInfoTargetWithCircular::Target(target)); } - - self.target.insert( - key, - ExportInfoTargetValue { - connection: connection_inner_dep_id, - export: export_name.cloned(), - priority: normalized_priority, - }, - ); - return true; - }; - if old_target.connection != connection_inner_dep_id - || old_target.priority != normalized_priority - || old_target.export.as_ref() != export_name - { - old_target.export = export_name.cloned(); - old_target.priority = normalized_priority; - old_target.connection = connection_inner_dep_id; - return true; + already_visited.insert(export_info); } - - false - } - - pub fn has_used_name(&self) -> bool { - self.used_name.is_some() - } - - pub fn set_used_name(&mut self, name: Atom) { - self.used_name = Some(name); + } else { + None } } @@ -1815,7 +1806,7 @@ pub fn get_dependency_used_by_exports_condition( .expect("should have parent module"); let exports_info = module_graph.get_exports_info(module_identifier); for export_name in used_by_exports.iter() { - if exports_info.get_used(UsedName::Str(export_name.clone()), runtime, module_graph) + if exports_info.get_used(module_graph, UsedName::Str(export_name.clone()), runtime) != UsageState::Unused { return ConnectionState::Bool(true); @@ -1899,58 +1890,57 @@ pub fn process_export_info( runtime: Option<&RuntimeSpec>, referenced_export: &mut Vec>, prefix: Vec, - export_info: Option, + export_info: Option, default_points_to_self: bool, - already_visited: &mut HashSet, + already_visited: &mut UkeySet, ) { - if let Some(export_info_id) = export_info { - let export_info = module_graph.get_export_info_by_id(&export_info_id); - let used = export_info.get_used(runtime); + if let Some(export_info) = export_info { + let used = export_info.get_used(module_graph, runtime); if used == UsageState::Unused { return; } - if already_visited.contains(&export_info.id) { + if already_visited.contains(&export_info) { referenced_export.push(prefix); return; } - already_visited.insert(export_info.id); + already_visited.insert(export_info); // FIXME: more branch if used != UsageState::OnlyPropertiesUsed { - already_visited.remove(&export_info.id); + already_visited.remove(&export_info); referenced_export.push(prefix); return; } - if let Some(exports_info) = module_graph - .try_get_exports_info_by_id(&export_info.exports_info.expect("should have exports info")) - { - for export_info_id in exports_info.get_ordered_exports() { - let export_info = module_graph.get_export_info_by_id(export_info_id); + if let Some(exports_info) = module_graph.try_get_exports_info_by_id( + &export_info + .exports_info(module_graph) + .expect("should have exports info"), + ) { + for export_info in exports_info.id.ordered_exports(module_graph) { process_export_info( module_graph, runtime, referenced_export, if default_points_to_self && export_info - .name - .as_ref() + .name(module_graph) .map(|name| name == "default") .unwrap_or_default() { prefix.clone() } else { let mut value = prefix.clone(); - if let Some(name) = export_info.name.as_ref() { + if let Some(name) = export_info.name(module_graph) { value.push(name.clone()); } value }, - Some(export_info.id), + Some(export_info), false, already_visited, ); } } - already_visited.remove(&export_info.id); + already_visited.remove(&export_info); } else { referenced_export.push(prefix); } diff --git a/crates/rspack_core/src/module.rs b/crates/rspack_core/src/module.rs index dc01d5c12ed..98c9e0a5860 100644 --- a/crates/rspack_core/src/module.rs +++ b/crates/rspack_core/src/module.rs @@ -414,11 +414,10 @@ fn get_exports_type_impl( if let Some(export_info) = mg.get_read_only_export_info(&identifier, Atom::from("__esModule")) { - let export_info_id = export_info.id; - if matches!(export_info.provided, Some(ExportInfoProvided::False)) { + if matches!(export_info.provided(mg), Some(ExportInfoProvided::False)) { handle_default(default_object) } else { - let Some(target) = export_info_id.get_target(mg, None) else { + let Some(target) = export_info.get_target(mg, None) else { return ExportsType::Dynamic; }; if target diff --git a/crates/rspack_core/src/module_graph/mod.rs b/crates/rspack_core/src/module_graph/mod.rs index c020add6430..3f38358667d 100644 --- a/crates/rspack_core/src/module_graph/mod.rs +++ b/crates/rspack_core/src/module_graph/mod.rs @@ -1,6 +1,6 @@ use std::collections::hash_map::Entry; -use rspack_collections::IdentifierMap; +use rspack_collections::{IdentifierMap, UkeyMap}; use rspack_error::Result; use rspack_hash::RspackHashDigest; use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet}; @@ -14,11 +14,10 @@ mod module; pub use module::*; mod connection; pub use connection::*; -mod vec_map; use crate::{ BoxDependency, BoxModule, BuildDependency, DependencyCondition, DependencyId, ExportInfo, - ExportInfoId, ExportsInfo, ExportsInfoId, ModuleIdentifier, ModuleProfile, + ExportInfoData, ExportsInfo, ExportsInfoData, ModuleIdentifier, ModuleProfile, }; // TODO Here request can be used Atom @@ -127,9 +126,9 @@ pub struct ModuleGraphPartial { /// ``` dependency_id_to_parents: HashMap>, - // TODO move outof module_graph - exports_info_map: vec_map::VecMap, - export_info_map: vec_map::VecMap, + // Module's ExportsInfo is also a part of ModuleGraph + exports_info_map: UkeyMap, + export_info_map: UkeyMap, connection_to_condition: HashMap, dep_meta_map: HashMap, } @@ -870,14 +869,11 @@ impl<'a> ModuleGraph<'a> { } /// refer https://github.com/webpack/webpack/blob/ac7e531436b0d47cd88451f497cdfd0dad41535d/lib/ModuleGraph.js#L582-L585 - pub fn get_export_info( - &mut self, - module_id: ModuleIdentifier, - export_name: &Atom, - ) -> ExportInfoId { - let exports_info_id = self.get_exports_info(&module_id).id; - exports_info_id.get_export_info(export_name, self) + pub fn get_export_info(&mut self, module_id: ModuleIdentifier, export_name: &Atom) -> ExportInfo { + let exports_info = self.get_exports_info(&module_id); + exports_info.get_export_info(self, export_name) } + /// Uniquely identify a connection by a given dependency pub fn connection_by_dependency( &self, @@ -1102,85 +1098,81 @@ impl<'a> ModuleGraph<'a> { } } - pub fn get_exports_info(&self, module_identifier: &ModuleIdentifier) -> &ExportsInfo { + pub fn get_exports_info(&self, module_identifier: &ModuleIdentifier) -> ExportsInfo { let mgm = self .module_graph_module_by_identifier(module_identifier) .expect("should have mgm"); self - .loop_partials(|p| p.exports_info_map.try_get(*mgm.exports as usize)) + .loop_partials(|p| p.exports_info_map.get(&mgm.exports)) .expect("should have exports info") + .id() } - pub fn get_exports_info_by_id(&self, id: &ExportsInfoId) -> &ExportsInfo { + pub fn get_exports_info_by_id(&self, id: &ExportsInfo) -> &ExportsInfoData { self .try_get_exports_info_by_id(id) .expect("should have exports info") } - pub fn try_get_exports_info_by_id(&self, id: &ExportsInfoId) -> Option<&ExportsInfo> { - self.loop_partials(|p| p.exports_info_map.try_get((**id) as usize)) + pub fn try_get_exports_info_by_id(&self, id: &ExportsInfo) -> Option<&ExportsInfoData> { + self.loop_partials(|p| p.exports_info_map.get(id)) } - pub fn get_exports_info_mut_by_id(&mut self, id: &ExportsInfoId) -> &mut ExportsInfo { - let id = (**id) as usize; + pub fn get_exports_info_mut_by_id(&mut self, id: &ExportsInfo) -> &mut ExportsInfoData { self .loop_partials_mut( - |p| p.exports_info_map.try_get(id).is_some(), + |p| p.exports_info_map.contains_key(id), |p, search_result| { - p.exports_info_map.insert(id, search_result); + p.exports_info_map.insert(*id, search_result); }, - |p| p.exports_info_map.try_get(id).cloned(), - |p| p.exports_info_map.try_get_mut(id), + |p| p.exports_info_map.get(id).cloned(), + |p| p.exports_info_map.get_mut(id), ) .expect("should have exports info") } - pub fn set_exports_info(&mut self, id: ExportsInfoId, info: ExportsInfo) { + pub fn set_exports_info(&mut self, id: ExportsInfo, info: ExportsInfoData) { let Some(active_partial) = &mut self.active else { panic!("should have active partial"); }; - active_partial.exports_info_map.insert(*id as usize, info); + active_partial.exports_info_map.insert(id, info); } - pub fn try_get_export_info_by_id(&self, id: &ExportInfoId) -> Option<&ExportInfo> { - self.loop_partials(|p| p.export_info_map.try_get((**id) as usize)) + pub fn try_get_export_info_by_id(&self, id: &ExportInfo) -> Option<&ExportInfoData> { + self.loop_partials(|p| p.export_info_map.get(id)) } - pub fn get_export_info_by_id(&self, id: &ExportInfoId) -> &ExportInfo { + pub fn get_export_info_by_id(&self, id: &ExportInfo) -> &ExportInfoData { self .try_get_export_info_by_id(id) .expect("should have export info") } - pub fn get_export_info_mut_by_id(&mut self, id: &ExportInfoId) -> &mut ExportInfo { - let id = **id as usize; + pub fn get_export_info_mut_by_id(&mut self, id: &ExportInfo) -> &mut ExportInfoData { self .loop_partials_mut( - |p| p.export_info_map.try_get(id).is_some(), + |p| p.export_info_map.contains_key(id), |p, search_result| { - p.export_info_map.insert(id, search_result); + p.export_info_map.insert(*id, search_result); }, - |p| p.export_info_map.try_get(id).cloned(), - |p| p.export_info_map.try_get_mut(id), + |p| p.export_info_map.get(id).cloned(), + |p| p.export_info_map.get_mut(id), ) .expect("should have export info") } - pub fn set_export_info(&mut self, id: ExportInfoId, info: ExportInfo) { + pub fn set_export_info(&mut self, id: ExportInfo, info: ExportInfoData) { let Some(active_partial) = &mut self.active else { panic!("should have active partial"); }; - active_partial.export_info_map.insert(*id as usize, info); + active_partial.export_info_map.insert(id, info); } pub fn get_provided_exports(&self, module_id: ModuleIdentifier) -> ProvidedExports { let mgm = self .module_graph_module_by_identifier(&module_id) .expect("should have module graph module"); - mgm - .exports - .get_exports_info(self) - .get_provided_exports(self) + mgm.exports.get_provided_exports(self) } pub fn get_used_exports( @@ -1191,10 +1183,7 @@ impl<'a> ModuleGraph<'a> { let mgm = self .module_graph_module_by_identifier(id) .expect("should have module graph module"); - mgm - .exports - .get_exports_info(self) - .get_used_exports(self, runtime) + mgm.exports.get_used_exports(self, runtime) } pub fn get_optimization_bailout_mut(&mut self, id: &ModuleIdentifier) -> &mut Vec { @@ -1204,14 +1193,10 @@ impl<'a> ModuleGraph<'a> { mgm.optimization_bailout_mut() } - pub fn get_read_only_export_info( - &self, - id: &ModuleIdentifier, - name: Atom, - ) -> Option<&ExportInfo> { + pub fn get_read_only_export_info(&self, id: &ModuleIdentifier, name: Atom) -> Option { self .module_graph_module_by_identifier(id) - .map(|mgm| mgm.exports.get_read_only_export_info(&name, self)) + .map(|mgm| mgm.exports.get_read_only_export_info(self, &name)) } pub fn get_condition_state( @@ -1234,7 +1219,7 @@ impl<'a> ModuleGraph<'a> { // - Some(false): not provided pub fn is_export_provided(&self, id: &ModuleIdentifier, names: &[Atom]) -> Option { self.module_graph_module_by_identifier(id).and_then(|mgm| { - match mgm.exports.is_export_provided(names, self)? { + match mgm.exports.is_export_provided(self, names)? { ExportProvided::True => Some(true), ExportProvided::False => Some(false), ExportProvided::Null => None, diff --git a/crates/rspack_core/src/module_graph/module.rs b/crates/rspack_core/src/module_graph/module.rs index 6bd751728b8..24c6bad7f71 100644 --- a/crates/rspack_core/src/module_graph/module.rs +++ b/crates/rspack_core/src/module_graph/module.rs @@ -1,6 +1,6 @@ use rustc_hash::FxHashSet as HashSet; -use crate::ExportsInfoId; +use crate::ExportsInfo; use crate::{ module_graph::ConnectionId, ChunkGraph, DependencyId, ModuleIdentifier, ModuleIssuer, ModuleProfile, ModuleSyntax, @@ -22,7 +22,7 @@ pub struct ModuleGraphModule { pub(crate) pre_order_index: Option, pub post_order_index: Option, pub module_syntax: ModuleSyntax, - pub exports: ExportsInfoId, + pub exports: ExportsInfo, pub profile: Option>, pub is_async: bool, pub depth: Option, @@ -30,7 +30,7 @@ pub struct ModuleGraphModule { } impl ModuleGraphModule { - pub fn new(module_identifier: ModuleIdentifier, exports_info_id: ExportsInfoId) -> Self { + pub fn new(module_identifier: ModuleIdentifier, exports_info: ExportsInfo) -> Self { Self { outgoing_connections: Default::default(), incoming_connections: Default::default(), @@ -41,7 +41,7 @@ impl ModuleGraphModule { pre_order_index: None, post_order_index: None, module_syntax: ModuleSyntax::empty(), - exports: exports_info_id, + exports: exports_info, profile: None, is_async: false, depth: None, diff --git a/crates/rspack_core/src/module_graph/vec_map.rs b/crates/rspack_core/src/module_graph/vec_map.rs deleted file mode 100644 index 2860d08ba66..00000000000 --- a/crates/rspack_core/src/module_graph/vec_map.rs +++ /dev/null @@ -1,33 +0,0 @@ -use std::fmt::Debug; - -#[derive(Debug)] -pub struct VecMap { - inner: Vec>, -} - -impl Default for VecMap { - fn default() -> Self { - Self { inner: vec![] } - } -} - -impl VecMap { - pub fn insert(&mut self, index: usize, v: T) { - if index < self.inner.len() { - self.inner[index] = Some(v); - } else { - while self.inner.len() < index { - self.inner.push(None); - } - self.inner.push(Some(v)); - } - } - - pub fn try_get(&self, index: usize) -> Option<&T> { - self.inner.get(index).and_then(|item| item.as_ref()) - } - - pub fn try_get_mut(&mut self, index: usize) -> Option<&mut T> { - self.inner.get_mut(index).and_then(|item| item.as_mut()) - } -} diff --git a/crates/rspack_plugin_css/src/parser_and_generator/mod.rs b/crates/rspack_plugin_css/src/parser_and_generator/mod.rs index 48e50692c22..6d6779f3407 100644 --- a/crates/rspack_plugin_css/src/parser_and_generator/mod.rs +++ b/crates/rspack_plugin_css/src/parser_and_generator/mod.rs @@ -498,7 +498,7 @@ impl ParserAndGenerator for CssParserAndGenerator { let (ns_obj, left, right) = if self.es_module && mg .get_exports_info(&module.identifier()) - .other_exports_info + .other_exports_info(&mg) .get_used(&mg, generate_context.runtime) != UsageState::Unused { @@ -569,7 +569,7 @@ fn get_used_exports<'a>( let export_info = mg.get_read_only_export_info(&identifier, name.as_str().into()); if let Some(export_info) = export_info { - !matches!(export_info.get_used(runtime), UsageState::Unused) + !matches!(export_info.get_used(mg, runtime), UsageState::Unused) } else { true } @@ -596,7 +596,7 @@ fn get_unused_local_ident( let export_info = mg.get_read_only_export_info(&identifier, name.as_str().into()); if let Some(export_info) = export_info { - matches!(export_info.get_used(runtime), UsageState::Unused) + matches!(export_info.get_used(mg, runtime), UsageState::Unused) } else { false } diff --git a/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_export_require_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_export_require_dependency.rs index e9b85cde295..ec00e2cd667 100644 --- a/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_export_require_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_export_require_dependency.rs @@ -65,9 +65,7 @@ impl CommonJsExportRequireDependency { if !ids.is_empty() { imported_exports_info = imported_exports_info .expect("Should get exports info from imported module") - .id - .get_nested_exports_info(Some(ids), mg) - .map(|id| id.get_exports_info(mg)); + .get_nested_exports_info(mg, Some(ids)); } let mut exports_info = Some( @@ -80,21 +78,18 @@ impl CommonJsExportRequireDependency { if !self.names.is_empty() { exports_info = exports_info .expect("Should get exports info from imported module") - .id - .get_nested_exports_info(Some(self.names.clone()), mg) - .map(|id| id.get_exports_info(mg)); + .get_nested_exports_info(mg, Some(self.names.clone())); } let no_extra_exports = imported_exports_info.is_some_and(|imported_exports_info| { imported_exports_info - .other_exports_info - .get_export_info(mg) - .provided + .other_exports_info(mg) + .provided(mg) .is_some_and(|provided| matches!(provided, ExportInfoProvided::False)) }); let no_extra_imports = exports_info.is_some_and(|exports_info| { - exports_info.other_exports_info.get_used(mg, runtime) == UsageState::Unused + exports_info.other_exports_info(mg).get_used(mg, runtime) == UsageState::Unused }); if !no_extra_exports && !no_extra_imports { @@ -114,19 +109,18 @@ impl CommonJsExportRequireDependency { let Some(exports_info) = exports_info else { unreachable!(); }; - for export_info_id in exports_info.get_ordered_exports() { - let export_info = export_info_id.get_export_info(mg); - let name = &export_info.name; - if matches!(export_info.get_used(runtime), UsageState::Unused) { + for export_info in exports_info.ordered_exports(mg) { + let name = export_info.name(mg); + if matches!(export_info.get_used(mg, runtime), UsageState::Unused) { continue; } if let Some(name) = name { if name == "__esModule" && is_namespace_import { exports.insert(name.to_owned()); } else if let Some(imported_exports_info) = imported_exports_info { - let imported_export_info = imported_exports_info.id.get_read_only_export_info(name, mg); + let imported_export_info = imported_exports_info.get_read_only_export_info(mg, name); if matches!( - imported_export_info.provided, + imported_export_info.provided(mg), Some(ExportInfoProvided::False) ) { continue; @@ -141,19 +135,18 @@ impl CommonJsExportRequireDependency { let Some(imported_exports_info) = imported_exports_info else { unreachable!(); }; - for imported_export_info_id in imported_exports_info.get_ordered_exports() { - let imported_export_info = imported_export_info_id.get_export_info(mg); - let name = &imported_export_info.name; + for imported_export_info in imported_exports_info.ordered_exports(mg) { + let name = imported_export_info.name(mg); if let Some(name) = name { if matches!( - imported_export_info.provided, + imported_export_info.provided(mg), Some(ExportInfoProvided::False) ) { continue; } if let Some(exports_info) = exports_info { - let export_info = exports_info.id.get_read_only_export_info(name, mg); - if matches!(export_info.get_used(runtime), UsageState::Unused) { + let export_info = exports_info.get_read_only_export_info(mg, name); + if matches!(export_info.get_used(mg, runtime), UsageState::Unused) { continue; } exports.insert(name.to_owned()); @@ -288,8 +281,8 @@ impl Dependency for CommonJsExportRequireDependency { ); for name in &self.names { - let export_info = exports_info.id.get_read_only_export_info(name, mg); - let used = export_info.get_used(runtime); + let export_info = exports_info.get_read_only_export_info(mg, name); + let used = export_info.get_used(mg, runtime); if matches!(used, UsageState::Unused) { return vec![ExtendedReferencedExport::Array(vec![])]; } @@ -297,25 +290,24 @@ impl Dependency for CommonJsExportRequireDependency { return get_full_result(); } - match export_info.exports_info { - Some(v) => exports_info = v.get_exports_info(mg), + match export_info.exports_info(mg) { + Some(v) => exports_info = v, None => return get_full_result(), }; } if !matches!( - exports_info.other_exports_info.get_used(mg, runtime), + exports_info.other_exports_info(mg).get_used(mg, runtime), UsageState::Unused ) { return get_full_result(); } let mut referenced_exports = vec![]; - for export_info_id in exports_info.get_ordered_exports() { - let export_info = export_info_id.get_export_info(mg); + for export_info in exports_info.ordered_exports(mg) { let prefix = ids .iter() - .chain(if let Some(name) = &export_info.name { + .chain(if let Some(name) = export_info.name(mg) { vec![name] } else { vec![] @@ -327,7 +319,7 @@ impl Dependency for CommonJsExportRequireDependency { runtime, &mut referenced_exports, prefix, - Some(*export_info_id), + Some(export_info), false, &mut Default::default(), ) @@ -368,7 +360,7 @@ impl DependencyTemplate for CommonJsExportRequireDependency { let exports_argument = module.get_exports_argument(); let module_argument = module.get_module_argument(); - let used = mg.get_exports_info(&module.identifier()).id.get_used_name( + let used = mg.get_exports_info(&module.identifier()).get_used_name( mg, *runtime, UsedName::Vec(self.names.clone()), @@ -399,7 +391,6 @@ impl DependencyTemplate for CommonJsExportRequireDependency { let ids = self.get_ids(mg); if let Some(used_imported) = mg .get_exports_info(&imported_module.identifier()) - .id .get_used_name(mg, *runtime, UsedName::Vec(ids)) { require_expr = format!( diff --git a/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_exports_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_exports_dependency.rs index 10147f544af..d0ebd7d0dd6 100644 --- a/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_exports_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_exports_dependency.rs @@ -121,7 +121,6 @@ impl DependencyTemplate for CommonJsExportsDependency { let used = module_graph .get_exports_info(&module.identifier()) - .id .get_used_name(&module_graph, *runtime, UsedName::Vec(self.names.clone())); let exports_argument = module.get_exports_argument(); diff --git a/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_full_require_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_full_require_dependency.rs index 363f9e5e0dd..c78fc41e408 100644 --- a/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_full_require_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_full_require_dependency.rs @@ -126,7 +126,6 @@ impl DependencyTemplate for CommonJsFullRequireDependency { if let Some(imported_module) = module_graph.module_graph_module_by_dependency_id(&self.id) { let used = module_graph .get_exports_info(&imported_module.module_identifier) - .id .get_used_name(&module_graph, *runtime, UsedName::Vec(self.names.clone())); if let Some(used) = used { diff --git a/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_self_reference_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_self_reference_dependency.rs index 3ae56c978a6..75bcd58423e 100644 --- a/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_self_reference_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_self_reference_dependency.rs @@ -93,7 +93,6 @@ impl DependencyTemplate for CommonJsSelfReferenceDependency { let used = if self.names.is_empty() { module_graph .get_exports_info(&module.identifier()) - .id .get_used_name(&module_graph, *runtime, UsedName::Vec(self.names.clone())) .unwrap_or_else(|| UsedName::Vec(self.names.clone())) } else { diff --git a/crates/rspack_plugin_javascript/src/dependency/esm/harmony_compatibility_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/esm/harmony_compatibility_dependency.rs index 629f7d8cf2a..5b373cb8192 100644 --- a/crates/rspack_plugin_javascript/src/dependency/esm/harmony_compatibility_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/esm/harmony_compatibility_dependency.rs @@ -34,9 +34,8 @@ impl DependencyTemplate for HarmonyCompatibilityDependency { let exports_info = module_graph.get_exports_info(&module.identifier()); if !matches!( exports_info - .id - .get_read_only_export_info(&Atom::from("__esModule"), &module_graph) - .get_used(*runtime), + .get_read_only_export_info(&module_graph, &Atom::from("__esModule"),) + .get_used(&module_graph, *runtime), UsageState::Unused ) { runtime_requirements.insert(RuntimeGlobals::MAKE_NAMESPACE_OBJECT); diff --git a/crates/rspack_plugin_javascript/src/dependency/esm/harmony_export_expression_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/esm/harmony_export_expression_dependency.rs index 4e75cc9b4e5..0d8a4f9398e 100644 --- a/crates/rspack_plugin_javascript/src/dependency/esm/harmony_export_expression_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/esm/harmony_export_expression_dependency.rs @@ -125,7 +125,6 @@ impl DependencyTemplate for HarmonyExportExpressionDependency { let module_graph = compilation.get_module_graph(); module_graph .get_exports_info(module_identifier) - .id .get_used_name(&module_graph, *runtime, UsedName::Str(name.into())) } diff --git a/crates/rspack_plugin_javascript/src/dependency/esm/harmony_export_imported_specifier_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/esm/harmony_export_imported_specifier_dependency.rs index 63e5600e90f..37c0e753349 100644 --- a/crates/rspack_plugin_javascript/src/dependency/esm/harmony_export_imported_specifier_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/esm/harmony_export_imported_specifier_dependency.rs @@ -7,9 +7,9 @@ use rspack_core::{ create_exports_object_referenced, create_no_exports_referenced, filter_runtime, get_exports_type, process_export_info, property_access, property_name, string_of_used_name, AsContextDependency, ConditionalInitFragment, ConnectionState, Dependency, DependencyCategory, DependencyCondition, - DependencyId, DependencyTemplate, DependencyType, ErrorSpan, ExportInfoId, ExportInfoProvided, - ExportNameOrSpec, ExportPresenceMode, ExportSpec, ExportsInfoId, ExportsOfExportsSpec, - ExportsSpec, ExportsType, ExtendedReferencedExport, HarmonyExportInitFragment, ImportAttributes, + DependencyId, DependencyTemplate, DependencyType, ErrorSpan, ExportInfo, ExportInfoProvided, + ExportNameOrSpec, ExportPresenceMode, ExportSpec, ExportsInfo, ExportsOfExportsSpec, ExportsSpec, + ExportsType, ExtendedReferencedExport, HarmonyExportInitFragment, ImportAttributes, InitFragmentExt, InitFragmentKey, InitFragmentStage, JavascriptParserOptions, ModuleDependency, ModuleGraph, ModuleIdentifier, NormalInitFragment, RuntimeCondition, RuntimeGlobals, RuntimeSpec, Template, TemplateContext, TemplateReplaceSource, UsageState, UsedName, @@ -129,10 +129,10 @@ impl HarmonyExportImportedSpecifierDependency { let exports_info = module_graph.get_exports_info(parent_module); let is_name_unused = if let Some(ref name) = name { - exports_info.get_used(UsedName::Str(name.clone()), runtime, module_graph) + exports_info.get_used(module_graph, UsedName::Str(name.clone()), runtime) == UsageState::Unused } else { - !exports_info.is_used(runtime, module_graph) + !exports_info.is_used(module_graph, runtime) }; if is_name_unused { let mut mode = ExportMode::new(ExportModeType::Unused); @@ -154,13 +154,10 @@ impl HarmonyExportImportedSpecifierDependency { return export_mode; } ExportsType::DefaultOnly | ExportsType::DefaultWithNamed => { - let export_info_id = exports_info - .id - .get_read_only_export_info(name, module_graph) - .id; + let export_info = exports_info.get_read_only_export_info(module_graph, name); let mut export_mode = ExportMode::new(ExportModeType::ReexportNamedDefault); export_mode.name = Some(name.clone()); - export_mode.partial_namespace_export_info = Some(export_info_id); + export_mode.partial_namespace_export_info = Some(export_info); return export_mode; } _ => {} @@ -169,10 +166,7 @@ impl HarmonyExportImportedSpecifierDependency { // reexporting with a fixed name if let Some(name) = name { - let export_info = exports_info - .id - .get_read_only_export_info(&name, module_graph) - .id; + let export_info = exports_info.get_read_only_export_info(module_graph, &name); if !ids.is_empty() { // export { name as name } match imported_exports_type { @@ -228,7 +222,7 @@ impl HarmonyExportImportedSpecifierDependency { } = self.get_star_reexports( module_graph, runtime, - Some(exports_info.id), + Some(exports_info), imported_module_identifier, ); // dbg!( @@ -257,10 +251,7 @@ impl HarmonyExportImportedSpecifierDependency { .as_ref() .map(|c| c.contains(&export_name)) .unwrap_or_default(), - export_info: exports_info - .id - .get_read_only_export_info(&export_name, module_graph) - .id, + export_info: exports_info.get_read_only_export_info(module_graph, &export_name), }) .collect::>(); @@ -271,10 +262,7 @@ impl HarmonyExportImportedSpecifierDependency { ids: vec![export_name.clone()], hidden: true, checked: false, - export_info: exports_info - .id - .get_read_only_export_info(export_name, module_graph) - .id, + export_info: exports_info.get_read_only_export_info(module_graph, export_name), }); } } @@ -293,34 +281,28 @@ impl HarmonyExportImportedSpecifierDependency { &self, module_graph: &ModuleGraph, runtime: Option<&RuntimeSpec>, - exports_info_id: Option, + exports_info: Option, imported_module_identifier: &ModuleIdentifier, ) -> StarReexportsInfo { - let exports_info = exports_info_id - .unwrap_or_else(|| { - // https://github.com/webpack/webpack/blob/ac7e531436b0d47cd88451f497cdfd0dad41535d/lib/dependencies/HarmonyExportImportedSpecifierDependency.js#L425 - let parent_module = module_graph - .get_parent_module(&self.id) - .expect("should have parent module"); - module_graph.get_exports_info(parent_module).id - }) - .get_exports_info(module_graph); - + let exports_info = exports_info.unwrap_or_else(|| { + // https://github.com/webpack/webpack/blob/ac7e531436b0d47cd88451f497cdfd0dad41535d/lib/dependencies/HarmonyExportImportedSpecifierDependency.js#L425 + let parent_module = module_graph + .get_parent_module(&self.id) + .expect("should have parent module"); + module_graph.get_exports_info(parent_module) + }); let imported_exports_info = module_graph.get_exports_info(imported_module_identifier); - // dbg!(&imported_exports_info); - let other_export_info_of_imported = - module_graph.get_export_info_by_id(&imported_exports_info.other_exports_info); - - let other_exports_info_of_exports_info = - module_graph.get_export_info_by_id(&exports_info.other_exports_info); let no_extra_exports = matches!( - other_export_info_of_imported.provided, + imported_exports_info + .other_exports_info(module_graph) + .provided(module_graph), Some(ExportInfoProvided::False) ); - let no_extra_imports = matches!( - other_exports_info_of_exports_info.get_used(runtime), + exports_info + .other_exports_info(module_graph) + .get_used(module_graph, runtime), UsageState::Unused ); @@ -358,20 +340,21 @@ impl HarmonyExportImportedSpecifierDependency { }; if no_extra_imports { - for export_info_id in exports_info.get_ordered_exports() { - let export_info = module_graph.get_export_info_by_id(export_info_id); - let export_name = export_info.name.clone().unwrap_or_default(); + for export_info in exports_info.ordered_exports(module_graph) { + let export_name = export_info.name(module_graph).cloned().unwrap_or_default(); if ignored_exports.contains(&export_name) - || matches!(export_info.get_used(runtime), UsageState::Unused) + || matches!( + export_info.get_used(module_graph, runtime), + UsageState::Unused + ) { continue; } - let imported_export_info = imported_exports_info - .id - .get_read_only_export_info(&export_name, module_graph); + let imported_export_info = + imported_exports_info.get_read_only_export_info(module_graph, &export_name); if matches!( - imported_export_info.provided, + imported_export_info.provided(module_graph), Some(ExportInfoProvided::False) ) { continue; @@ -388,7 +371,7 @@ impl HarmonyExportImportedSpecifierDependency { exports.insert(export_name.clone()); if matches!( - imported_export_info.provided, + imported_export_info.provided(module_graph), Some(ExportInfoProvided::True) ) { continue; @@ -396,21 +379,25 @@ impl HarmonyExportImportedSpecifierDependency { checked.insert(export_name); } } else if no_extra_exports { - for imported_export_info_id in imported_exports_info.get_ordered_exports() { - let imported_export_info = module_graph.get_export_info_by_id(imported_export_info_id); - let imported_export_info_name = imported_export_info.name.clone().unwrap_or_default(); + for imported_export_info in imported_exports_info.ordered_exports(module_graph) { + let imported_export_info_name = imported_export_info + .name(module_graph) + .cloned() + .unwrap_or_default(); if ignored_exports.contains(&imported_export_info_name) || matches!( - imported_export_info.provided, + imported_export_info.provided(module_graph), Some(ExportInfoProvided::False) ) { continue; } - let export_info = exports_info - .id - .get_read_only_export_info(&imported_export_info_name, module_graph); - if matches!(export_info.get_used(runtime), UsageState::Unused) { + let export_info = + exports_info.get_read_only_export_info(module_graph, &imported_export_info_name); + if matches!( + export_info.get_used(module_graph, runtime), + UsageState::Unused + ) { continue; } if let Some(hidden) = hidden.as_mut() @@ -425,7 +412,7 @@ impl HarmonyExportImportedSpecifierDependency { exports.insert(imported_export_info_name.clone()); if matches!( - imported_export_info.provided, + imported_export_info.provided(module_graph), Some(ExportInfoProvided::True) ) { continue; @@ -520,7 +507,7 @@ impl HarmonyExportImportedSpecifierDependency { .boxed(), ), ExportModeType::ReexportDynamicDefault => { - let used_name = mg.get_exports_info(&module.identifier()).id.get_used_name( + let used_name = mg.get_exports_info(&module.identifier()).get_used_name( mg, None, UsedName::Str(mode.name.expect("should have name")), @@ -539,7 +526,7 @@ impl HarmonyExportImportedSpecifierDependency { fragments.push(init_fragment); } ExportModeType::ReexportNamedDefault => { - let used_name = mg.get_exports_info(&module.identifier()).id.get_used_name( + let used_name = mg.get_exports_info(&module.identifier()).get_used_name( mg, None, UsedName::Str(mode.name.expect("should have name")), @@ -557,7 +544,7 @@ impl HarmonyExportImportedSpecifierDependency { fragments.push(init_fragment); } ExportModeType::ReexportNamespaceObject => { - let used_name = mg.get_exports_info(&module.identifier()).id.get_used_name( + let used_name = mg.get_exports_info(&module.identifier()).get_used_name( mg, None, UsedName::Str(mode.name.expect("should have name")), @@ -577,7 +564,7 @@ impl HarmonyExportImportedSpecifierDependency { } ExportModeType::ReexportFakeNamespaceObject => { // TODO: reexport fake namespace object - let used_name = mg.get_exports_info(&module.identifier()).id.get_used_name( + let used_name = mg.get_exports_info(&module.identifier()).get_used_name( mg, None, UsedName::Str(mode.name.expect("should have name")), @@ -586,7 +573,7 @@ impl HarmonyExportImportedSpecifierDependency { self.get_reexport_fake_namespace_object_fragments(ctxt, key, &import_var, mode.fake_type); } ExportModeType::ReexportUndefined => { - let used_name = mg.get_exports_info(&module.identifier()).id.get_used_name( + let used_name = mg.get_exports_info(&module.identifier()).get_used_name( mg, None, UsedName::Str(mode.name.expect("should have name")), @@ -621,7 +608,7 @@ impl HarmonyExportImportedSpecifierDependency { continue; } - let used_name = mg.get_exports_info(&module_identifier).id.get_used_name( + let used_name = mg.get_exports_info(&module_identifier).get_used_name( mg, None, UsedName::Str(name.clone()), @@ -662,7 +649,6 @@ impl HarmonyExportImportedSpecifierDependency { } else { let used_name = mg.get_exports_info(imported_module) - .id .get_used_name(mg, None, UsedName::Vec(ids)); let init_fragment = self .get_reexport_fragment(ctxt, "reexport safe", key, &import_var, used_name.into()) @@ -925,12 +911,14 @@ impl HarmonyExportImportedSpecifierDependency { let exports_info = module_graph.get_exports_info(&imported_module.identifier()); let mut conflicts: IndexMap<&str, Vec<&Atom>, BuildHasherDefault> = IndexMap::default(); - for export_info_id in exports_info.get_ordered_exports() { - let export_info = export_info_id.get_export_info(module_graph); - if !matches!(export_info.provided, Some(ExportInfoProvided::True)) { + for export_info in exports_info.ordered_exports(module_graph) { + if !matches!( + export_info.provided(module_graph), + Some(ExportInfoProvided::True) + ) { continue; } - let Some(name) = &export_info.name else { + let Some(name) = export_info.name(module_graph) else { continue; }; if name == "default" { @@ -1430,7 +1418,7 @@ pub struct NormalReexportItem { pub ids: Vec, pub hidden: bool, pub checked: bool, - pub export_info: ExportInfoId, + pub export_info: ExportInfo, } #[derive(Debug)] @@ -1440,7 +1428,7 @@ pub struct ExportMode { pub items: Option>, pub name: Option, pub fake_type: u8, - pub partial_namespace_export_info: Option, + pub partial_namespace_export_info: Option, pub ignored: Option>, pub hidden: Option>, } @@ -1482,12 +1470,15 @@ fn determine_export_assignments<'a>( for dependency in dependencies.iter().chain(additional_dependency.iter()) { if let Some(module_identifier) = module_graph.module_identifier_by_dependency_id(dependency) { let exports_info = module_graph.get_exports_info(module_identifier); - for export_info_id in exports_info.exports.values() { - let export_info = module_graph.get_export_info_by_id(export_info_id); + for export_info in exports_info.ordered_exports(module_graph) { // SAFETY: This is safe because a real export can't export empty string - let export_info_name = export_info.name.as_ref().expect("export name is empty"); - if matches!(export_info.provided, Some(ExportInfoProvided::True)) - && export_info_name != "default" + let export_info_name = export_info + .name(module_graph) + .expect("export name is empty"); + if matches!( + export_info.provided(module_graph), + Some(ExportInfoProvided::True) + ) && export_info_name != "default" && !names.contains(export_info_name) { names.insert(export_info_name); diff --git a/crates/rspack_plugin_javascript/src/dependency/esm/harmony_export_specifier_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/esm/harmony_export_specifier_dependency.rs index 62c82b1b16c..3ff3a947b81 100644 --- a/crates/rspack_plugin_javascript/src/dependency/esm/harmony_export_specifier_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/esm/harmony_export_specifier_dependency.rs @@ -85,9 +85,9 @@ impl DependencyTemplate for HarmonyExportSpecifierDependency { .expect("should have module graph module"); let used_name = { - let exports_info_id = module_graph.get_exports_info(&module.identifier()).id; + let exports_info = module_graph.get_exports_info(&module.identifier()); let used_name = - exports_info_id.get_used_name(&module_graph, *runtime, UsedName::Str(self.name.clone())); + exports_info.get_used_name(&module_graph, *runtime, UsedName::Str(self.name.clone())); used_name.map(|item| match item { UsedName::Str(name) => name, UsedName::Vec(vec) => { diff --git a/crates/rspack_plugin_javascript/src/dependency/esm/harmony_import_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/esm/harmony_import_dependency.rs index 5550495a4ad..02a9bf0b1d2 100644 --- a/crates/rspack_plugin_javascript/src/dependency/esm/harmony_import_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/esm/harmony_import_dependency.rs @@ -272,21 +272,18 @@ pub fn harmony_import_dependency_get_linking_error( ) { let mut pos = 0; - let mut maybe_exports_info = Some( - module_graph - .get_exports_info(&imported_module_identifier) - .id, - ); + let mut maybe_exports_info = Some(module_graph.get_exports_info(&imported_module_identifier)); while pos < ids.len() && let Some(exports_info) = maybe_exports_info { let id = &ids[pos]; pos += 1; - let export_info = exports_info.get_read_only_export_info(id, module_graph); - if matches!(export_info.provided, Some(ExportInfoProvided::False)) { - let provided_exports = exports_info - .get_exports_info(module_graph) - .get_provided_exports(module_graph); + let export_info = exports_info.get_read_only_export_info(module_graph, id); + if matches!( + export_info.provided(module_graph), + Some(ExportInfoProvided::False) + ) { + let provided_exports = exports_info.get_provided_exports(module_graph); let more_info = if let ProvidedExports::Vec(exports) = &provided_exports { if exports.is_empty() { " (module has no exports)".to_string() @@ -316,7 +313,7 @@ pub fn harmony_import_dependency_get_linking_error( ); return Some(create_error(msg)); } - maybe_exports_info = export_info.id.get_nested_exports_info(module_graph); + maybe_exports_info = export_info.get_nested_exports_info(module_graph); } let msg = format!( "export {} {} was not found in '{}'", diff --git a/crates/rspack_plugin_javascript/src/dependency/esm/provide_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/esm/provide_dependency.rs index d2663361d81..d47d0cefead 100644 --- a/crates/rspack_plugin_javascript/src/dependency/esm/provide_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/esm/provide_dependency.rs @@ -95,9 +95,7 @@ impl DependencyTemplate for ProvideDependency { }; let exports_info = module_graph.get_exports_info(con.module_identifier()); let used_name = - exports_info - .id - .get_used_name(&module_graph, *runtime, UsedName::Vec(self.ids.clone())); + exports_info.get_used_name(&module_graph, *runtime, UsedName::Vec(self.ids.clone())); init_fragments.push(Box::new(NormalInitFragment::new( format!( "/* provided dependency */ var {} = {}{};\n", diff --git a/crates/rspack_plugin_javascript/src/dependency/export_info_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/export_info_dependency.rs index 1e8645c028e..f9a952e74b7 100644 --- a/crates/rspack_plugin_javascript/src/dependency/export_info_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/export_info_dependency.rs @@ -77,27 +77,25 @@ impl ExportInfoDependency { match prop.to_string().as_str() { "canMangle" => { - let can_mangle = if let Some(export_info) = exports_info - .id - .get_read_only_export_info_recursive(export_name, &module_graph) + let can_mangle = if let Some(export_info) = + exports_info.get_read_only_export_info_recursive(&module_graph, export_name) { - export_info.can_mangle() + export_info.can_mangle(&module_graph) } else { exports_info - .other_exports_info - .get_export_info(&module_graph) - .can_mangle() + .other_exports_info(&module_graph) + .can_mangle(&module_graph) }; can_mangle.map(|v| v.to_string()) } "used" => { let used = - exports_info.get_used(UsedName::Vec(export_name.clone()), *runtime, &module_graph); + exports_info.get_used(&module_graph, UsedName::Vec(export_name.clone()), *runtime); Some((!matches!(used, UsageState::Unused)).to_string()) } "useInfo" => { let used_state = - exports_info.get_used(UsedName::Vec(export_name.clone()), *runtime, &module_graph); + exports_info.get_used(&module_graph, UsedName::Vec(export_name.clone()), *runtime); Some( (match used_state { UsageState::Used => "true", @@ -110,8 +108,7 @@ impl ExportInfoDependency { ) } "provideInfo" => exports_info - .id - .is_export_provided(export_name, &module_graph) + .is_export_provided(&module_graph, export_name) .map(|provided| { (match provided { ExportProvided::True => "true", diff --git a/crates/rspack_plugin_javascript/src/dependency/pure_expression_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/pure_expression_dependency.rs index dd1e622e9e8..f0aa760101e 100644 --- a/crates/rspack_plugin_javascript/src/dependency/pure_expression_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/pure_expression_dependency.rs @@ -59,7 +59,7 @@ impl DependencyTemplate for PureExpressionDependency { let runtime = ctx.runtime; let runtime_condition = filter_runtime(runtime, |cur_runtime| { set.iter().any(|id| { - exports_info.get_used(UsedName::Str(id.clone()), cur_runtime, &module_graph) + exports_info.get_used(&module_graph, UsedName::Str(id.clone()), cur_runtime) != UsageState::Unused }) }); diff --git a/crates/rspack_plugin_javascript/src/plugin/flag_dependency_exports_plugin.rs b/crates/rspack_plugin_javascript/src/plugin/flag_dependency_exports_plugin.rs index 0d03ca64e9b..271ce41afe8 100644 --- a/crates/rspack_plugin_javascript/src/plugin/flag_dependency_exports_plugin.rs +++ b/crates/rspack_plugin_javascript/src/plugin/flag_dependency_exports_plugin.rs @@ -5,7 +5,7 @@ use itertools::Itertools; use rspack_collections::{IdentifierMap, IdentifierSet}; use rspack_core::{ ApplyContext, BuildMetaExportsType, Compilation, CompilationFinishModules, CompilerOptions, - DependenciesBlock, DependencyId, ExportInfoProvided, ExportNameOrSpec, ExportsInfoId, + DependenciesBlock, DependencyId, ExportInfoProvided, ExportNameOrSpec, ExportsInfo, ExportsOfExportsSpec, ExportsSpec, ModuleGraph, ModuleGraphConnection, ModuleIdentifier, Plugin, PluginContext, }; @@ -41,7 +41,7 @@ impl<'a> FlagDependencyExportsProxy<'a> { .mg .module_graph_module_by_identifier(&module_id) .expect("mgm should exist"); - let exports_id = mgm.exports; + let exports_info = mgm.exports; let module = self .mg @@ -53,12 +53,13 @@ impl<'a> FlagDependencyExportsProxy<'a> { true }; if is_module_without_exports { - let exports_info = self.mg.get_exports_info_by_id(&exports_id); - let other_exports_info_id = exports_info.other_exports_info; - let other_exports_info = self.mg.get_export_info_by_id(&other_exports_info_id); - if !matches!(other_exports_info.provided, Some(ExportInfoProvided::Null)) { - exports_id.set_has_provide_info(self.mg); - exports_id.set_unknown_exports_provided(self.mg, false, None, None, None, None); + let other_exports_info = exports_info.other_exports_info(self.mg); + if !matches!( + other_exports_info.provided(self.mg), + Some(ExportInfoProvided::Null) + ) { + exports_info.set_has_provide_info(self.mg); + exports_info.set_unknown_exports_provided(self.mg, false, None, None, None, None); continue; } } @@ -69,12 +70,12 @@ impl<'a> FlagDependencyExportsProxy<'a> { .map(|item| item.hash.is_some()) .unwrap_or_default() { - exports_id.set_has_provide_info(self.mg); + exports_info.set_has_provide_info(self.mg); q.enqueue(module_id); continue; } - exports_id.set_has_provide_info(self.mg); + exports_info.set_has_provide_info(self.mg); q.enqueue(module_id); // TODO: mem cache } @@ -85,9 +86,9 @@ impl<'a> FlagDependencyExportsProxy<'a> { let mut exports_specs_from_dependencies: IndexMap = IndexMap::default(); self.process_dependencies_block(&module_id, &mut exports_specs_from_dependencies); - let exports_info_id = self.mg.get_exports_info(&module_id).id; + let exports_info = self.mg.get_exports_info(&module_id); for (dep_id, exports_spec) in exports_specs_from_dependencies.into_iter() { - self.process_exports_spec(dep_id, exports_spec, exports_info_id); + self.process_exports_spec(dep_id, exports_spec, exports_info); } if self.changed { self.notify_dependencies(&mut q); @@ -163,7 +164,7 @@ impl<'a> FlagDependencyExportsProxy<'a> { &mut self, dep_id: DependencyId, export_desc: ExportsSpec, - exports_info_id: ExportsInfoId, + exports_info: ExportsInfo, ) { let exports = &export_desc.exports; // dbg!(&exports); @@ -174,14 +175,13 @@ impl<'a> FlagDependencyExportsProxy<'a> { let export_dependencies = &export_desc.dependencies; if let Some(hide_export) = export_desc.hide_export { for name in hide_export.iter() { - let from_exports_info_id = exports_info_id.get_export_info(name, self.mg); - let export_info = self.mg.get_export_info_mut_by_id(&from_exports_info_id); - export_info.unset_target(&dep_id); + let from_exports_info = exports_info.get_export_info(self.mg, name); + from_exports_info.unset_target(self.mg, &dep_id); } } match exports { ExportsOfExportsSpec::True => { - if exports_info_id.set_unknown_exports_provided( + if exports_info.set_unknown_exports_provided( self.mg, global_can_mangle.unwrap_or_default(), export_desc.exclude_exports, @@ -195,7 +195,7 @@ impl<'a> FlagDependencyExportsProxy<'a> { ExportsOfExportsSpec::Null => {} ExportsOfExportsSpec::Array(ele) => { self.merge_exports( - exports_info_id, + exports_info, ele, DefaultExportInfo { can_mangle: *global_can_mangle, @@ -224,7 +224,7 @@ impl<'a> FlagDependencyExportsProxy<'a> { pub fn merge_exports( &mut self, - exports_info: ExportsInfoId, + exports_info: ExportsInfo, exports: &Vec, global_export_info: DefaultExportInfo, dep_id: DependencyId, @@ -265,31 +265,29 @@ impl<'a> FlagDependencyExportsProxy<'a> { spec.hidden.unwrap_or(false), ), }; - let export_info_id = exports_info.get_export_info(&name, self.mg); - - let export_info_mut = export_info_id.get_export_info_mut(self.mg); - if let Some(ref mut provided) = export_info_mut.provided + let export_info = exports_info.get_export_info(self.mg, &name); + if let Some(provided) = export_info.provided(self.mg) && matches!( provided, ExportInfoProvided::False | ExportInfoProvided::Null ) { - *provided = ExportInfoProvided::True; + export_info.set_provided(self.mg, Some(ExportInfoProvided::True)); self.changed = true; } - if Some(false) != export_info_mut.can_mangle_provide && can_mangle == Some(false) { - export_info_mut.can_mangle_provide = Some(false); + if Some(false) != export_info.can_mangle_provide(self.mg) && can_mangle == Some(false) { + export_info.set_can_mangle_provide(self.mg, Some(false)); self.changed = true; } - if terminal_binding && !export_info_mut.terminal_binding { - export_info_mut.terminal_binding = true; + if terminal_binding && !export_info.terminal_binding(self.mg) { + export_info.set_terminal_binding(self.mg, true); self.changed = true; } if let Some(exports) = exports { - let nested_exports_info = export_info_id.create_nested_exports_info(self.mg); + let nested_exports_info = export_info.create_nested_exports_info(self.mg); self.merge_exports( nested_exports_info, exports, @@ -300,10 +298,9 @@ impl<'a> FlagDependencyExportsProxy<'a> { // shadowing the previous `export_info_mut` to reduce the mut borrow life time, // because `create_nested_exports_info` needs `&mut ModuleGraph` - let export_info_mut = export_info_id.get_export_info_mut(self.mg); if let Some(from) = from { let changed = if hidden { - export_info_mut.unset_target(&dep_id) + export_info.unset_target(self.mg, &dep_id) } else { let fallback = rspack_core::Nullable::Value(vec![name.clone()]); let export_name = if let Some(from) = from_export { @@ -311,7 +308,8 @@ impl<'a> FlagDependencyExportsProxy<'a> { } else { Some(&fallback) }; - export_info_mut.set_target( + export_info.set_target( + self.mg, Some(dep_id), Some(from.dependency_id), export_name, @@ -322,14 +320,13 @@ impl<'a> FlagDependencyExportsProxy<'a> { } // Recalculate target exportsInfo - let target = export_info_id.get_target(self.mg, None); + let target = export_info.get_target(self.mg, None); - let mut target_exports_info: Option = None; + let mut target_exports_info: Option = None; if let Some(target) = target { let target_module_exports_info = self.mg.get_exports_info(&target.module); - target_exports_info = target_module_exports_info - .id - .get_nested_exports_info(target.export, self.mg); + target_exports_info = + target_module_exports_info.get_nested_exports_info(self.mg, target.export); match self.dependencies.entry(target.module) { Entry::Occupied(mut occ) => { occ.get_mut().insert(self.current_module_id); @@ -340,17 +337,16 @@ impl<'a> FlagDependencyExportsProxy<'a> { } } - let export_info = self.mg.get_export_info_mut_by_id(&export_info_id); - if export_info.exports_info_owned { + if export_info.exports_info_owned(self.mg) { let changed = export_info - .exports_info + .exports_info(self.mg) .expect("should have exports_info when exports_info_owned is true") .set_redirect_name_to(self.mg, target_exports_info); if changed { self.changed = true; } - } else if export_info.exports_info != target_exports_info { - export_info.exports_info = target_exports_info; + } else if export_info.exports_info(self.mg) != target_exports_info { + export_info.set_exports_info(self.mg, target_exports_info); self.changed = true; } } diff --git a/crates/rspack_plugin_javascript/src/plugin/flag_dependency_usage_plugin.rs b/crates/rspack_plugin_javascript/src/plugin/flag_dependency_usage_plugin.rs index 464fa827659..6716830d6f3 100644 --- a/crates/rspack_plugin_javascript/src/plugin/flag_dependency_usage_plugin.rs +++ b/crates/rspack_plugin_javascript/src/plugin/flag_dependency_usage_plugin.rs @@ -1,11 +1,11 @@ use std::collections::hash_map::Entry; use std::collections::VecDeque; -use rspack_collections::IdentifierMap; +use rspack_collections::{IdentifierMap, UkeyMap}; use rspack_core::{ get_entry_runtime, is_exports_object_referenced, is_no_exports_referenced, merge_runtime, AsyncDependenciesBlockIdentifier, BuildMetaExportsType, Compilation, - CompilationOptimizeDependencies, ConnectionState, DependenciesBlock, DependencyId, ExportsInfoId, + CompilationOptimizeDependencies, ConnectionState, DependenciesBlock, DependencyId, ExportsInfo, ExtendedReferencedExport, GroupOptions, ModuleIdentifier, Plugin, ReferencedExport, RuntimeSpec, UsageState, }; @@ -25,7 +25,7 @@ enum ModuleOrAsyncDependenciesBlock { pub struct FlagDependencyUsagePluginProxy<'a> { global: bool, compilation: &'a mut Compilation, - exports_info_module_map: HashMap, + exports_info_module_map: UkeyMap, } #[allow(unused)] @@ -34,7 +34,7 @@ impl<'a> FlagDependencyUsagePluginProxy<'a> { Self { global, compilation, - exports_info_module_map: HashMap::default(), + exports_info_module_map: UkeyMap::default(), } } @@ -48,8 +48,8 @@ impl<'a> FlagDependencyUsagePluginProxy<'a> { let mut q = Queue::new(); let mg = &mut module_graph; // debug_exports_info!(mg); - for exports_info_id in self.exports_info_module_map.keys() { - exports_info_id.set_has_use_info(mg); + for exports_info in self.exports_info_module_map.keys() { + exports_info.set_has_use_info(mg); } // SAFETY: we can make sure that entries will not be used other place at the same time, // this take is aiming to avoid use self ref and mut ref at the same time; @@ -304,14 +304,14 @@ impl<'a> FlagDependencyUsagePluginProxy<'a> { let module = module_graph .module_by_identifier(&module_id) .expect("should have module"); - let mgm_exports_info_id = mgm.exports; + let mgm_exports_info = mgm.exports; if !used_exports.is_empty() { let need_insert = match module.build_meta() { Some(build_meta) => matches!(build_meta.exports_type, BuildMetaExportsType::Unset), None => true, }; if need_insert { - let flag = mgm_exports_info_id.set_used_without_info(&mut module_graph, runtime.as_ref()); + let flag = mgm_exports_info.set_used_without_info(&mut module_graph, runtime.as_ref()); if flag { queue.enqueue((module_id, None)); } @@ -324,70 +324,61 @@ impl<'a> FlagDependencyUsagePluginProxy<'a> { ExtendedReferencedExport::Export(export) => (export.can_mangle, export.name), }; if used_exports.is_empty() { - let flag = - mgm_exports_info_id.set_used_in_unknown_way(&mut module_graph, runtime.as_ref()); + let flag = mgm_exports_info.set_used_in_unknown_way(&mut module_graph, runtime.as_ref()); if flag { queue.enqueue((module_id, runtime.clone())); } } else { - let mut current_exports_info_id = mgm_exports_info_id; - // dbg!(¤t_exports_info_id.get_exports_info(&self.compilation.get_module_graph())); + let mut current_exports_info = mgm_exports_info; let len = used_exports.len(); for (i, used_export) in used_exports.into_iter().enumerate() { - let export_info_id = - current_exports_info_id.get_export_info(&used_export, &mut module_graph); - // dbg!(&export_info_id.get_export_info(&self.compilation.get_module_graph())); - let export_info = module_graph.get_export_info_mut_by_id(&export_info_id); + let export_info = current_exports_info.get_export_info(&mut module_graph, &used_export); if !can_mangle { - export_info.can_mangle_use = Some(false); + export_info.set_can_mangle_use(&mut module_graph, Some(false)); } let last_one = i == len - 1; if !last_one { - let nested_info = export_info_id.get_nested_exports_info(&module_graph); + let nested_info = export_info.get_nested_exports_info(&module_graph); // dbg!(&nested_info); if let Some(nested_info) = nested_info { - let changed_flag = export_info_id.set_used_conditionally( + let changed_flag = export_info.set_used_conditionally( &mut module_graph, Box::new(|used| used == &UsageState::Unused), UsageState::OnlyPropertiesUsed, runtime.as_ref(), ); if changed_flag { - let current_module = if current_exports_info_id == mgm_exports_info_id { + let current_module = if current_exports_info == mgm_exports_info { Some(module_id) } else { self .exports_info_module_map - .get(¤t_exports_info_id) + .get(¤t_exports_info) .cloned() }; if let Some(current_module) = current_module { queue.enqueue((current_module, runtime.clone())); } } - current_exports_info_id = nested_info; + current_exports_info = nested_info; continue; } } - let changed_flag = export_info_id.set_used_conditionally( + let changed_flag = export_info.set_used_conditionally( &mut module_graph, Box::new(|v| v != &UsageState::Used), UsageState::Used, runtime.as_ref(), ); - // dbg!( - // &export_info_id.get_export_info(&self.compilation.get_module_graph()), - // changed_flag - // ); if changed_flag { - let current_module = if current_exports_info_id == mgm_exports_info_id { + let current_module = if current_exports_info == mgm_exports_info { Some(module_id) } else { self .exports_info_module_map - .get(¤t_exports_info_id) + .get(¤t_exports_info) .cloned() }; if let Some(current_module) = current_module { @@ -408,7 +399,7 @@ impl<'a> FlagDependencyUsagePluginProxy<'a> { return; } let changed_flag = - mgm_exports_info_id.set_used_for_side_effects_only(&mut module_graph, runtime.as_ref()); + mgm_exports_info.set_used_for_side_effects_only(&mut module_graph, runtime.as_ref()); if changed_flag { queue.enqueue((module_id, runtime)); } diff --git a/crates/rspack_plugin_javascript/src/plugin/mangle_exports_plugin.rs b/crates/rspack_plugin_javascript/src/plugin/mangle_exports_plugin.rs index 7b7c580543b..5872321bd1d 100644 --- a/crates/rspack_plugin_javascript/src/plugin/mangle_exports_plugin.rs +++ b/crates/rspack_plugin_javascript/src/plugin/mangle_exports_plugin.rs @@ -2,31 +2,25 @@ use once_cell::sync::Lazy; use regex::Regex; use rspack_core::{ ApplyContext, BuildMetaExportsType, Compilation, CompilationOptimizeCodeGeneration, - CompilerOptions, ExportInfo, ExportInfoProvided, ExportsInfoId, ModuleGraph, Plugin, - PluginContext, UsageState, + CompilerOptions, ExportInfoProvided, ExportsInfo, ModuleGraph, Plugin, PluginContext, UsageState, }; use rspack_error::Result; use rspack_hook::{plugin, plugin_hook}; use rspack_ids::id_helpers::assign_deterministic_ids; +use rspack_util::atom::Atom; use rustc_hash::{FxHashMap, FxHashSet}; use crate::utils::mangle_exports::{ number_to_identifier, NUMBER_OF_IDENTIFIER_CONTINUATION_CHARS, NUMBER_OF_IDENTIFIER_START_CHARS, }; -fn can_mangle(exports_info_id: ExportsInfoId, mg: &ModuleGraph) -> bool { - let exports_info = exports_info_id.get_exports_info(mg); - if exports_info - .other_exports_info - .get_export_info(mg) - .get_used(None) - != UsageState::Unused - { +fn can_mangle(exports_info: ExportsInfo, mg: &ModuleGraph) -> bool { + if exports_info.other_exports_info(mg).get_used(mg, None) != UsageState::Unused { return false; } let mut has_something_to_mangle = false; - for export_info_id in exports_info.exports.values() { - if export_info_id.get_export_info(mg).can_mangle() == Some(true) { + for export_info in exports_info.exports(mg) { + if export_info.can_mangle(mg) == Some(true) { has_something_to_mangle = true; } } @@ -64,8 +58,8 @@ fn optimize_code_generation(&self, compilation: &mut Compilation) -> Result<()> .as_ref() .map(|meta| matches!(meta.exports_type, BuildMetaExportsType::Namespace)) .unwrap_or_default(); - let exports_info_id = mgm.exports; - mangle_exports_info(&mut mg, self.deterministic, exports_info_id, is_namespace); + let exports_info = mgm.exports; + mangle_exports_info(&mut mg, self.deterministic, exports_info, is_namespace); } Ok(()) } @@ -86,8 +80,8 @@ impl Plugin for MangleExportsPlugin { } /// Compare function for sorting exports by name. -fn compare_strings_numeric(a: &ExportInfo, b: &ExportInfo) -> std::cmp::Ordering { - a.name.cmp(&b.name) +fn compare_strings_numeric(a: Option<&Atom>, b: Option<&Atom>) -> std::cmp::Ordering { + a.cmp(&b) } static MANGLE_NAME_NORMAL_REG: Lazy = Lazy::new(|| Regex::new("^[a-zA-Z0-9_$]").expect("should construct regex")); @@ -98,10 +92,10 @@ static MANGLE_NAME_DETERMINISTIC_REG: Lazy = fn mangle_exports_info( mg: &mut ModuleGraph, deterministic: bool, - exports_info_id: ExportsInfoId, + exports_info: ExportsInfo, is_namespace: bool, ) { - if !can_mangle(exports_info_id, mg) { + if !can_mangle(exports_info, mg) { return; } @@ -110,57 +104,45 @@ fn mangle_exports_info( let mut avoid_mangle_non_provided = !is_namespace; if !avoid_mangle_non_provided && deterministic { - let exports_info = exports_info_id.get_exports_info(mg); - for export_info_id in exports_info.exports.values() { - let export_info = export_info_id.get_export_info(mg); - if !matches!(export_info.provided, Some(ExportInfoProvided::False)) { + for export_info in exports_info.owned_exports(mg) { + if !matches!(export_info.provided(mg), Some(ExportInfoProvided::False)) { avoid_mangle_non_provided = true; break; } } } - let export_info_id_list = exports_info_id - .get_exports_info(mg) - .exports - .values() - .cloned() - .collect::>(); - for export_info_id in export_info_id_list { - let export_info = export_info_id.get_export_info(mg); - if !export_info.has_used_name() { + for export_info in exports_info.owned_exports(mg).collect::>() { + if !export_info.has_used_name(mg) { let name = export_info - .name - .as_ref() + .name(mg) .expect("the name of export_info inserted in exports_info can not be `None`") .clone(); - let can_not_mangle = export_info.can_mangle() != Some(true) + let can_not_mangle = export_info.can_mangle(mg) != Some(true) || (name.len() == 1 && MANGLE_NAME_NORMAL_REG.is_match(name.as_str())) || (deterministic && name.len() == 2 && MANGLE_NAME_DETERMINISTIC_REG.is_match(name.as_str())) || (avoid_mangle_non_provided - && !matches!(export_info.provided, Some(ExportInfoProvided::True))); + && !matches!(export_info.provided(mg), Some(ExportInfoProvided::True))); - let export_info_mut = export_info_id.get_export_info_mut(mg); if can_not_mangle { - export_info_mut.set_used_name(name.clone()); + export_info.set_used_name(mg, name.clone()); used_names.insert(name.to_string()); } else { - mangleable_exports.push(export_info_mut.id); + mangleable_exports.push(export_info); }; } // we need to re get export info to avoid extending immutable borrow lifetime - let export_info = export_info_id.get_export_info(mg); - if export_info.exports_info_owned { - let used = export_info.get_used(None); + if export_info.exports_info_owned(mg) { + let used = export_info.get_used(mg, None); if used == UsageState::OnlyPropertiesUsed || used == UsageState::Unused { mangle_exports_info( mg, deterministic, export_info - .exports_info + .exports_info(mg) .expect("should have exports info id"), false, ); @@ -170,22 +152,11 @@ fn mangle_exports_info( if deterministic { let used_names_len = used_names.len(); - let mut export_info_id_used_name = FxHashMap::default(); + let mut export_info_used_name = FxHashMap::default(); assign_deterministic_ids( mangleable_exports, - |e| { - let export_info = e.get_export_info(mg); - export_info - .name - .as_ref() - .expect("should have name") - .to_string() - }, - |a, b| { - let a_info = a.get_export_info(mg); - let b_info = b.get_export_info(mg); - compare_strings_numeric(a_info, b_info) - }, + |e| e.name(mg).expect("should have name").to_string(), + |a, b| compare_strings_numeric(a.name(mg), b.name(mg)), |e, id| { let name = number_to_identifier(id as u32); let size = used_names.len(); @@ -193,7 +164,7 @@ fn mangle_exports_info( if size == used_names.len() { false } else { - export_info_id_used_name.insert(e, name); + export_info_used_name.insert(e, name); true } }, @@ -205,10 +176,8 @@ fn mangle_exports_info( used_names_len, 0, ); - for (export_info_id, name) in export_info_id_used_name { - export_info_id - .get_export_info_mut(mg) - .set_used_name(name.into()); + for (export_info, name) in export_info_used_name { + export_info.set_used_name(mg, name.into()); } } else { let mut used_exports = Vec::new(); @@ -222,20 +191,12 @@ fn mangle_exports_info( } } - used_exports.sort_by(|a, b| { - let export_info_a = a.get_export_info(mg); - let export_info_b = b.get_export_info(mg); - compare_strings_numeric(export_info_a, export_info_b) - }); - unused_exports.sort_by(|a, b| { - let export_info_a = a.get_export_info(mg); - let export_info_b = b.get_export_info(mg); - compare_strings_numeric(export_info_a, export_info_b) - }); + used_exports.sort_by(|a, b| compare_strings_numeric(a.name(mg), b.name(mg))); + unused_exports.sort_by(|a, b| compare_strings_numeric(a.name(mg), b.name(mg))); let mut i = 0; for list in [used_exports, unused_exports] { - for export_info_id in list { + for export_info in list { let mut name; loop { name = number_to_identifier(i); @@ -244,7 +205,7 @@ fn mangle_exports_info( } i += 1; } - export_info_id.set_used_name(mg, name.into()); + export_info.set_used_name(mg, name.into()); } } } diff --git a/crates/rspack_plugin_javascript/src/plugin/module_concatenation_plugin.rs b/crates/rspack_plugin_javascript/src/plugin/module_concatenation_plugin.rs index e98d78384a5..343cd3cbdfc 100644 --- a/crates/rspack_plugin_javascript/src/plugin/module_concatenation_plugin.rs +++ b/crates/rspack_plugin_javascript/src/plugin/module_concatenation_plugin.rs @@ -766,26 +766,24 @@ impl ModuleConcatenationPlugin { } let exports_info = module_graph.get_exports_info(&module_id); - let relevant_exports = exports_info.get_relevant_exports(None, &module_graph); + let relevant_exports = exports_info.get_relevant_exports(&module_graph, None); let unknown_exports = relevant_exports .iter() - .filter(|id| { - let export_info = id.get_export_info(&module_graph).clone(); - export_info.is_reexport() && export_info.id.get_target(&module_graph, None).is_none() + .filter(|export_info| { + export_info.is_reexport(&module_graph) + && export_info.get_target(&module_graph, None).is_none() }) .copied() .collect::>(); if !unknown_exports.is_empty() { let cur_bailout_reason = unknown_exports .into_iter() - .map(|id| { - let export_info = id.get_export_info(&module_graph); + .map(|export_info| { let name = export_info - .name - .as_ref() + .name(&module_graph) .map(|name| name.to_string()) .unwrap_or("other exports".to_string()); - format!("{} : {}", name, export_info.id.get_used_info(&module_graph)) + format!("{} : {}", name, export_info.get_used_info(&module_graph)) }) .collect::>() .join(", "); @@ -804,9 +802,11 @@ impl ModuleConcatenationPlugin { } let unknown_provided_exports = relevant_exports .iter() - .filter(|id| { - let export_info = id.get_export_info(&module_graph); - !matches!(export_info.provided, Some(ExportInfoProvided::True)) + .filter(|export_info| { + !matches!( + export_info.provided(&module_graph), + Some(ExportInfoProvided::True) + ) }) .copied() .collect::>(); @@ -814,18 +814,16 @@ impl ModuleConcatenationPlugin { if !unknown_provided_exports.is_empty() { let cur_bailout_reason = unknown_provided_exports .into_iter() - .map(|id| { - let export_info = id.get_export_info(&module_graph); + .map(|export_info| { let name = export_info - .name - .as_ref() + .name(&module_graph) .map(|name| name.to_string()) .unwrap_or("other exports".to_string()); format!( "{} : {} and {}", name, - export_info.id.get_provided_info(&module_graph), - export_info.id.get_used_info(&module_graph) + export_info.get_provided_info(&module_graph), + export_info.get_used_info(&module_graph), ) }) .collect::>() @@ -910,9 +908,9 @@ impl ModuleConcatenationPlugin { chunk_runtime = merge_runtime(&chunk_runtime, &r); } let module_graph = compilation.get_module_graph(); - let exports_info_id = module_graph.get_exports_info(current_root).id; + let exports_info = module_graph.get_exports_info(current_root); let filtered_runtime = filter_runtime(Some(&chunk_runtime), |r| { - exports_info_id.is_module_used(&module_graph, r) + exports_info.is_module_used(&module_graph, r) }); let active_runtime = match filtered_runtime { RuntimeCondition::Boolean(true) => Some(chunk_runtime.clone()), diff --git a/crates/rspack_plugin_javascript/src/plugin/side_effects_flag_plugin.rs b/crates/rspack_plugin_javascript/src/plugin/side_effects_flag_plugin.rs index de050a378f7..56564d81afa 100644 --- a/crates/rspack_plugin_javascript/src/plugin/side_effects_flag_plugin.rs +++ b/crates/rspack_plugin_javascript/src/plugin/side_effects_flag_plugin.rs @@ -669,7 +669,7 @@ fn optimize_dependencies(&self, compilation: &mut Compilation) -> Result Result() .and_then(|dep| dep.name.clone()) { - let export_info_id = module_graph.get_export_info( + let export_info = module_graph.get_export_info( con .original_module_identifier .expect("should have original_module_identifier"), &name, ); - export_info_id.move_target( + export_info.move_target( &mut module_graph, Arc::new(|target: &ResolvedExportInfoTarget, mg: &ModuleGraph| { mg.module_by_identifier(&target.module) @@ -737,9 +737,9 @@ fn optimize_dependencies(&self, compilation: &mut Compilation) -> Result { create_object_for_exports_info(json_data.clone(), exports_info, *runtime, &module_graph) @@ -228,11 +227,11 @@ impl Plugin for JsonPlugin { fn create_object_for_exports_info( data: JsonValue, - exports_info: &ExportsInfo, + exports_info: ExportsInfo, runtime: Option<&RuntimeSpec>, mg: &ModuleGraph, ) -> JsonValue { - if exports_info.other_exports_info.get_used(mg, runtime) != UsageState::Unused { + if exports_info.other_exports_info(mg).get_used(mg, runtime) != UsageState::Unused { return data; } @@ -245,15 +244,14 @@ fn create_object_for_exports_info( JsonValue::Object(mut obj) => { let mut used_pair = vec![]; for (key, value) in obj.iter_mut() { - let export_info = exports_info.id.get_read_only_export_info(&key.into(), mg); - let used = export_info.get_used(runtime); + let export_info = exports_info.get_read_only_export_info(mg, &key.into()); + let used = export_info.get_used(mg, runtime); if used == UsageState::Unused { continue; } let new_value = if used == UsageState::OnlyPropertiesUsed - && let Some(exports_info_id) = export_info.exports_info + && let Some(exports_info) = export_info.exports_info(mg) { - let exports_info = mg.get_exports_info_by_id(&exports_info_id); // avoid clone let temp = std::mem::replace(value, JsonValue::Null); create_object_for_exports_info(temp, exports_info, runtime, mg) @@ -261,7 +259,7 @@ fn create_object_for_exports_info( std::mem::replace(value, JsonValue::Null) }; let used_name = export_info - .get_used_name(Some(&(key.into())), runtime) + .get_used_name(mg, Some(&(key.into())), runtime) .expect("should have used name"); used_pair.push((used_name, new_value)); } @@ -278,18 +276,15 @@ fn create_object_for_exports_info( .into_iter() .enumerate() .map(|(i, item)| { - let export_info = exports_info - .id - .get_read_only_export_info(&format!("{i}").into(), mg); - let used = export_info.get_used(runtime); + let export_info = exports_info.get_read_only_export_info(mg, &format!("{i}").into()); + let used = export_info.get_used(mg, runtime); if used == UsageState::Unused { return None; } max_used_index = max_used_index.max(i); if used == UsageState::OnlyPropertiesUsed - && let Some(exports_info_id) = export_info.exports_info + && let Some(exports_info) = export_info.exports_info(mg) { - let exports_info = mg.get_exports_info_by_id(&exports_info_id); Some(create_object_for_exports_info( item, exports_info, @@ -302,9 +297,8 @@ fn create_object_for_exports_info( }) .collect::>(); let arr_length_used = exports_info - .id - .get_read_only_export_info(&"length".into(), mg) - .get_used(runtime); + .get_read_only_export_info(mg, &"length".into()) + .get_used(mg, runtime); let array_length_when_used = match arr_length_used { UsageState::Unused => None, _ => Some(original_len), diff --git a/crates/rspack_plugin_library/src/assign_library_plugin.rs b/crates/rspack_plugin_library/src/assign_library_plugin.rs index a99bbf17ecc..a665eda17bf 100644 --- a/crates/rspack_plugin_library/src/assign_library_plugin.rs +++ b/crates/rspack_plugin_library/src/assign_library_plugin.rs @@ -411,12 +411,10 @@ async fn finish_modules(&self, compilation: &mut Compilation) -> Result<()> { Some(&runtime), ); } else { - let exports_info_id = compilation + let exports_info = compilation .get_module_graph() - .get_exports_info(&module_identifier) - .id; - exports_info_id - .set_used_in_unknown_way(&mut compilation.get_module_graph_mut(), Some(&runtime)); + .get_exports_info(&module_identifier); + exports_info.set_used_in_unknown_way(&mut compilation.get_module_graph_mut(), Some(&runtime)); } } Ok(()) diff --git a/crates/rspack_plugin_library/src/export_property_library_plugin.rs b/crates/rspack_plugin_library/src/export_property_library_plugin.rs index f5434a69a8a..9e93335947d 100644 --- a/crates/rspack_plugin_library/src/export_property_library_plugin.rs +++ b/crates/rspack_plugin_library/src/export_property_library_plugin.rs @@ -151,18 +151,15 @@ async fn finish_modules(&self, compilation: &mut Compilation) -> Result<()> { for (runtime, export, module_identifier) in runtime_info { let mut module_graph = compilation.get_module_graph_mut(); if let Some(export) = export { - let export_info_id = - module_graph.get_export_info(module_identifier, &(export.as_str()).into()); - export_info_id.set_used(&mut module_graph, UsageState::Used, Some(&runtime)); - export_info_id - .get_export_info_mut(&mut module_graph) - .can_mangle_use = Some(false); + let export_info = module_graph.get_export_info(module_identifier, &(export.as_str()).into()); + export_info.set_used(&mut module_graph, UsageState::Used, Some(&runtime)); + export_info.set_can_mangle_use(&mut module_graph, Some(false)); } else { - let exports_info_id = module_graph.get_exports_info(&module_identifier).id; + let exports_info = module_graph.get_exports_info(&module_identifier); if self.ns_object_used { - exports_info_id.set_used_in_unknown_way(&mut module_graph, Some(&runtime)); + exports_info.set_used_in_unknown_way(&mut module_graph, Some(&runtime)); } else { - exports_info_id.set_all_known_exports_used(&mut module_graph, Some(&runtime)); + exports_info.set_all_known_exports_used(&mut module_graph, Some(&runtime)); } } } diff --git a/crates/rspack_plugin_library/src/modern_module_library_plugin.rs b/crates/rspack_plugin_library/src/modern_module_library_plugin.rs index 3c89a12fc4c..e5cf70e1772 100644 --- a/crates/rspack_plugin_library/src/modern_module_library_plugin.rs +++ b/crates/rspack_plugin_library/src/modern_module_library_plugin.rs @@ -129,11 +129,10 @@ fn render_startup( .map(|d: &CodeGenerationExportsFinalNames| d.inner()) { let exports_info = module_graph.get_exports_info(module_id); - for id in exports_info.get_ordered_exports() { - let info = id.get_export_info(&module_graph); - let info_name = info.name.as_ref().expect("should have name"); - let used_name = info - .get_used_name(info.name.as_ref(), Some(&chunk.runtime)) + for export_info in exports_info.ordered_exports(&module_graph) { + let info_name = export_info.name(&module_graph).expect("should have name"); + let used_name = export_info + .get_used_name(&module_graph, Some(info_name), Some(&chunk.runtime)) .expect("name can't be empty"); let final_name = exports_final_names.get(used_name.as_str()); diff --git a/crates/rspack_plugin_library/src/module_library_plugin.rs b/crates/rspack_plugin_library/src/module_library_plugin.rs index 2a987c34010..624786b410d 100644 --- a/crates/rspack_plugin_library/src/module_library_plugin.rs +++ b/crates/rspack_plugin_library/src/module_library_plugin.rs @@ -75,12 +75,11 @@ fn render_startup( )); } let exports_info = module_graph.get_exports_info(module); - for id in exports_info.get_ordered_exports() { - let info = id.get_export_info(&module_graph); + for export_info in exports_info.ordered_exports(&module_graph) { let chunk = compilation.chunk_by_ukey.expect_get(chunk_ukey); - let info_name = info.name.as_ref().expect("should have name"); - let used_name = info - .get_used_name(info.name.as_ref(), Some(&chunk.runtime)) + let info_name = export_info.name(&module_graph).expect("should have name"); + let used_name = export_info + .get_used_name(&module_graph, Some(info_name), Some(&chunk.runtime)) .expect("name can't be empty"); let var_name = format!("__webpack_exports__{}", to_identifier(info_name)); source.add(RawSource::from(format!( diff --git a/crates/rspack_plugin_merge_duplicate_chunks/src/lib.rs b/crates/rspack_plugin_merge_duplicate_chunks/src/lib.rs index 34a0901715d..17d867ee0ad 100644 --- a/crates/rspack_plugin_merge_duplicate_chunks/src/lib.rs +++ b/crates/rspack_plugin_merge_duplicate_chunks/src/lib.rs @@ -97,7 +97,7 @@ fn optimize_chunks(&self, compilation: &mut Compilation) -> Result> .get_chunk_modules(&chunk_ukey, &compilation.get_module_graph()) { let exports_info = module_graph.get_exports_info(&module.identifier()); - if !exports_info.is_equally_used(&chunk.runtime, &other_chunk.runtime, &module_graph) { + if !exports_info.is_equally_used(&module_graph, &chunk.runtime, &other_chunk.runtime) { continue 'outer; } } diff --git a/crates/rspack_plugin_wasm/src/parser_and_generator.rs b/crates/rspack_plugin_wasm/src/parser_and_generator.rs index ab0d50a877a..88e0d9749b8 100644 --- a/crates/rspack_plugin_wasm/src/parser_and_generator.rs +++ b/crates/rspack_plugin_wasm/src/parser_and_generator.rs @@ -186,7 +186,6 @@ impl ParserAndGenerator for AsyncWasmParserAndGenerator { let dep_name = serde_json::to_string(dep.name()).expect("should be ok."); let used_name = module_graph .get_exports_info(&mgm.module_identifier) - .id .get_used_name(module_graph, *runtime, UsedName::Str(dep.name().into())); let Some(UsedName::Str(used_name)) = used_name else { return;