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

**Related issue:**

 - Closes #8275.
This commit is contained in:
Donny/강동윤 2023-11-15 04:59:15 +09:00 committed by GitHub
parent 2f6af92232
commit 1ccfc0762c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 115 additions and 24 deletions

View File

@ -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
}

View File

@ -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>`;

View File

@ -0,0 +1,6 @@
export const c = (function(strings, ...values) {
return {
strings,
values
};
})`<span>cccc</span>`;

View File

@ -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 {

View File

@ -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!();
@ -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);
@ -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);