diff --git a/crates/mako/src/build/transform.rs b/crates/mako/src/build/transform.rs index 66b1b668b..a406f7c99 100644 --- a/crates/mako/src/build/transform.rs +++ b/crates/mako/src/build/transform.rs @@ -49,6 +49,7 @@ use crate::visitors::try_resolve::TryResolve; use crate::visitors::ts_strip::ts_strip; use crate::visitors::tsx_strip::tsx_strip; use crate::visitors::virtual_css_modules::VirtualCSSModules; +use crate::visitors::webpack_runtime_replacement::WebpackRuntimeReplacement; use crate::visitors::worker_module::WorkerModule; pub struct Transform {} @@ -111,6 +112,7 @@ impl Transform { unresolved_mark, }), Box::new(WorkerModule::new(unresolved_mark)), + Box::new(WebpackRuntimeReplacement::new(unresolved_mark)), ]; // named default export diff --git a/crates/mako/src/visitors.rs b/crates/mako/src/visitors.rs index 1faca4174..0d40cb6a4 100644 --- a/crates/mako/src/visitors.rs +++ b/crates/mako/src/visitors.rs @@ -28,4 +28,5 @@ pub(crate) mod try_resolve; pub(crate) mod ts_strip; pub(crate) mod tsx_strip; pub(crate) mod virtual_css_modules; +pub(crate) mod webpack_runtime_replacement; pub(crate) mod worker_module; diff --git a/crates/mako/src/visitors/webpack_runtime_replacement.rs b/crates/mako/src/visitors/webpack_runtime_replacement.rs new file mode 100644 index 000000000..17d7c6131 --- /dev/null +++ b/crates/mako/src/visitors/webpack_runtime_replacement.rs @@ -0,0 +1,88 @@ +use swc_core::common::{Mark, DUMMY_SP}; +use swc_core::ecma::ast::{Expr, Ident, UnaryExpr}; +use swc_core::ecma::visit::{VisitMut, VisitMutWith}; + +pub const WEBPACK_VALUES: [&str; 14] = [ + "__webpack_get_script_filename__", + "__webpack_runtime_id__", + "__webpack_chunkname__", + "__webpack_nonce__", + "__webpack_init_sharing__", + "__webpack_share_scopes__", + "__system_context__", + "__non_webpack_require__", + "__webpack_require__", + "__webpack_hash__", + "__webpack_modules__", + "__webpack_module__", + "__webpack_chunk_load__", + "__webpack_base_uri__", +]; + +pub struct WebpackRuntimeReplacement { + pub unresolved_mark: Mark, +} + +impl WebpackRuntimeReplacement { + pub fn new(unresolved_mark: Mark) -> Self { + Self { unresolved_mark } + } + fn is_ident_webpack(&self, ident: &Ident, unresolved_mark: &Mark) -> bool { + WEBPACK_VALUES.iter().any(|&i| i == &ident.sym) && ident.ctxt.outer() == *unresolved_mark + } +} + +impl VisitMut for WebpackRuntimeReplacement { + // find the "typeof __webpack_require__" in the ast tree + fn visit_mut_unary_expr(&mut self, unary_expr: &mut UnaryExpr) { + if unary_expr.op.as_str() == "typeof" + && let Some(arg_ident) = unary_expr.arg.as_ident() + && self.is_ident_webpack(arg_ident, &self.unresolved_mark) + { + unary_expr.arg = Expr::undefined(DUMMY_SP) + } else { + unary_expr.visit_mut_children_with(self); + } + } +} + +#[cfg(test)] +mod tests { + use swc_core::common::GLOBALS; + use swc_core::ecma::visit::VisitMutWith; + + use super::WebpackRuntimeReplacement; + use crate::ast::tests::TestUtils; + + #[test] + fn test_webpack_require_ident() { + assert_eq!( + run(r#"typeof __webpack_require__ === 'function';"#), + r#"typeof void 0 === 'function';"# + ); + } + + #[test] + fn test_webpack_module_ident() { + assert_eq!(run(r#"typeof __webpack_modules__;"#), r#"typeof void 0;"#); + } + #[test] + fn test_dbcheck_webpack_module_ident() { + assert_eq!( + run(r#"typeof typeof __webpack_modules__;"#), + r#"typeof typeof void 0;"# + ); + } + + fn run(js_code: &str) -> String { + let mut test_utils = TestUtils::gen_js_ast(js_code); + let ast = test_utils.ast.js_mut(); + GLOBALS.set(&test_utils.context.meta.script.globals, || { + let mut visitor = WebpackRuntimeReplacement { + unresolved_mark: ast.unresolved_mark, + }; + ast.ast.visit_mut_with(&mut visitor); + }); + test_utils.js_ast_to_code() + } +}