mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
refactor(minifier): improve ast passes (#7518)
This commit is contained in:
parent
32f860d238
commit
625a5bad02
12 changed files with 145 additions and 127 deletions
|
|
@ -9,14 +9,10 @@ use crate::CompressorPass;
|
|||
/// `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>
|
||||
pub struct CollapseVariableDeclarations {
|
||||
changed: bool,
|
||||
pub(crate) changed: bool,
|
||||
}
|
||||
|
||||
impl<'a> CompressorPass<'a> for CollapseVariableDeclarations {
|
||||
fn changed(&self) -> bool {
|
||||
self.changed
|
||||
}
|
||||
|
||||
fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) {
|
||||
self.changed = false;
|
||||
traverse_mut_with_ctx(self, program, ctx);
|
||||
|
|
|
|||
|
|
@ -7,14 +7,10 @@ use crate::CompressorPass;
|
|||
///
|
||||
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/ExploitAssigns.java>
|
||||
pub struct ExploitAssigns {
|
||||
changed: bool,
|
||||
pub(crate) changed: bool,
|
||||
}
|
||||
|
||||
impl<'a> CompressorPass<'a> for ExploitAssigns {
|
||||
fn changed(&self) -> bool {
|
||||
self.changed
|
||||
}
|
||||
|
||||
fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) {
|
||||
self.changed = false;
|
||||
traverse_mut_with_ctx(self, program, ctx);
|
||||
|
|
|
|||
|
|
@ -23,13 +23,46 @@ use oxc_ast::ast::*;
|
|||
use oxc_traverse::{traverse_mut_with_ctx, ReusableTraverseCtx, Traverse, TraverseCtx};
|
||||
|
||||
pub trait CompressorPass<'a>: Traverse<'a> {
|
||||
fn changed(&self) -> bool;
|
||||
|
||||
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`
|
||||
pub struct EarlyPass {
|
||||
pub struct LatePeepholeOptimizations {
|
||||
x0_statement_fusion: StatementFusion,
|
||||
x1_peephole_remove_dead_code: PeepholeRemoveDeadCode,
|
||||
// TODO: MinimizeExitPoints
|
||||
|
|
@ -37,10 +70,9 @@ pub struct EarlyPass {
|
|||
x3_peephole_substitute_alternate_syntax: PeepholeSubstituteAlternateSyntax,
|
||||
x4_peephole_replace_known_methods: PeepholeReplaceKnownMethods,
|
||||
x5_peephole_fold_constants: PeepholeFoldConstants,
|
||||
changed: bool,
|
||||
}
|
||||
|
||||
impl EarlyPass {
|
||||
impl LatePeepholeOptimizations {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
x0_statement_fusion: StatementFusion::new(),
|
||||
|
|
@ -51,29 +83,55 @@ impl EarlyPass {
|
|||
),
|
||||
x4_peephole_replace_known_methods: PeepholeReplaceKnownMethods::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 {
|
||||
fn changed(&self) -> bool {
|
||||
self.changed
|
||||
}
|
||||
|
||||
impl<'a> CompressorPass<'a> for LatePeepholeOptimizations {
|
||||
fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) {
|
||||
self.changed = false;
|
||||
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>) {
|
||||
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`
|
||||
pub struct LatePass {
|
||||
x0_exploit_assigns: ExploitAssigns,
|
||||
x1_collapse_variable_declarations: CollapseVariableDeclarations,
|
||||
x2_peephole_substitute_alternate_syntax: PeepholeSubstituteAlternateSyntax,
|
||||
changed: bool,
|
||||
// See `createPeepholeOptimizationsPass`
|
||||
pub struct PeepholeOptimizations {
|
||||
// TODO: MinimizeExitPoints
|
||||
x2_peephole_minimize_conditions: PeepholeMinimizeConditions,
|
||||
x3_peephole_substitute_alternate_syntax: PeepholeSubstituteAlternateSyntax,
|
||||
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 {
|
||||
Self {
|
||||
x0_exploit_assigns: ExploitAssigns::new(),
|
||||
x1_collapse_variable_declarations: CollapseVariableDeclarations::new(),
|
||||
x2_peephole_substitute_alternate_syntax: PeepholeSubstituteAlternateSyntax::new(
|
||||
x2_peephole_minimize_conditions: PeepholeMinimizeConditions::new(),
|
||||
x3_peephole_substitute_alternate_syntax: PeepholeSubstituteAlternateSyntax::new(
|
||||
/* 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 {
|
||||
fn changed(&self) -> bool {
|
||||
self.changed
|
||||
}
|
||||
|
||||
impl<'a> CompressorPass<'a> for PeepholeOptimizations {
|
||||
fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) {
|
||||
self.changed = false;
|
||||
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 {
|
||||
fn enter_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>, ctx: &mut TraverseCtx<'a>) {
|
||||
self.x1_collapse_variable_declarations.enter_statements(stmts, ctx);
|
||||
impl<'a> Traverse<'a> for PeepholeOptimizations {
|
||||
fn enter_statement(&mut self, stmt: &mut Statement<'a>, ctx: &mut TraverseCtx<'a>) {
|
||||
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>) {
|
||||
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(
|
||||
|
|
@ -191,23 +256,27 @@ impl<'a> Traverse<'a> for LatePass {
|
|||
decl: &mut VariableDeclaration<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
self.x2_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);
|
||||
self.x3_peephole_substitute_alternate_syntax.enter_variable_declaration(decl, ctx);
|
||||
}
|
||||
|
||||
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>) {
|
||||
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(
|
||||
|
|
@ -215,6 +284,6 @@ impl<'a> Traverse<'a> for LatePass {
|
|||
expr: &mut BinaryExpression<'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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
pub struct PeepholeFoldConstants {
|
||||
changed: bool,
|
||||
pub(crate) changed: bool,
|
||||
}
|
||||
|
||||
impl<'a> CompressorPass<'a> for PeepholeFoldConstants {
|
||||
fn changed(&self) -> bool {
|
||||
self.changed
|
||||
}
|
||||
|
||||
fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) {
|
||||
self.changed = false;
|
||||
traverse_mut_with_ctx(self, program, ctx);
|
||||
|
|
|
|||
|
|
@ -13,14 +13,10 @@ use crate::CompressorPass;
|
|||
///
|
||||
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/PeepholeMinimizeConditions.java>
|
||||
pub struct PeepholeMinimizeConditions {
|
||||
changed: bool,
|
||||
pub(crate) changed: bool,
|
||||
}
|
||||
|
||||
impl<'a> CompressorPass<'a> for PeepholeMinimizeConditions {
|
||||
fn changed(&self) -> bool {
|
||||
self.changed
|
||||
}
|
||||
|
||||
fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) {
|
||||
self.changed = false;
|
||||
traverse_mut_with_ctx(self, program, ctx);
|
||||
|
|
|
|||
|
|
@ -14,14 +14,10 @@ use crate::{keep_var::KeepVar, CompressorPass};
|
|||
/// 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>
|
||||
pub struct PeepholeRemoveDeadCode {
|
||||
changed: bool,
|
||||
pub(crate) changed: bool,
|
||||
}
|
||||
|
||||
impl<'a> CompressorPass<'a> for PeepholeRemoveDeadCode {
|
||||
fn changed(&self) -> bool {
|
||||
self.changed
|
||||
}
|
||||
|
||||
fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) {
|
||||
self.changed = false;
|
||||
traverse_mut_with_ctx(self, program, ctx);
|
||||
|
|
|
|||
|
|
@ -11,14 +11,10 @@ use crate::{node_util::Ctx, CompressorPass};
|
|||
/// Minimize With Known Methods
|
||||
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/PeepholeReplaceKnownMethods.java>
|
||||
pub struct PeepholeReplaceKnownMethods {
|
||||
changed: bool,
|
||||
pub(crate) changed: bool,
|
||||
}
|
||||
|
||||
impl<'a> CompressorPass<'a> for PeepholeReplaceKnownMethods {
|
||||
fn changed(&self) -> bool {
|
||||
self.changed
|
||||
}
|
||||
|
||||
fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) {
|
||||
self.changed = false;
|
||||
traverse_mut_with_ctx(self, program, ctx);
|
||||
|
|
|
|||
|
|
@ -24,14 +24,10 @@ pub struct PeepholeSubstituteAlternateSyntax {
|
|||
// states
|
||||
in_define_export: bool,
|
||||
|
||||
changed: bool,
|
||||
pub(crate) changed: bool,
|
||||
}
|
||||
|
||||
impl<'a> CompressorPass<'a> for PeepholeSubstituteAlternateSyntax {
|
||||
fn changed(&self) -> bool {
|
||||
self.changed
|
||||
}
|
||||
|
||||
fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) {
|
||||
self.changed = false;
|
||||
traverse_mut_with_ctx(self, program, ctx);
|
||||
|
|
|
|||
|
|
@ -15,10 +15,6 @@ pub struct RemoveSyntax {
|
|||
}
|
||||
|
||||
impl<'a> CompressorPass<'a> for RemoveSyntax {
|
||||
fn changed(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) {
|
||||
traverse_mut_with_ctx(self, program, ctx);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,14 +12,10 @@ use crate::CompressorPass;
|
|||
///
|
||||
/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/StatementFusion.java>
|
||||
pub struct StatementFusion {
|
||||
changed: bool,
|
||||
pub(crate) changed: bool,
|
||||
}
|
||||
|
||||
impl<'a> CompressorPass<'a> for StatementFusion {
|
||||
fn changed(&self) -> bool {
|
||||
self.changed
|
||||
}
|
||||
|
||||
fn build(&mut self, program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) {
|
||||
self.changed = false;
|
||||
traverse_mut_with_ctx(self, program, ctx);
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ use oxc_traverse::ReusableTraverseCtx;
|
|||
|
||||
use crate::{
|
||||
ast_passes::{
|
||||
EarlyPass, LatePass, PeepholeFoldConstants, PeepholeMinimizeConditions,
|
||||
PeepholeRemoveDeadCode, RemoveSyntax,
|
||||
CollapsePass, LatePeepholeOptimizations, PeepholeFoldConstants, PeepholeMinimizeConditions,
|
||||
PeepholeOptimizations, PeepholeRemoveDeadCode, RemoveSyntax,
|
||||
},
|
||||
CompressOptions, CompressorPass,
|
||||
};
|
||||
|
|
@ -41,25 +41,10 @@ impl<'a> Compressor<'a> {
|
|||
return;
|
||||
}
|
||||
|
||||
let mut i = 0;
|
||||
loop {
|
||||
let mut changed = false;
|
||||
let mut pass = EarlyPass::new();
|
||||
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);
|
||||
PeepholeOptimizations::new().build(program, &mut ctx);
|
||||
CollapsePass::new().build(program, &mut ctx);
|
||||
LatePeepholeOptimizations::new().run_in_loop(program, &mut ctx);
|
||||
PeepholeOptimizations::new().build(program, &mut ctx);
|
||||
}
|
||||
|
||||
fn dead_code_elimination(program: &mut Program<'a>, ctx: &mut ReusableTraverseCtx<'a>) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue