Skip to content

Commit

Permalink
perf(minifier): avoid repeated Atom creation in `InjectGlobalVariab…
Browse files Browse the repository at this point in the history
…les` (#4802)

Re-use `Atom`s in `InjectGlobalVariables` minifier plugin.

Instead of allocating a new `Atom` on every replacement, create `Atom` lazily when making first replacement, and cache it.

As discussed in: #4759 (comment)
  • Loading branch information
overlookmotel committed Aug 10, 2024
1 parent 62f759c commit 35f2742
Showing 1 changed file with 21 additions and 7 deletions.
28 changes: 21 additions & 7 deletions crates/oxc_minifier/src/plugins/inject_global_variables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,20 @@ impl InjectImportSpecifier {
}
}

impl From<&InjectImport> for DotDefine {
/// Wrapper around `DotDefine` which caches the `Atom` to replace with.
/// `value_atom` is populated lazily when first replacement happens.
/// If no replacement is made, `value_atom` remains `None`.
struct DotDefineState<'a> {
dot_define: DotDefine,
value_atom: Option<Atom<'a>>,
}

impl<'a> From<&InjectImport> for DotDefineState<'a> {
fn from(inject: &InjectImport) -> Self {
let parts = inject.specifier.local().split('.').map(CompactStr::from).collect::<Vec<_>>();
let value = inject.replace_value.clone().unwrap();
Self { parts, value }
let dot_define = DotDefine { parts, value };
Self { dot_define, value_atom: None }
}
}

Expand All @@ -102,7 +111,7 @@ pub struct InjectGlobalVariables<'a> {

// states
/// Dot defines derived from the config.
dot_defines: Vec<DotDefine>,
dot_defines: Vec<DotDefineState<'a>>,

/// Identifiers for which dot define replaced a member expression.
replaced_dot_defines:
Expand Down Expand Up @@ -138,7 +147,7 @@ impl<'a> InjectGlobalVariables<'a> {
.injects
.iter()
.filter(|i| i.replace_value.is_some())
.map(DotDefine::from)
.map(DotDefineState::from)
.collect::<Vec<_>>();

if !dot_defines.is_empty() {
Expand Down Expand Up @@ -211,10 +220,15 @@ impl<'a> InjectGlobalVariables<'a> {

fn replace_dot_defines(&mut self, expr: &mut Expression<'a>) {
if let Expression::StaticMemberExpression(member) = expr {
for dot_define in &self.dot_defines {
for DotDefineState { dot_define, value_atom } in &mut self.dot_defines {
if ReplaceGlobalDefines::is_dot_define(dot_define, member) {
let value =
self.ast.expression_identifier_reference(SPAN, dot_define.value.as_str());
// Create `Atom` for replacement lazily on first replacement
if value_atom.is_none() {
*value_atom = Some(self.ast.atom(dot_define.value.as_str()));
}
let value_atom = value_atom.as_ref().unwrap().clone();

let value = self.ast.expression_identifier_reference(SPAN, value_atom);
*expr = value;
self.replaced_dot_defines
.push((dot_define.parts[0].clone(), dot_define.value.clone()));
Expand Down

0 comments on commit 35f2742

Please sign in to comment.