From 968fde6d9636fb672cd4c892a15694d2f8cddad6 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig <4586894+mischnic@users.noreply.github.com> Date: Wed, 9 Mar 2022 05:23:24 +0100 Subject: [PATCH] Replace typeof before DCE (#7788) --- .../test/integration/falsy-dep/index.js | 18 +++++++ packages/transformers/js/core/src/hoist.rs | 25 --------- packages/transformers/js/core/src/lib.rs | 6 +++ .../js/core/src/typeof_replacer.rs | 52 +++++++++++++++++++ 4 files changed, 76 insertions(+), 25 deletions(-) create mode 100644 packages/transformers/js/core/src/typeof_replacer.rs diff --git a/packages/core/integration-tests/test/integration/falsy-dep/index.js b/packages/core/integration-tests/test/integration/falsy-dep/index.js index d42ce74b972..9043f103482 100644 --- a/packages/core/integration-tests/test/integration/falsy-dep/index.js +++ b/packages/core/integration-tests/test/integration/falsy-dep/index.js @@ -24,4 +24,22 @@ if (process.env.NODE_ENV !== 'test') { require('./true-alternate'); } +if (typeof require === "function") { + require('./true-consequent'); +} else { + require('./false-alternate'); +} + +if (typeof exports === "object") { + require('./true-consequent'); +} else { + require('./false-alternate'); +} + +if (typeof module === "object") { + require('./true-consequent'); +} else { + require('./false-alternate'); +} + module.exports = 2; diff --git a/packages/transformers/js/core/src/hoist.rs b/packages/transformers/js/core/src/hoist.rs index 3d3eb58f331..02e17bce0b1 100644 --- a/packages/transformers/js/core/src/hoist.rs +++ b/packages/transformers/js/core/src/hoist.rs @@ -693,31 +693,6 @@ impl<'a> Fold for Hoist<'a> { } } } - Expr::Unary(ref unary) => { - // typeof require -> "function" - // typeof module -> "object" - if unary.op == UnaryOp::TypeOf { - if let Expr::Ident(ident) = &*unary.arg { - if ident.sym == js_word!("require") && !self.collect.decls.contains(&id!(ident)) { - return Expr::Lit(Lit::Str(Str { - kind: StrKind::Synthesized, - has_escape: false, - span: unary.span, - value: js_word!("function"), - })); - } - - if ident.sym == js_word!("module") && !self.collect.decls.contains(&id!(ident)) { - return Expr::Lit(Lit::Str(Str { - kind: StrKind::Synthesized, - has_escape: false, - span: unary.span, - value: js_word!("object"), - })); - } - } - } - } _ => {} } diff --git a/packages/transformers/js/core/src/lib.rs b/packages/transformers/js/core/src/lib.rs index 58ba9bd4cea..3e9c161f629 100644 --- a/packages/transformers/js/core/src/lib.rs +++ b/packages/transformers/js/core/src/lib.rs @@ -18,6 +18,7 @@ mod fs; mod global_replacer; mod hoist; mod modules; +mod typeof_replacer; mod utils; use std::collections::{HashMap, HashSet}; @@ -49,6 +50,7 @@ use fs::inline_fs; use global_replacer::GlobalReplacer; use hoist::{hoist, CollectResult, HoistResult}; use modules::esm2cjs; +use typeof_replacer::*; use utils::{CodeHighlight, Diagnostic, DiagnosticSeverity, SourceLocation, SourceType}; use crate::hoist::Collect; @@ -321,6 +323,10 @@ pub fn transform(config: Config) -> Result { let mut diagnostics = vec![]; let module = { let mut passes = chain!( + Optional::new( + TypeofReplacer { decls: &decls }, + config.source_type != SourceType::Script + ), // Inline process.env and process.browser Optional::new( EnvReplacer { diff --git a/packages/transformers/js/core/src/typeof_replacer.rs b/packages/transformers/js/core/src/typeof_replacer.rs new file mode 100644 index 00000000000..f76c1fa8bf7 --- /dev/null +++ b/packages/transformers/js/core/src/typeof_replacer.rs @@ -0,0 +1,52 @@ +use std::collections::HashSet; + +use swc_atoms::JsWord; +use swc_ecmascript::ast::{Expr, Lit, Str, StrKind, UnaryOp}; +use swc_ecmascript::visit::{Fold, FoldWith}; + +use crate::id; +use crate::utils::IdentId; + +pub struct TypeofReplacer<'a> { + pub decls: &'a HashSet, +} + +impl<'a> Fold for TypeofReplacer<'a> { + fn fold_expr(&mut self, node: Expr) -> Expr { + if let Expr::Unary(ref unary) = node { + // typeof require -> "function" + // typeof module -> "object" + if unary.op == UnaryOp::TypeOf { + if let Expr::Ident(ident) = &*unary.arg { + if ident.sym == js_word!("require") && !self.decls.contains(&id!(ident)) { + return Expr::Lit(Lit::Str(Str { + kind: StrKind::Synthesized, + has_escape: false, + span: unary.span, + value: js_word!("function"), + })); + } + let exports: JsWord = "exports".into(); + if ident.sym == exports && !self.decls.contains(&id!(ident)) { + return Expr::Lit(Lit::Str(Str { + kind: StrKind::Synthesized, + has_escape: false, + span: unary.span, + value: js_word!("object"), + })); + } + + if ident.sym == js_word!("module") && !self.decls.contains(&id!(ident)) { + return Expr::Lit(Lit::Str(Str { + kind: StrKind::Synthesized, + has_escape: false, + span: unary.span, + value: js_word!("object"), + })); + } + } + } + } + node.fold_children_with(self) + } +}