diff --git a/crates/oxc_minifier/src/peephole/remove_dead_code.rs b/crates/oxc_minifier/src/peephole/remove_dead_code.rs index 090a909f03836..bd76163110170 100644 --- a/crates/oxc_minifier/src/peephole/remove_dead_code.rs +++ b/crates/oxc_minifier/src/peephole/remove_dead_code.rs @@ -1,7 +1,7 @@ use oxc_allocator::Vec; use oxc_ast::{ast::*, Visit}; use oxc_ecmascript::{ - constant_evaluation::{ConstantEvaluation, IsLiteralValue}, + constant_evaluation::{ConstantEvaluation, IsLiteralValue, ValueType}, side_effects::MayHaveSideEffects, }; use oxc_span::GetSpan; @@ -358,6 +358,51 @@ impl<'a, 'b> PeepholeOptimizations { ctx.ast.move_expression(&mut unary_expr.argument), )) } + Expression::NewExpression(e) => { + let Expression::Identifier(ident) = &e.callee else { return None }; + let len = e.arguments.len(); + if match ident.name.as_str() { + "WeakSet" | "WeakMap" if ctx.is_global_reference(ident) => match len { + 0 => true, + 1 => match e.arguments[0].as_expression()? { + Expression::NullLiteral(_) => true, + Expression::ArrayExpression(e) => e.elements.is_empty(), + e if ctx.is_expression_undefined(e) => true, + _ => false, + }, + _ => false, + }, + "Date" if ctx.is_global_reference(ident) => match len { + 0 => true, + 1 => { + let arg = e.arguments[0].as_expression()?; + let ty = ValueType::from(arg); + matches!( + ty, + ValueType::Null + | ValueType::Undefined + | ValueType::Boolean + | ValueType::Number + | ValueType::String + ) && !ctx.expression_may_have_side_efffects(arg) + } + _ => false, + }, + "Set" | "Map" if ctx.is_global_reference(ident) => match len { + 0 => true, + 1 => match e.arguments[0].as_expression()? { + Expression::NullLiteral(_) => true, + e if ctx.is_expression_undefined(e) => true, + _ => false, + }, + _ => false, + }, + _ => false, + } { + return Some(ctx.ast.statement_empty(e.span)); + } + None + } _ => None, } } @@ -811,6 +856,43 @@ mod test { test("1", ""); } + #[test] + fn test_new_constructor_side_effect() { + test("new WeakSet()", ""); + test("new WeakSet(null)", ""); + test("new WeakSet(void 0)", ""); + test("new WeakSet([])", ""); + test_same("new WeakSet([x])"); + test_same("new WeakSet(x)"); + test("new WeakMap()", ""); + test("new WeakMap(null)", ""); + test("new WeakMap(void 0)", ""); + test("new WeakMap([])", ""); + test_same("new WeakMap([x])"); + test_same("new WeakMap(x)"); + test("new Date()", ""); + test("new Date('')", ""); + test("new Date(0)", ""); + test("new Date(null)", ""); + test("new Date(true)", ""); + test("new Date(false)", ""); + test("new Date(undefined)", ""); + test_same("new Date(x)"); + test("new Set()", ""); + // test("new Set([a, b, c])", ""); + test("new Set(null)", ""); + test("new Set(undefined)", ""); + test("new Set(void 0)", ""); + test_same("new Set(x)"); + test("new Map()", ""); + test("new Map(null)", ""); + test("new Map(undefined)", ""); + test("new Map(void 0)", ""); + // test_same("new Map([x])"); + test_same("new Map(x)"); + // test("new Map([[a, b], [c, d]])", ""); + } + #[test] fn keep_module_syntax() { test_same("throw foo; export let bar"); diff --git a/tasks/minsize/minsize.snap b/tasks/minsize/minsize.snap index 9a02cc0dd5add..b2756462d9b25 100644 --- a/tasks/minsize/minsize.snap +++ b/tasks/minsize/minsize.snap @@ -3,7 +3,7 @@ Original | minified | minified | gzip | gzip | Fixture ------------------------------------------------------------------------------------- 72.14 kB | 23.61 kB | 23.70 kB | 8.55 kB | 8.54 kB | react.development.js -173.90 kB | 59.69 kB | 59.82 kB | 19.26 kB | 19.33 kB | moment.js +173.90 kB | 59.71 kB | 59.82 kB | 19.26 kB | 19.33 kB | moment.js 287.63 kB | 89.58 kB | 90.07 kB | 31.08 kB | 31.95 kB | jquery.js