diff --git a/Cargo.lock b/Cargo.lock index b565fa4d7b3a..e395002dee39 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3394,7 +3394,7 @@ dependencies = [ [[package]] name = "swc_webpack_ast" -version = "0.5.1" +version = "0.5.2" dependencies = [ "anyhow", "rayon", diff --git a/crates/swc_webpack_ast/Cargo.toml b/crates/swc_webpack_ast/Cargo.toml index 8d44f09d8b8e..04e0aa5a0bfe 100644 --- a/crates/swc_webpack_ast/Cargo.toml +++ b/crates/swc_webpack_ast/Cargo.toml @@ -5,7 +5,7 @@ edition = "2018" license = "Apache-2.0" name = "swc_webpack_ast" repository = "https://github.com/swc-project/swc.git" -version = "0.5.1" +version = "0.5.2" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/crates/swc_webpack_ast/src/reducer.rs b/crates/swc_webpack_ast/src/reducer.rs index 316e8965d526..b2ab9f4abaea 100644 --- a/crates/swc_webpack_ast/src/reducer.rs +++ b/crates/swc_webpack_ast/src/reducer.rs @@ -4,7 +4,7 @@ use swc_common::{ collections::AHashSet, pass::{Repeat, Repeated}, util::take::Take, - Mark, Span, SyntaxContext, DUMMY_SP, + Mark, Span, Spanned, SyntaxContext, DUMMY_SP, }; use swc_ecma_ast::*; use swc_ecma_utils::{ident::IdentLike, Id, IsEmpty, StmtLike, StmtOrModuleItem}; @@ -231,6 +231,7 @@ impl ReduceAst { // Flatten a function declaration. Stmt::Decl(Decl::Fn(fn_decl)) => { let Function { + span, params, decorators, body, @@ -239,9 +240,9 @@ impl ReduceAst { if !decorators.is_empty() { let mut s = Stmt::Expr(ExprStmt { - span: DUMMY_SP, + span, expr: Box::new(Expr::Seq(SeqExpr { - span: DUMMY_SP, + span, exprs: decorators.into_iter().map(|d| d.expr).collect(), })), }); @@ -259,11 +260,8 @@ impl ReduceAst { } let mut s = Stmt::Expr(ExprStmt { - span: DUMMY_SP, - expr: Box::new(Expr::Seq(SeqExpr { - span: DUMMY_SP, - exprs, - })), + span, + expr: Box::new(Expr::Seq(SeqExpr { span, exprs })), }); s.visit_mut_with(self); to.push(T::from_stmt(s)); @@ -284,9 +282,9 @@ impl ReduceAst { if !exprs.is_empty() { let mut s = Stmt::Expr(ExprStmt { - span: DUMMY_SP, + span: d.span, expr: Box::new(Expr::Seq(SeqExpr { - span: DUMMY_SP, + span: d.span, exprs, })), }); @@ -296,10 +294,18 @@ impl ReduceAst { } Stmt::ForOf(ForOfStmt { - left, right, body, .. + span, + left, + right, + body, + .. }) | Stmt::ForIn(ForInStmt { - left, right, body, .. + span, + left, + right, + body, + .. }) => { self.changed = true; @@ -318,11 +324,8 @@ impl ReduceAst { if !exprs.is_empty() { to.push(T::from_stmt(Stmt::Expr(ExprStmt { - span: DUMMY_SP, - expr: Box::new(Expr::Seq(SeqExpr { - span: DUMMY_SP, - exprs, - })), + span, + expr: Box::new(Expr::Seq(SeqExpr { span, exprs })), }))); } to.push(T::from_stmt(*body)); @@ -565,11 +568,14 @@ impl VisitMut for ReduceAst { match e { Expr::Call(CallExpr { + span, callee: ExprOrSuper::Expr(callee), args, .. }) | Expr::New(NewExpr { + span, + callee, args: Some(args), .. @@ -601,7 +607,7 @@ impl VisitMut for ReduceAst { if callee.is_invalid() { let mut seq = Expr::Seq(SeqExpr { - span: DUMMY_SP, + span: *span, exprs: args.take().into_iter().map(|arg| arg.expr).collect(), }); @@ -722,7 +728,7 @@ impl VisitMut for ReduceAst { exprs.extend(expr.tpl.exprs.take()); let mut seq = Expr::Seq(SeqExpr { - span: DUMMY_SP, + span: expr.span, exprs, }); @@ -733,7 +739,7 @@ impl VisitMut for ReduceAst { Expr::Tpl(expr) => { let mut seq = Expr::Seq(SeqExpr { - span: DUMMY_SP, + span: expr.span, exprs: expr.exprs.take(), }); @@ -747,7 +753,7 @@ impl VisitMut for ReduceAst { preserve_pat_or_expr(&mut exprs, expr.left.take()); exprs.push(expr.right.take()); let mut seq = Expr::Seq(SeqExpr { - span: DUMMY_SP, + span: expr.span, exprs, }); @@ -770,7 +776,7 @@ impl VisitMut for ReduceAst { exprs.push(expr.right.take()); let mut seq = Expr::Seq(SeqExpr { - span: DUMMY_SP, + span: expr.span, exprs, }); @@ -787,7 +793,7 @@ impl VisitMut for ReduceAst { exprs.push(expr.alt.take()); let mut seq = Expr::Seq(SeqExpr { - span: DUMMY_SP, + span: expr.span, exprs, }); @@ -798,7 +804,7 @@ impl VisitMut for ReduceAst { Expr::Array(arr) => { let mut seq = Expr::Seq(SeqExpr { - span: DUMMY_SP, + span: arr.span, exprs: arr .elems .take() @@ -848,7 +854,7 @@ impl VisitMut for ReduceAst { } let mut seq = Expr::Seq(SeqExpr { - span: DUMMY_SP, + span: obj.span, exprs, }); @@ -881,6 +887,7 @@ impl VisitMut for ReduceAst { } Expr::Arrow(ArrowExpr { + span, params, body: BlockStmtOrExpr::Expr(body), .. @@ -892,10 +899,7 @@ impl VisitMut for ReduceAst { exprs.push(body.take()); - let mut seq = Expr::Seq(SeqExpr { - span: DUMMY_SP, - exprs, - }); + let mut seq = Expr::Seq(SeqExpr { span: *span, exprs }); seq.visit_mut_with(self); @@ -927,15 +931,14 @@ impl VisitMut for ReduceAst { } } - Expr::New(NewExpr { callee, args, .. }) => { + Expr::New(NewExpr { + span, callee, args, .. + }) => { let mut exprs = vec![]; exprs.push(callee.take()); exprs.extend(args.take().into_iter().flatten().map(|v| v.expr)); - *e = Expr::Seq(SeqExpr { - span: DUMMY_SP, - exprs, - }); + *e = Expr::Seq(SeqExpr { span: *span, exprs }); self.changed = true; return; } @@ -952,10 +955,7 @@ impl VisitMut for ReduceAst { *e = null_expr(*span); return; } - let seq = Expr::Seq(SeqExpr { - span: DUMMY_SP, - exprs, - }); + let seq = Expr::Seq(SeqExpr { span: *span, exprs }); *e = seq; } @@ -1021,7 +1021,7 @@ impl VisitMut for ReduceAst { s.init = None; } else { s.init = Some(VarDeclOrExpr::Expr(Box::new(Expr::Seq(SeqExpr { - span: DUMMY_SP, + span: v.span, exprs, })))) } @@ -1191,7 +1191,7 @@ impl VisitMut for ReduceAst { JSXExpr::JSXEmptyExpr(_) => {} JSXExpr::Expr(expr) => { if expr.is_invalid() { - *e = JSXExpr::JSXEmptyExpr(JSXEmptyExpr { span: DUMMY_SP }); + *e = JSXExpr::JSXEmptyExpr(JSXEmptyExpr { span: expr.span() }); } } } @@ -1441,7 +1441,7 @@ impl VisitMut for ReduceAst { fn visit_mut_stmt(&mut self, stmt: &mut Stmt) { match stmt { Stmt::Debugger(_) | Stmt::Break(_) | Stmt::Continue(_) => { - *stmt = Stmt::Empty(EmptyStmt { span: DUMMY_SP }); + *stmt = Stmt::Empty(EmptyStmt { span: stmt.span() }); return; } @@ -1449,18 +1449,18 @@ impl VisitMut for ReduceAst { if let Some(arg) = s.arg.take() { self.changed = true; *stmt = Stmt::Expr(ExprStmt { - span: DUMMY_SP, + span: s.span, expr: arg, }); } else { - *stmt = Stmt::Empty(EmptyStmt { span: DUMMY_SP }); + *stmt = Stmt::Empty(EmptyStmt { span: s.span }); return; } } Stmt::Throw(s) => { self.changed = true; *stmt = Stmt::Expr(ExprStmt { - span: DUMMY_SP, + span: s.span, expr: s.arg.take(), }); } @@ -1482,13 +1482,14 @@ impl VisitMut for ReduceAst { Stmt::Expr(e) => { if e.expr.is_invalid() { self.changed = true; - *stmt = Stmt::Empty(EmptyStmt { span: DUMMY_SP }); + *stmt = Stmt::Empty(EmptyStmt { span: e.span }); return; } match &mut *e.expr { // Optimize IIFE Expr::Call(CallExpr { + span, callee: ExprOrSuper::Expr(callee), args, .. @@ -1505,9 +1506,9 @@ impl VisitMut for ReduceAst { if !decorators.is_empty() { let mut s = Stmt::Expr(ExprStmt { - span: DUMMY_SP, + span: *span, expr: Box::new(Expr::Seq(SeqExpr { - span: DUMMY_SP, + span: *span, exprs: decorators.into_iter().map(|d| d.expr).collect(), })), }); @@ -1527,11 +1528,8 @@ impl VisitMut for ReduceAst { exprs.extend(args.into_iter().map(|arg| arg.expr.take())); let mut s = Stmt::Expr(ExprStmt { - span: DUMMY_SP, - expr: Box::new(Expr::Seq(SeqExpr { - span: DUMMY_SP, - exprs, - })), + span: *span, + expr: Box::new(Expr::Seq(SeqExpr { span: *span, exprs })), }); s.visit_mut_with(self); stmts.push(s); @@ -1541,10 +1539,7 @@ impl VisitMut for ReduceAst { stmts.extend(body.stmts); } - *stmt = Stmt::Block(BlockStmt { - span: DUMMY_SP, - stmts, - }); + *stmt = Stmt::Block(BlockStmt { span: *span, stmts }); return; } _ => {} @@ -1556,7 +1551,7 @@ impl VisitMut for ReduceAst { Stmt::Block(block) => { if block.stmts.is_empty() { - *stmt = Stmt::Empty(EmptyStmt { span: DUMMY_SP }); + *stmt = Stmt::Empty(EmptyStmt { span: block.span }); return; } if block.stmts.len() == 1 { @@ -1575,12 +1570,12 @@ impl VisitMut for ReduceAst { } if exprs.is_empty() { - *stmt = Stmt::Empty(EmptyStmt { span: DUMMY_SP }); + *stmt = Stmt::Empty(EmptyStmt { span: var.span }); } else { *stmt = Stmt::Expr(ExprStmt { - span: DUMMY_SP, + span: var.span, expr: Box::new(Expr::Seq(SeqExpr { - span: DUMMY_SP, + span: var.span, exprs, })), }); @@ -1597,7 +1592,7 @@ impl VisitMut for ReduceAst { // if self.can_remove(&is.test, true) { if is.cons.is_empty() && is.alt.is_empty() { - *stmt = Stmt::Empty(EmptyStmt { span: DUMMY_SP }); + *stmt = Stmt::Empty(EmptyStmt { span: is.span }); return; } @@ -1615,7 +1610,7 @@ impl VisitMut for ReduceAst { if is.cons.is_empty() && is.alt.is_empty() { self.changed = true; *stmt = Stmt::Expr(ExprStmt { - span: DUMMY_SP, + span: is.span, expr: is.test.take(), }); return; @@ -1625,7 +1620,7 @@ impl VisitMut for ReduceAst { Stmt::While(s) => { if s.body.is_empty() { *stmt = Stmt::Expr(ExprStmt { - span: DUMMY_SP, + span: s.span, expr: s.test.take(), }); self.changed = true; @@ -1642,7 +1637,7 @@ impl VisitMut for ReduceAst { Stmt::DoWhile(s) => { if s.body.is_empty() { *stmt = Stmt::Expr(ExprStmt { - span: DUMMY_SP, + span: s.test.span(), expr: s.test.take(), }); self.changed = true; @@ -1685,7 +1680,7 @@ impl VisitMut for ReduceAst { Stmt::Switch(s) => { if s.cases.is_empty() { *stmt = Stmt::Expr(ExprStmt { - span: DUMMY_SP, + span: s.span, expr: s.discriminant.take(), }); self.changed = true; @@ -1710,14 +1705,15 @@ impl VisitMut for ReduceAst { let mut stmts = ts.block.stmts.take(); if let Some(h) = ts.handler.take() { if let Some(p) = h.param { + let p_span = p.span(); let mut exprs = vec![]; preserve_pat(&mut exprs, p); if !exprs.is_empty() { stmts.push(Stmt::Expr(ExprStmt { - span: DUMMY_SP, + span: p_span, expr: Box::new(Expr::Seq(SeqExpr { - span: DUMMY_SP, + span: p_span, exprs, })), })); @@ -1731,13 +1727,14 @@ impl VisitMut for ReduceAst { } *stmt = Stmt::Block(BlockStmt { - span: DUMMY_SP, + span: ts.span, stmts, }); return; } Stmt::For(ForStmt { + span, init, test, update, @@ -1769,21 +1766,15 @@ impl VisitMut for ReduceAst { if !exprs.is_empty() { stmts.push(Stmt::Expr(ExprStmt { - span: DUMMY_SP, - expr: Box::new(Expr::Seq(SeqExpr { - span: DUMMY_SP, - exprs, - })), + span: *span, + expr: Box::new(Expr::Seq(SeqExpr { span: *span, exprs })), })); } } stmts.push(*body.take()); - *stmt = Stmt::Block(BlockStmt { - span: DUMMY_SP, - stmts, - }); + *stmt = Stmt::Block(BlockStmt { span: *span, stmts }); return; } diff --git a/crates/swc_webpack_ast/tests/fixture/react-dom/2/input.js b/crates/swc_webpack_ast/tests/fixture/react-dom/2/input.js new file mode 100644 index 000000000000..631c99309d0c --- /dev/null +++ b/crates/swc_webpack_ast/tests/fixture/react-dom/2/input.js @@ -0,0 +1,38 @@ +'use strict'; + +function checkDCE() { + /* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */ + if ( + typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined' || + typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE !== 'function' + ) { + return; + } + if (process.env.NODE_ENV !== 'production') { + // This branch is unreachable because this function is only called + // in production, but the condition is true only in development. + // Therefore if the branch is still here, dead code elimination wasn't + // properly applied. + // Don't change the message. React DevTools relies on it. Also make sure + // this message doesn't occur elsewhere in this function, or it will cause + // a false positive. + throw new Error('^_^'); + } + try { + // Verify that the code above has been dead code eliminated (DCE'd). + __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(checkDCE); + } catch (err) { + // DevTools shouldn't crash React, no matter what. + // We should still report in case we break this code. + console.error(err); + } +} + +if (process.env.NODE_ENV === 'production') { + // DCE check should happen before ReactDOM bundle executes so that + // DevTools can report bad minification during injection. + checkDCE(); + module.exports = require('./cjs/react-dom.production.min.js'); +} else { + module.exports = require('./cjs/react-dom.development.js'); +} \ No newline at end of file diff --git a/crates/swc_webpack_ast/tests/fixture/react-dom/2/output.js b/crates/swc_webpack_ast/tests/fixture/react-dom/2/output.js new file mode 100644 index 000000000000..c08a8a210a66 --- /dev/null +++ b/crates/swc_webpack_ast/tests/fixture/react-dom/2/output.js @@ -0,0 +1,3 @@ +process.env.NODE_ENV !== "production"; +if (process.env.NODE_ENV === "production") module.exports, require("./cjs/react-dom.production.min.js"); +else module.exports, require("./cjs/react-dom.development.js");