refactor(minifier): improve ast passes (#7518)

This commit is contained in:
Boshen 2024-11-28 09:33:31 +00:00
parent 32f860d238
commit 625a5bad02
12 changed files with 145 additions and 127 deletions

View file

@ -9,14 +9,10 @@ use crate::CompressorPass;
/// `var a; var b = 1; var c = 2` => `var a, b = 1; c = 2` /// `var a; var b = 1; var c = 2` => `var a, b = 1; c = 2`
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/CollapseVariableDeclarations.java> /// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/CollapseVariableDeclarations.java>
pub struct CollapseVariableDeclarations { pub struct CollapseVariableDeclarations {
changed: bool, pub(crate) changed: bool,
} }
impl<'a> CompressorPass<'a> for CollapseVariableDeclarations { impl<'a> CompressorPass<'a> for CollapseVariableDeclarations {
fn changed(&self) -> bool {
self.changed
}
fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) { fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) {
self.changed = false; self.changed = false;
traverse_mut_with_ctx(self, program, ctx); traverse_mut_with_ctx(self, program, ctx);

View file

@ -7,14 +7,10 @@ use crate::CompressorPass;
/// ///
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/ExploitAssigns.java> /// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/ExploitAssigns.java>
pub struct ExploitAssigns { pub struct ExploitAssigns {
changed: bool, pub(crate) changed: bool,
} }
impl<'a> CompressorPass<'a> for ExploitAssigns { impl<'a> CompressorPass<'a> for ExploitAssigns {
fn changed(&self) -> bool {
self.changed
}
fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) { fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) {
self.changed = false; self.changed = false;
traverse_mut_with_ctx(self, program, ctx); traverse_mut_with_ctx(self, program, ctx);

View file

@ -23,13 +23,46 @@ use oxc_ast::ast::*;
use oxc_traverse::{traverse_mut_with_ctx, ReusableTraverseCtx, Traverse, TraverseCtx}; use oxc_traverse::{traverse_mut_with_ctx, ReusableTraverseCtx, Traverse, TraverseCtx};
pub trait CompressorPass<'a>: Traverse<'a> { pub trait CompressorPass<'a>: Traverse<'a> {
fn changed(&self) -> bool;
fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>); fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>);
} }
// See `peepholeOptimizationsOnce`
// For pass:
// ```
// if (options.collapseVariableDeclarations) {
// passes.maybeAdd(exploitAssign);
// passes.maybeAdd(collapseVariableDeclarations);
// }
// ```
pub struct CollapsePass {
_x0_exploit_assigns: ExploitAssigns,
x1_collapse_variable_declarations: CollapseVariableDeclarations,
}
impl CollapsePass {
pub fn new() -> Self {
Self {
_x0_exploit_assigns: ExploitAssigns::new(),
x1_collapse_variable_declarations: CollapseVariableDeclarations::new(),
}
}
}
impl<'a> CompressorPass<'a> for CollapsePass {
fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) {
traverse_mut_with_ctx(self, program, ctx);
}
}
impl<'a> Traverse<'a> for CollapsePass {
fn enter_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>, ctx: &mut TraverseCtx<'a>) {
self.x1_collapse_variable_declarations.enter_statements(stmts, ctx);
}
}
// See `latePeepholeOptimizations` // See `latePeepholeOptimizations`
pub struct EarlyPass { pub struct LatePeepholeOptimizations {
x0_statement_fusion: StatementFusion, x0_statement_fusion: StatementFusion,
x1_peephole_remove_dead_code: PeepholeRemoveDeadCode, x1_peephole_remove_dead_code: PeepholeRemoveDeadCode,
// TODO: MinimizeExitPoints // TODO: MinimizeExitPoints
@ -37,10 +70,9 @@ pub struct EarlyPass {
x3_peephole_substitute_alternate_syntax: PeepholeSubstituteAlternateSyntax, x3_peephole_substitute_alternate_syntax: PeepholeSubstituteAlternateSyntax,
x4_peephole_replace_known_methods: PeepholeReplaceKnownMethods, x4_peephole_replace_known_methods: PeepholeReplaceKnownMethods,
x5_peephole_fold_constants: PeepholeFoldConstants, x5_peephole_fold_constants: PeepholeFoldConstants,
changed: bool,
} }
impl EarlyPass { impl LatePeepholeOptimizations {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
x0_statement_fusion: StatementFusion::new(), x0_statement_fusion: StatementFusion::new(),
@ -51,29 +83,55 @@ impl EarlyPass {
), ),
x4_peephole_replace_known_methods: PeepholeReplaceKnownMethods::new(), x4_peephole_replace_known_methods: PeepholeReplaceKnownMethods::new(),
x5_peephole_fold_constants: PeepholeFoldConstants::new(), x5_peephole_fold_constants: PeepholeFoldConstants::new(),
changed: false, }
}
fn reset_changed(&mut self) {
self.x0_statement_fusion.changed = false;
self.x1_peephole_remove_dead_code.changed = false;
self.x2_peephole_minimize_conditions.changed = false;
self.x3_peephole_substitute_alternate_syntax.changed = false;
self.x4_peephole_replace_known_methods.changed = false;
self.x5_peephole_fold_constants.changed = false;
}
fn changed(&self) -> bool {
self.x0_statement_fusion.changed
|| self.x1_peephole_remove_dead_code.changed
|| self.x2_peephole_minimize_conditions.changed
|| self.x3_peephole_substitute_alternate_syntax.changed
|| self.x4_peephole_replace_known_methods.changed
|| self.x5_peephole_fold_constants.changed
}
pub fn run_in_loop<'a>(
&mut self,
program: &mut Program<'a>,
ctx: &mut ReusableTraverseCtx<'a>,
) {
let mut i = 0;
loop {
self.reset_changed();
self.build(program, ctx);
if !self.changed() {
break;
}
if i > 10 {
debug_assert!(false, "Ran loop more than 10 times.");
break;
}
i += 1;
} }
} }
} }
impl<'a> CompressorPass<'a> for EarlyPass { impl<'a> CompressorPass<'a> for LatePeepholeOptimizations {
fn changed(&self) -> bool {
self.changed
}
fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) { fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) {
self.changed = false;
traverse_mut_with_ctx(self, program, ctx); traverse_mut_with_ctx(self, program, ctx);
self.changed = self.x0_statement_fusion.changed()
|| self.x1_peephole_remove_dead_code.changed()
|| self.x2_peephole_minimize_conditions.changed()
|| self.x3_peephole_substitute_alternate_syntax.changed()
|| self.x4_peephole_replace_known_methods.changed()
|| self.x5_peephole_fold_constants.changed();
} }
} }
impl<'a> Traverse<'a> for EarlyPass { impl<'a> Traverse<'a> for LatePeepholeOptimizations {
fn enter_statement(&mut self, stmt: &mut Statement<'a>, ctx: &mut TraverseCtx<'a>) { fn enter_statement(&mut self, stmt: &mut Statement<'a>, ctx: &mut TraverseCtx<'a>) {
self.x1_peephole_remove_dead_code.enter_statement(stmt, ctx); self.x1_peephole_remove_dead_code.enter_statement(stmt, ctx);
} }
@ -141,49 +199,56 @@ impl<'a> Traverse<'a> for EarlyPass {
} }
} }
// Passes listed in `getFinalization` in `DefaultPassConfig` // See `createPeepholeOptimizationsPass`
pub struct LatePass { pub struct PeepholeOptimizations {
x0_exploit_assigns: ExploitAssigns, // TODO: MinimizeExitPoints
x1_collapse_variable_declarations: CollapseVariableDeclarations, x2_peephole_minimize_conditions: PeepholeMinimizeConditions,
x2_peephole_substitute_alternate_syntax: PeepholeSubstituteAlternateSyntax, x3_peephole_substitute_alternate_syntax: PeepholeSubstituteAlternateSyntax,
changed: bool, x4_peephole_replace_known_methods: PeepholeReplaceKnownMethods,
x5_peephole_remove_dead_code: PeepholeRemoveDeadCode,
x6_peephole_fold_constants: PeepholeFoldConstants,
} }
impl LatePass { impl PeepholeOptimizations {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
x0_exploit_assigns: ExploitAssigns::new(), x2_peephole_minimize_conditions: PeepholeMinimizeConditions::new(),
x1_collapse_variable_declarations: CollapseVariableDeclarations::new(), x3_peephole_substitute_alternate_syntax: PeepholeSubstituteAlternateSyntax::new(
x2_peephole_substitute_alternate_syntax: PeepholeSubstituteAlternateSyntax::new(
/* in_fixed_loop */ false, /* in_fixed_loop */ false,
), ),
changed: false, x4_peephole_replace_known_methods: PeepholeReplaceKnownMethods::new(),
x5_peephole_remove_dead_code: PeepholeRemoveDeadCode::new(),
x6_peephole_fold_constants: PeepholeFoldConstants::new(),
} }
} }
} }
impl<'a> CompressorPass<'a> for LatePass { impl<'a> CompressorPass<'a> for PeepholeOptimizations {
fn changed(&self) -> bool {
self.changed
}
fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) { fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) {
self.changed = false;
traverse_mut_with_ctx(self, program, ctx); traverse_mut_with_ctx(self, program, ctx);
self.changed = self.x0_exploit_assigns.changed()
|| self.x0_exploit_assigns.changed()
|| self.x1_collapse_variable_declarations.changed()
|| self.x2_peephole_substitute_alternate_syntax.changed();
} }
} }
impl<'a> Traverse<'a> for LatePass { impl<'a> Traverse<'a> for PeepholeOptimizations {
fn enter_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>, ctx: &mut TraverseCtx<'a>) { fn enter_statement(&mut self, stmt: &mut Statement<'a>, ctx: &mut TraverseCtx<'a>) {
self.x1_collapse_variable_declarations.enter_statements(stmts, ctx); self.x5_peephole_remove_dead_code.enter_statement(stmt, ctx);
}
fn exit_statement(&mut self, stmt: &mut Statement<'a>, ctx: &mut TraverseCtx<'a>) {
self.x2_peephole_minimize_conditions.exit_statement(stmt, ctx);
self.x5_peephole_remove_dead_code.exit_statement(stmt, ctx);
}
fn exit_program(&mut self, program: &mut Program<'a>, ctx: &mut TraverseCtx<'a>) {
self.x5_peephole_remove_dead_code.exit_program(program, ctx);
}
fn exit_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>, ctx: &mut TraverseCtx<'a>) {
self.x5_peephole_remove_dead_code.exit_statements(stmts, ctx);
} }
fn exit_return_statement(&mut self, stmt: &mut ReturnStatement<'a>, ctx: &mut TraverseCtx<'a>) { fn exit_return_statement(&mut self, stmt: &mut ReturnStatement<'a>, ctx: &mut TraverseCtx<'a>) {
self.x2_peephole_substitute_alternate_syntax.exit_return_statement(stmt, ctx); self.x3_peephole_substitute_alternate_syntax.exit_return_statement(stmt, ctx);
} }
fn enter_variable_declaration( fn enter_variable_declaration(
@ -191,23 +256,27 @@ impl<'a> Traverse<'a> for LatePass {
decl: &mut VariableDeclaration<'a>, decl: &mut VariableDeclaration<'a>,
ctx: &mut TraverseCtx<'a>, ctx: &mut TraverseCtx<'a>,
) { ) {
self.x2_peephole_substitute_alternate_syntax.enter_variable_declaration(decl, ctx); self.x3_peephole_substitute_alternate_syntax.enter_variable_declaration(decl, ctx);
}
fn enter_call_expression(&mut self, expr: &mut CallExpression<'a>, ctx: &mut TraverseCtx<'a>) {
self.x2_peephole_substitute_alternate_syntax.enter_call_expression(expr, ctx);
}
fn exit_call_expression(&mut self, expr: &mut CallExpression<'a>, ctx: &mut TraverseCtx<'a>) {
self.x2_peephole_substitute_alternate_syntax.exit_call_expression(expr, ctx);
} }
fn enter_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) { fn enter_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) {
self.x2_peephole_substitute_alternate_syntax.enter_expression(expr, ctx); self.x3_peephole_substitute_alternate_syntax.enter_expression(expr, ctx);
self.x4_peephole_replace_known_methods.enter_expression(expr, ctx);
} }
fn exit_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) { fn exit_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) {
self.x2_peephole_substitute_alternate_syntax.exit_expression(expr, ctx); self.x2_peephole_minimize_conditions.exit_expression(expr, ctx);
self.x3_peephole_substitute_alternate_syntax.exit_expression(expr, ctx);
self.x5_peephole_remove_dead_code.exit_expression(expr, ctx);
self.x6_peephole_fold_constants.exit_expression(expr, ctx);
}
fn enter_call_expression(&mut self, expr: &mut CallExpression<'a>, ctx: &mut TraverseCtx<'a>) {
self.x3_peephole_substitute_alternate_syntax.enter_call_expression(expr, ctx);
}
fn exit_call_expression(&mut self, expr: &mut CallExpression<'a>, ctx: &mut TraverseCtx<'a>) {
self.x3_peephole_substitute_alternate_syntax.exit_call_expression(expr, ctx);
} }
fn enter_binary_expression( fn enter_binary_expression(
@ -215,6 +284,6 @@ impl<'a> Traverse<'a> for LatePass {
expr: &mut BinaryExpression<'a>, expr: &mut BinaryExpression<'a>,
ctx: &mut TraverseCtx<'a>, ctx: &mut TraverseCtx<'a>,
) { ) {
self.x2_peephole_substitute_alternate_syntax.enter_binary_expression(expr, ctx); self.x3_peephole_substitute_alternate_syntax.enter_binary_expression(expr, ctx);
} }
} }

View file

@ -16,14 +16,10 @@ use crate::{node_util::Ctx, CompressorPass};
/// ///
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/PeepholeFoldConstants.java> /// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/PeepholeFoldConstants.java>
pub struct PeepholeFoldConstants { pub struct PeepholeFoldConstants {
changed: bool, pub(crate) changed: bool,
} }
impl<'a> CompressorPass<'a> for PeepholeFoldConstants { impl<'a> CompressorPass<'a> for PeepholeFoldConstants {
fn changed(&self) -> bool {
self.changed
}
fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) { fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) {
self.changed = false; self.changed = false;
traverse_mut_with_ctx(self, program, ctx); traverse_mut_with_ctx(self, program, ctx);

View file

@ -13,14 +13,10 @@ use crate::CompressorPass;
/// ///
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/PeepholeMinimizeConditions.java> /// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/PeepholeMinimizeConditions.java>
pub struct PeepholeMinimizeConditions { pub struct PeepholeMinimizeConditions {
changed: bool, pub(crate) changed: bool,
} }
impl<'a> CompressorPass<'a> for PeepholeMinimizeConditions { impl<'a> CompressorPass<'a> for PeepholeMinimizeConditions {
fn changed(&self) -> bool {
self.changed
}
fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) { fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) {
self.changed = false; self.changed = false;
traverse_mut_with_ctx(self, program, ctx); traverse_mut_with_ctx(self, program, ctx);

View file

@ -14,14 +14,10 @@ use crate::{keep_var::KeepVar, CompressorPass};
/// See `KeepVar` at the end of this file for `var` hoisting logic. /// See `KeepVar` at the end of this file for `var` hoisting logic.
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/PeepholeRemoveDeadCode.java> /// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/PeepholeRemoveDeadCode.java>
pub struct PeepholeRemoveDeadCode { pub struct PeepholeRemoveDeadCode {
changed: bool, pub(crate) changed: bool,
} }
impl<'a> CompressorPass<'a> for PeepholeRemoveDeadCode { impl<'a> CompressorPass<'a> for PeepholeRemoveDeadCode {
fn changed(&self) -> bool {
self.changed
}
fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) { fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) {
self.changed = false; self.changed = false;
traverse_mut_with_ctx(self, program, ctx); traverse_mut_with_ctx(self, program, ctx);

View file

@ -11,14 +11,10 @@ use crate::{node_util::Ctx, CompressorPass};
/// Minimize With Known Methods /// Minimize With Known Methods
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/PeepholeReplaceKnownMethods.java> /// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/PeepholeReplaceKnownMethods.java>
pub struct PeepholeReplaceKnownMethods { pub struct PeepholeReplaceKnownMethods {
changed: bool, pub(crate) changed: bool,
} }
impl<'a> CompressorPass<'a> for PeepholeReplaceKnownMethods { impl<'a> CompressorPass<'a> for PeepholeReplaceKnownMethods {
fn changed(&self) -> bool {
self.changed
}
fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) { fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) {
self.changed = false; self.changed = false;
traverse_mut_with_ctx(self, program, ctx); traverse_mut_with_ctx(self, program, ctx);

View file

@ -24,14 +24,10 @@ pub struct PeepholeSubstituteAlternateSyntax {
// states // states
in_define_export: bool, in_define_export: bool,
changed: bool, pub(crate) changed: bool,
} }
impl<'a> CompressorPass<'a> for PeepholeSubstituteAlternateSyntax { impl<'a> CompressorPass<'a> for PeepholeSubstituteAlternateSyntax {
fn changed(&self) -> bool {
self.changed
}
fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) { fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) {
self.changed = false; self.changed = false;
traverse_mut_with_ctx(self, program, ctx); traverse_mut_with_ctx(self, program, ctx);

View file

@ -15,10 +15,6 @@ pub struct RemoveSyntax {
} }
impl<'a> CompressorPass<'a> for RemoveSyntax { impl<'a> CompressorPass<'a> for RemoveSyntax {
fn changed(&self) -> bool {
false
}
fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) { fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) {
traverse_mut_with_ctx(self, program, ctx); traverse_mut_with_ctx(self, program, ctx);
} }

View file

@ -12,14 +12,10 @@ use crate::CompressorPass;
/// ///
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/StatementFusion.java> /// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/StatementFusion.java>
pub struct StatementFusion { pub struct StatementFusion {
changed: bool, pub(crate) changed: bool,
} }
impl<'a> CompressorPass<'a> for StatementFusion { impl<'a> CompressorPass<'a> for StatementFusion {
fn changed(&self) -> bool {
self.changed
}
fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) { fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) {
self.changed = false; self.changed = false;
traverse_mut_with_ctx(self, program, ctx); traverse_mut_with_ctx(self, program, ctx);

View file

@ -5,8 +5,8 @@ use oxc_traverse::ReusableTraverseCtx;
use crate::{ use crate::{
ast_passes::{ ast_passes::{
EarlyPass, LatePass, PeepholeFoldConstants, PeepholeMinimizeConditions, CollapsePass, LatePeepholeOptimizations, PeepholeFoldConstants, PeepholeMinimizeConditions,
PeepholeRemoveDeadCode, RemoveSyntax, PeepholeOptimizations, PeepholeRemoveDeadCode, RemoveSyntax,
}, },
CompressOptions, CompressorPass, CompressOptions, CompressorPass,
}; };
@ -41,25 +41,10 @@ impl<'a> Compressor<'a> {
return; return;
} }
let mut i = 0; PeepholeOptimizations::new().build(program, &mut ctx);
loop { CollapsePass::new().build(program, &mut ctx);
let mut changed = false; LatePeepholeOptimizations::new().run_in_loop(program, &mut ctx);
let mut pass = EarlyPass::new(); PeepholeOptimizations::new().build(program, &mut ctx);
pass.build(program, &mut ctx);
if pass.changed() {
changed = true;
}
if !changed {
break;
}
if i > 50 {
debug_assert!(false, "Ran in a infinite loop.");
break;
}
i += 1;
}
LatePass::new().build(program, &mut ctx);
} }
fn dead_code_elimination(program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) { fn dead_code_elimination(program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) {

View file

@ -4,7 +4,7 @@ Original | Minified | esbuild | Gzip | esbuild
173.90 kB | 61.16 kB | 59.82 kB | 19.62 kB | 19.33 kB | moment.js 173.90 kB | 61.16 kB | 59.82 kB | 19.62 kB | 19.33 kB | moment.js
287.63 kB | 91.70 kB | 90.07 kB | 32.35 kB | 31.95 kB | jquery.js 287.63 kB | 91.70 kB | 90.07 kB | 32.34 kB | 31.95 kB | jquery.js
342.15 kB | 120.23 kB | 118.14 kB | 44.72 kB | 44.37 kB | vue.js 342.15 kB | 120.23 kB | 118.14 kB | 44.72 kB | 44.37 kB | vue.js
@ -12,15 +12,15 @@ Original | Minified | esbuild | Gzip | esbuild
555.77 kB | 275.23 kB | 270.13 kB | 91.33 kB | 90.80 kB | d3.js 555.77 kB | 275.23 kB | 270.13 kB | 91.33 kB | 90.80 kB | d3.js
1.01 MB | 464.89 kB | 458.89 kB | 127.05 kB | 126.71 kB | bundle.min.js 1.01 MB | 464.89 kB | 458.89 kB | 127.04 kB | 126.71 kB | bundle.min.js
1.25 MB | 660.45 kB | 646.76 kB | 164.57 kB | 163.73 kB | three.js 1.25 MB | 660.45 kB | 646.76 kB | 164.46 kB | 163.73 kB | three.js
2.14 MB | 739.98 kB | 724.14 kB | 181.63 kB | 181.07 kB | victory.js 2.14 MB | 739.98 kB | 724.14 kB | 181.63 kB | 181.07 kB | victory.js
3.20 MB | 1.02 MB | 1.01 MB | 333.05 kB | 331.56 kB | echarts.js 3.20 MB | 1.02 MB | 1.01 MB | 333.04 kB | 331.56 kB | echarts.js
6.69 MB | 2.39 MB | 2.31 MB | 496.76 kB | 488.28 kB | antd.js 6.69 MB | 2.39 MB | 2.31 MB | 496.74 kB | 488.28 kB | antd.js
10.95 MB | 3.55 MB | 3.49 MB | 913.60 kB | 915.50 kB | typescript.js 10.95 MB | 3.55 MB | 3.49 MB | 913.59 kB | 915.50 kB | typescript.js