Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions crates/oxc_minifier/src/ast_passes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use oxc_traverse::{traverse_mut_with_ctx, ReusableTraverseCtx, Traverse, Travers

mod collapse_variable_declarations;
mod exploit_assigns;
mod normalize;
mod peephole_fold_constants;
mod peephole_minimize_conditions;
mod peephole_remove_dead_code;
Expand All @@ -14,6 +15,7 @@ mod statement_fusion;

pub use collapse_variable_declarations::CollapseVariableDeclarations;
pub use exploit_assigns::ExploitAssigns;
pub use normalize::Normalize;
pub use peephole_fold_constants::PeepholeFoldConstants;
pub use peephole_minimize_conditions::PeepholeMinimizeConditions;
pub use peephole_remove_dead_code::PeepholeRemoveDeadCode;
Expand Down
67 changes: 67 additions & 0 deletions crates/oxc_minifier/src/ast_passes/normalize.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use oxc_ast::ast::*;
use oxc_syntax::scope::ScopeFlags;
use oxc_traverse::{traverse_mut_with_ctx, ReusableTraverseCtx, Traverse, TraverseCtx};

use crate::CompressorPass;

/// Normalize AST
///
/// Make subsequent AST passes easier to analyze:
///
/// * convert whiles to fors
///
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/Normalize.java>
pub struct Normalize;

impl<'a> CompressorPass<'a> for Normalize {
fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) {
traverse_mut_with_ctx(self, program, ctx);
}
}

impl<'a> Traverse<'a> for Normalize {
fn exit_statement(&mut self, stmt: &mut Statement<'a>, ctx: &mut TraverseCtx<'a>) {
if matches!(stmt, Statement::WhileStatement(_)) {
Self::convert_while_to_for(stmt, ctx);
}
}
}

impl<'a> Normalize {
pub fn new() -> Self {
Self
}

fn convert_while_to_for(stmt: &mut Statement<'a>, ctx: &mut TraverseCtx<'a>) {
let Statement::WhileStatement(while_stmt) = ctx.ast.move_statement(stmt) else { return };
let while_stmt = while_stmt.unbox();
let for_stmt = ctx.ast.alloc_for_statement_with_scope_id(
while_stmt.span,
None,
Some(while_stmt.test),
None,
while_stmt.body,
ctx.create_child_scope_of_current(ScopeFlags::empty()),
);
*stmt = Statement::ForStatement(for_stmt);
}
}

#[cfg(test)]
mod test {
use oxc_allocator::Allocator;

use crate::tester;

fn test(source_text: &str, expected: &str) {
let allocator = Allocator::default();
let mut pass = super::Normalize::new();
tester::test(&allocator, source_text, expected, &mut pass);
}

#[test]
fn test_while() {
// Verify while loops are converted to FOR loops.
test("while(c < b) foo()", "for(; c < b;) foo()");
}
}
5 changes: 3 additions & 2 deletions crates/oxc_minifier/src/compressor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use oxc_traverse::ReusableTraverseCtx;

use crate::{
ast_passes::{
CollapsePass, DeadCodeElimination, LatePeepholeOptimizations, PeepholeOptimizations,
RemoveSyntax,
CollapsePass, DeadCodeElimination, LatePeepholeOptimizations, Normalize,
PeepholeOptimizations, RemoveSyntax,
},
CompressOptions, CompressorPass,
};
Expand Down Expand Up @@ -35,6 +35,7 @@ impl<'a> Compressor<'a> {
) {
let mut ctx = ReusableTraverseCtx::new(scopes, symbols, self.allocator);
RemoveSyntax::new(self.options).build(program, &mut ctx);
Normalize::new().build(program, &mut ctx);
PeepholeOptimizations::new().build(program, &mut ctx);
CollapsePass::new().build(program, &mut ctx);
LatePeepholeOptimizations::new().run_in_loop(program, &mut ctx);
Expand Down
20 changes: 10 additions & 10 deletions tasks/minsize/minsize.snap
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,23 @@ Original | minified | minified | gzip | gzip | Fixture

173.90 kB | 61.52 kB | 59.82 kB | 19.54 kB | 19.33 kB | moment.js

287.63 kB | 92.47 kB | 90.07 kB | 32.30 kB | 31.95 kB | jquery.js
287.63 kB | 92.42 kB | 90.07 kB | 32.32 kB | 31.95 kB | jquery.js

342.15 kB | 121.36 kB | 118.14 kB | 44.67 kB | 44.37 kB | vue.js
342.15 kB | 121.31 kB | 118.14 kB | 44.69 kB | 44.37 kB | vue.js

544.10 kB | 73.32 kB | 72.48 kB | 26.13 kB | 26.20 kB | lodash.js
544.10 kB | 73.22 kB | 72.48 kB | 26.22 kB | 26.20 kB | lodash.js

555.77 kB | 275.77 kB | 270.13 kB | 91.12 kB | 90.80 kB | d3.js
555.77 kB | 275.67 kB | 270.13 kB | 91.19 kB | 90.80 kB | d3.js

1.01 MB | 466.38 kB | 458.89 kB | 126.72 kB | 126.71 kB | bundle.min.js
1.01 MB | 466.33 kB | 458.89 kB | 126.76 kB | 126.71 kB | bundle.min.js

1.25 MB | 660.41 kB | 646.76 kB | 163.99 kB | 163.73 kB | three.js
1.25 MB | 660.39 kB | 646.76 kB | 164.00 kB | 163.73 kB | three.js

2.14 MB | 740.08 kB | 724.14 kB | 181.34 kB | 181.07 kB | victory.js
2.14 MB | 739.97 kB | 724.14 kB | 181.42 kB | 181.07 kB | victory.js

3.20 MB | 1.02 MB | 1.01 MB | 332.26 kB | 331.56 kB | echarts.js
3.20 MB | 1.02 MB | 1.01 MB | 332.30 kB | 331.56 kB | echarts.js

6.69 MB | 2.39 MB | 2.31 MB | 495.65 kB | 488.28 kB | antd.js
6.69 MB | 2.39 MB | 2.31 MB | 495.67 kB | 488.28 kB | antd.js

10.95 MB | 3.54 MB | 3.49 MB | 909.94 kB | 915.50 kB | typescript.js
10.95 MB | 3.54 MB | 3.49 MB | 910.07 kB | 915.50 kB | typescript.js