diff --git a/Cargo.lock b/Cargo.lock index ae8f13a73f494..a1c2b49fa2f9a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2311,6 +2311,7 @@ dependencies = [ "oxc_compat 0.94.0", "oxc_data_structures 0.94.0", "oxc_ecmascript 0.94.0", + "oxc_index 4.1.0", "oxc_mangler 0.94.0", "oxc_parser 0.94.0", "oxc_regular_expression 0.94.0", diff --git a/crates/oxc_mangler/src/lib.rs b/crates/oxc_mangler/src/lib.rs index 3efb4f39eaf49..3381b58007d62 100644 --- a/crates/oxc_mangler/src/lib.rs +++ b/crates/oxc_mangler/src/lib.rs @@ -268,20 +268,25 @@ impl<'t> Mangler<'t> { pub fn build(self, program: &Program<'_>) -> ManglerReturn { let mut semantic = SemanticBuilder::new().with_scope_tree_child_ids(true).build(program).semantic; - let class_private_mappings = Self::collect_private_members_from_semantic(&semantic); - self.build_with_semantic(&mut semantic, program); + let class_private_mappings = self.build_with_semantic(&mut semantic, program); ManglerReturn { scoping: semantic.into_scoping(), class_private_mappings } } /// # Panics /// /// Panics if the child_ids does not exist in scope_tree. - pub fn build_with_semantic(self, semantic: &mut Semantic<'_>, program: &Program<'_>) { + pub fn build_with_semantic( + self, + semantic: &mut Semantic<'_>, + program: &Program<'_>, + ) -> IndexVec> { + let class_private_mappings = Self::collect_private_members_from_semantic(semantic); if self.options.debug { self.build_with_semantic_impl(semantic, program, debug_name); } else { self.build_with_semantic_impl(semantic, program, base54); } + class_private_mappings } fn build_with_semantic_impl InlineString>( diff --git a/crates/oxc_minifier/Cargo.toml b/crates/oxc_minifier/Cargo.toml index a2286e587e12a..356883fc9bb2b 100644 --- a/crates/oxc_minifier/Cargo.toml +++ b/crates/oxc_minifier/Cargo.toml @@ -28,6 +28,7 @@ oxc_codegen = { workspace = true } oxc_compat = { workspace = true } oxc_data_structures = { workspace = true, features = ["stack"] } oxc_ecmascript = { workspace = true } +oxc_index = { workspace = true } oxc_mangler = { workspace = true } oxc_parser = { workspace = true } oxc_regular_expression = { workspace = true } diff --git a/crates/oxc_minifier/src/lib.rs b/crates/oxc_minifier/src/lib.rs index 6c90e067c26bf..21dcfdd6e5624 100644 --- a/crates/oxc_minifier/src/lib.rs +++ b/crates/oxc_minifier/src/lib.rs @@ -57,8 +57,12 @@ mod tester; use oxc_allocator::Allocator; use oxc_ast::ast::Program; +use oxc_index::IndexVec; use oxc_mangler::Mangler; use oxc_semantic::{Scoping, SemanticBuilder}; +use oxc_span::CompactStr; +use oxc_syntax::class::ClassId; +use rustc_hash::FxHashMap; pub use oxc_mangler::{MangleOptions, MangleOptionsKeepNames}; @@ -79,6 +83,10 @@ impl Default for MinifierOptions { pub struct MinifierReturn { pub scoping: Option, + /// A vector where each element corresponds to a class in declaration order. + /// Each element is a mapping from original private member names to their mangled names. + pub class_private_mappings: Option>>, + /// Total number of iterations ran. Useful for debugging performance issues. pub iterations: u8, } @@ -127,15 +135,21 @@ impl<'a> Minifier { (stats, iterations) }) .unwrap_or_default(); - let scoping = self.options.mangle.map(|options| { - let mut semantic = SemanticBuilder::new() - .with_stats(stats) - .with_scope_tree_child_ids(true) - .build(program) - .semantic; - Mangler::default().with_options(options).build_with_semantic(&mut semantic, program); - semantic.into_scoping() - }); - MinifierReturn { scoping, iterations } + let (scoping, class_private_mappings) = self + .options + .mangle + .map(|options| { + let mut semantic = SemanticBuilder::new() + .with_stats(stats) + .with_scope_tree_child_ids(true) + .build(program) + .semantic; + let class_private_mappings = Mangler::default() + .with_options(options) + .build_with_semantic(&mut semantic, program); + (semantic.into_scoping(), class_private_mappings) + }) + .map_or((None, None), |(scoping, mappings)| (Some(scoping), Some(mappings))); + MinifierReturn { scoping, class_private_mappings, iterations } } } diff --git a/napi/playground/src/lib.rs b/napi/playground/src/lib.rs index 5a697ef5cea0b..2dfaa20e93130 100644 --- a/napi/playground/src/lib.rs +++ b/napi/playground/src/lib.rs @@ -19,7 +19,7 @@ use oxc::{ diagnostics::OxcDiagnostic, isolated_declarations::{IsolatedDeclarations, IsolatedDeclarationsOptions}, mangler::{MangleOptions, MangleOptionsKeepNames}, - minifier::{CompressOptions, Minifier, MinifierOptions}, + minifier::{CompressOptions, Minifier, MinifierOptions, MinifierReturn}, parser::{ParseOptions, Parser, ParserReturn}, semantic::{ ReferenceId, ScopeFlags, ScopeId, Scoping, SemanticBuilder, SymbolFlags, SymbolId, @@ -203,10 +203,10 @@ impl Oxc { } // Phase 7: Apply minification - let scoping = Self::apply_minification(&allocator, &mut program, &options); + let minifier_return = Self::apply_minification(&allocator, &mut program, &options); // Phase 8: Generate code - self.codegen(&path, &program, scoping, run_options, &codegen_options); + self.codegen(&path, &program, minifier_return, run_options, &codegen_options); // Phase 9: Finalize output self.finalize_output(&source_text, &mut program, &mut module_record, source_type); @@ -318,7 +318,7 @@ impl Oxc { allocator: &'a Allocator, program: &mut Program<'a>, options: &OxcOptions, - ) -> Option { + ) -> Option { if !options.run.compress && !options.run.mangle { return None; } @@ -336,7 +336,7 @@ impl Oxc { } else { None }; - Minifier::new(MinifierOptions { mangle, compress }).minify(allocator, program).scoping + Some(Minifier::new(MinifierOptions { mangle, compress }).minify(allocator, program)) } fn finalize_output<'a>( @@ -445,7 +445,7 @@ impl Oxc { &mut self, path: &Path, program: &Program<'_>, - scoping: Option, + minifier_return: Option, run_options: &OxcRunOptions, codegen_options: &OxcCodegenOptions, ) { @@ -464,8 +464,13 @@ impl Oxc { source_map_path: Some(path.to_path_buf()), ..CodegenOptions::default() }; - let codegen_result = - Codegen::new().with_scoping(scoping).with_options(options).build(program); + let (scoping, class_private_mappings) = + minifier_return.map(|m| (m.scoping, m.class_private_mappings)).unwrap_or_default(); + let codegen_result = Codegen::new() + .with_scoping(scoping) + .with_private_member_mappings(class_private_mappings) + .with_options(options) + .build(program); self.codegen_text = codegen_result.code; self.codegen_sourcemap_text = codegen_result.map.map(|map| map.to_json_string()); } diff --git a/tasks/track_memory_allocations/allocs_minifier.snap b/tasks/track_memory_allocations/allocs_minifier.snap index 1de07ec9bfa40..b076ed1d1f319 100644 --- a/tasks/track_memory_allocations/allocs_minifier.snap +++ b/tasks/track_memory_allocations/allocs_minifier.snap @@ -1,12 +1,12 @@ File | File size || Sys allocs | Sys reallocs || Arena allocs | Arena reallocs | Arena bytes ------------------------------------------------------------------------------------------------------------------------------------------- -checker.ts | 2.92 MB || 83500 | 14179 || 152592 | 28237 +checker.ts | 2.92 MB || 83503 | 14179 || 152592 | 28237 -cal.com.tsx | 1.06 MB || 40449 | 3033 || 37146 | 4583 +cal.com.tsx | 1.06 MB || 40452 | 3033 || 37146 | 4583 RadixUIAdoptionSection.jsx | 2.52 kB || 85 | 9 || 30 | 6 -pdf.mjs | 567.30 kB || 19808 | 2899 || 47442 | 7725 +pdf.mjs | 567.30 kB || 20494 | 2899 || 47442 | 7725 antd.js | 6.69 MB || 99524 | 13523 || 331573 | 69338