Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(es/minifier): Respect pure_funcs for tagged tpls #8280

Merged
merged 7 commits into from
Nov 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions crates/swc/tests/fixture/issues-8xxx/8275/input/.swcrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"jsc": {
"parser": {
"syntax": "ecmascript",
"jsx": false
},
"target": "es2022",
"loose": false,
"minify": {
"compress": {
"pure_funcs": [
"pure_html"
]
},
"mangle": false
}
},
"module": {
"type": "es6"
},
"isModule": true
}
15 changes: 15 additions & 0 deletions crates/swc/tests/fixture/issues-8xxx/8275/input/1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*#__PURE__*/
function pure_html(strings, ...values) {
return { strings, values };
}

// ✅ This is tree-shaken from the minified output.
const a = `<span>aaaa</span>`;

// ❌ This is not tree-shaken from the minified output,
// despite the "html" function being declare using
// `jsc.minify.compress.pure_funcs` configuration.
const b = pure_html`<span>bbbb</span>`;

// ✅ This is not tree-shaken from the minified output.
export const c = pure_html`<span>cccc</span>`;
6 changes: 6 additions & 0 deletions crates/swc/tests/fixture/issues-8xxx/8275/output/1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const c = (function(strings, ...values) {
return {
strings,
values
};
})`<span>cccc</span>`;
41 changes: 28 additions & 13 deletions crates/swc_ecma_minifier/src/compress/pure/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -928,20 +928,35 @@ impl Pure<'_> {
_ => {}
}

if let Expr::Call(CallExpr {
callee: Callee::Expr(callee),
args,
..
}) = e
{
if callee.is_pure_callee(&self.expr_ctx) {
self.changed = true;
report_change!("Dropping pure call as callee is pure");
*e = self
.make_ignored_expr(args.take().into_iter().map(|arg| arg.expr))
.unwrap_or(Expr::Invalid(Invalid { span: DUMMY_SP }));
return;
match e {
Expr::Call(CallExpr {
callee: Callee::Expr(callee),
args,
..
}) => {
if callee.is_pure_callee(&self.expr_ctx) {
self.changed = true;
report_change!("Dropping pure call as callee is pure");
*e = self
.make_ignored_expr(args.take().into_iter().map(|arg| arg.expr))
.unwrap_or(Expr::Invalid(Invalid { span: DUMMY_SP }));
return;
}
}

Expr::TaggedTpl(TaggedTpl {
tag: callee, tpl, ..
}) => {
if callee.is_pure_callee(&self.expr_ctx) {
self.changed = true;
report_change!("Dropping pure tag tpl as callee is pure");
*e = self
.make_ignored_expr(tpl.exprs.take().into_iter())
.unwrap_or(Expr::Invalid(Invalid { span: DUMMY_SP }));
return;
}
}
_ => (),
}

if self.options.unused {
Expand Down
55 changes: 44 additions & 11 deletions crates/swc_ecma_minifier/src/metadata/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,39 @@ struct InfoMarker<'a> {
state: State,
}

impl InfoMarker<'_> {
fn is_pure_callee(&self, callee: &Expr) -> bool {
match callee {
Expr::Ident(callee) => {
if self.pure_callee.contains(&callee.to_id()) {
return true;
}
}

Expr::Seq(callee) => {
if has_pure(self.comments, callee.span) {
return true;
}
}
_ => (),
}

if let Some(pure_fns) = &self.pure_funcs {
if let Expr::Ident(..) = callee {
// Check for pure_funcs
if Ident::within_ignored_ctxt(|| {
//
pure_fns.contains(&NodeIgnoringSpan::borrowed(callee))
}) {
return true;
}
}
}

has_pure(self.comments, callee.span())
}
}

impl VisitMut for InfoMarker<'_> {
noop_visit_mut_type!();

Expand All @@ -71,19 +104,9 @@ impl VisitMut for InfoMarker<'_> {
// We check callee in some cases because we move comments
// See https://github.com/swc-project/swc/issues/7241
if match &n.callee {
Callee::Expr(e) => match &**e {
Expr::Ident(callee) => self.pure_callee.contains(&callee.to_id()),
_ => false,
},
Callee::Expr(e) => self.is_pure_callee(e),
_ => false,
} || has_pure(self.comments, n.span)
|| match &n.callee {
Callee::Expr(e) => match &**e {
Expr::Seq(callee) => has_pure(self.comments, callee.span),
_ => false,
},
_ => false,
}
{
if !n.span.is_dummy_ignoring_cmt() {
n.span = n.span.apply_mark(self.marks.pure);
Expand Down Expand Up @@ -185,6 +208,16 @@ impl VisitMut for InfoMarker<'_> {
}
}

fn visit_mut_tagged_tpl(&mut self, n: &mut TaggedTpl) {
n.visit_mut_children_with(self);

if has_pure(self.comments, n.span) || self.is_pure_callee(&n.tag) {
if !n.span.is_dummy_ignoring_cmt() {
n.span = n.span.apply_mark(self.marks.pure);
}
}
}

fn visit_mut_var_decl(&mut self, n: &mut VarDecl) {
n.visit_mut_children_with(self);

Expand Down
Loading