Skip to content

Commit

Permalink
fix(es/minifier): Fix top-level check (#8583)
Browse files Browse the repository at this point in the history
**Description:**

Our logic for checking top-level was wrong.
  • Loading branch information
kdy1 committed Feb 2, 2024
1 parent ef21736 commit a7c5255
Show file tree
Hide file tree
Showing 15 changed files with 120 additions and 126 deletions.
16 changes: 13 additions & 3 deletions crates/swc_ecma_minifier/src/compress/optimize/mod.rs
Expand Up @@ -178,8 +178,8 @@ struct Ctx {

impl Ctx {
pub fn is_top_level_for_block_level_vars(self) -> bool {
if self.top_level {
return true;
if !self.top_level {
return false;
}

if self.in_fn_like || self.in_block {
Expand Down Expand Up @@ -1663,6 +1663,7 @@ impl VisitMut for Optimizer<'_> {
}
}

#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
fn visit_mut_class_expr(&mut self, e: &mut ClassExpr) {
if !self.options.keep_classnames {
if e.ident.is_some() && !contains_eval(&e.class, true) {
Expand Down Expand Up @@ -2255,6 +2256,7 @@ impl VisitMut for Optimizer<'_> {
}
}

#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
fn visit_mut_module_item(&mut self, s: &mut ModuleItem) {
s.visit_mut_children_with(self);

Expand All @@ -2269,8 +2271,14 @@ impl VisitMut for Optimizer<'_> {
}
}

#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
fn visit_mut_script(&mut self, s: &mut Script) {
s.visit_mut_children_with(self);
let ctx = Ctx {
top_level: true,
skip_standalone: true,
..self.ctx
};
s.visit_mut_children_with(&mut *self.with_ctx(ctx));

if self.vars.inline_with_multi_replacer(s) {
self.changed = true;
Expand All @@ -2279,6 +2287,7 @@ impl VisitMut for Optimizer<'_> {
drop_invalid_stmts(&mut s.body);
}

#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
fn visit_mut_module_items(&mut self, stmts: &mut Vec<ModuleItem>) {
let ctx = Ctx {
top_level: true,
Expand Down Expand Up @@ -2701,6 +2710,7 @@ impl VisitMut for Optimizer<'_> {
debug_assert_valid(s);
}

#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
fn visit_mut_stmts(&mut self, stmts: &mut Vec<Stmt>) {
// Skip if `use asm` exists.
if maybe_par!(
Expand Down
2 changes: 1 addition & 1 deletion crates/swc_ecma_minifier/src/option/mod.rs
Expand Up @@ -352,7 +352,7 @@ impl CompressOptions {
return true;
}

self.top_level.map(|v| v.functions).unwrap_or(false)
self.top_level.map(|v| v.functions).unwrap_or(false) || self.module
}
}

Expand Down
12 changes: 10 additions & 2 deletions crates/swc_ecma_minifier/tests/compress.rs
Expand Up @@ -31,7 +31,7 @@ use swc_ecma_minifier::{
optimize,
option::{
terser::TerserCompressorOptions, CompressOptions, ExtraOptions, MangleOptions,
MinifyOptions,
MinifyOptions, TopLevelOptions,
},
};
use swc_ecma_parser::{
Expand Down Expand Up @@ -150,7 +150,7 @@ fn run(
HANDLER.set(handler, || {
let disable_hygiene = mangle.is_some() || skip_hygiene;

let (_module, config) = parse_compressor_config(cm.clone(), config);
let (_module, mut config) = parse_compressor_config(cm.clone(), config);

let fm = cm.load_file(input).expect("failed to load input.js");
let comments = SingleThreadedComments::default();
Expand Down Expand Up @@ -213,6 +213,14 @@ fn run(
_ => return None,
};

if config.top_level.is_none() {
if program.is_module() {
config.top_level = Some(TopLevelOptions { functions: true });
} else {
config.top_level = Some(TopLevelOptions { functions: false });
}
}

let optimization_start = Instant::now();
let mut output = optimize(
program,
Expand Down
5 changes: 2 additions & 3 deletions crates/swc_ecma_minifier/tests/fixture/issues/7402/output.js
Expand Up @@ -11,9 +11,8 @@ export const myFunc = function() {
return mutate(temp), out[0] = 1 / temp[0], out[1] = 1 / temp[1], out[2] = 1 / temp[2], out;
};
}();
const out = [
myFunc([
1,
2,
3
];
myFunc(out);
]);
@@ -1,6 +1,4 @@
import { m } from "../index.f66dda46.js";
const value$1 = "it works", value = "it works";
function AliasOutside() {
export default function() {
return m`<div><p>Inside: ${"it works"}</p><p>Outside: ${"it works"}</p></div>`;
}
export default AliasOutside;
@@ -1,5 +1,5 @@
import { _, m } from "../index.f66dda46.js";
class ClassFields extends _ {
export default class extends _ {
state = {
value: 1
};
Expand All @@ -12,4 +12,3 @@ class ClassFields extends _ {
return m`<div><p> State: <span>${this.state.value}</span></p><button onClick=${this.onClick}>click me</button></div>`;
}
}
export default ClassFields;
@@ -1,5 +1,5 @@
import { D, F, y, b as s } from "../index.f66dda46.js";
var isServerSide = "undefined" == typeof document, META = "M", TITLE = "T", LINK = "L", TEMPLATE = "P", SCRIPT = "S", applyTitleTemplate = function(title, template) {
var lang, linkQueue, scriptQueue, titleQueue, titleTemplateQueue, metaQueue, currentTitleIndex, currentTitleTemplateIndex, currentMetaIndex, timeout, processQueue, isServerSide = "undefined" == typeof document, applyTitleTemplate = function(title, template) {
return template ? template.replace(/%s/g, title || "") : title;
}, changeOrCreateMetaTag = function(meta) {
var result = document.head.querySelectorAll(meta.charset ? "meta[" + meta.keyword + "]" : "meta[" + meta.keyword + '="' + meta[meta.keyword] + '"]');
Expand All @@ -8,70 +8,67 @@ var isServerSide = "undefined" == typeof document, META = "M", TITLE = "T", LINK
var metaTag = document.createElement("meta");
meta.charset ? metaTag.setAttribute(meta.keyword, meta.charset) : (metaTag.setAttribute(meta.keyword, meta[meta.keyword]), metaTag.setAttribute("content", meta.content)), document.head.appendChild(metaTag);
}
}, createDispatcher = function() {
var timeout, lang, linkQueue = [], scriptQueue = [], titleQueue = [], titleTemplateQueue = [], metaQueue = [], currentTitleIndex = 0, currentTitleTemplateIndex = 0, currentMetaIndex = 0, processQueue = function() {
clearTimeout(timeout), timeout = setTimeout(function() {
timeout = null;
var visited = new Set();
document.title = applyTitleTemplate(titleQueue[0], titleTemplateQueue[0]), metaQueue.forEach(function(meta) {
visited.has(meta.charset ? meta.keyword : meta[meta.keyword]) || (visited.add(meta.charset ? meta.keyword : meta[meta.keyword]), changeOrCreateMetaTag(meta));
}), currentTitleIndex = currentTitleTemplateIndex = currentMetaIndex = 0;
}, 1000 / 60);
};
return {
_setLang: function(l) {
lang = l;
},
_addToQueue: function(type, payload) {
isServerSide || processQueue(), type === SCRIPT ? scriptQueue.push(payload) : type === TITLE ? titleQueue.splice(currentTitleIndex++, 0, payload) : type === TEMPLATE ? titleTemplateQueue.splice(currentTitleTemplateIndex++, 0, payload) : type === META ? metaQueue.splice(currentMetaIndex++, 0, payload) : linkQueue.push(payload);
},
_removeFromQueue: function(type, payload) {
if (type === TITLE || type === TEMPLATE) {
var queue = type === TEMPLATE ? titleTemplateQueue : titleQueue, index = queue.indexOf(payload);
queue.splice(index, 1), 0 === index && (document.title = applyTitleTemplate(titleQueue[0] || "", titleTemplateQueue[0]));
} else {
var oldMeta = metaQueue[metaQueue.indexOf(payload)];
if (oldMeta) {
metaQueue.splice(metaQueue.indexOf(payload), 1);
var newMeta = metaQueue.find(function(m) {
return m.keyword === oldMeta.keyword && (m.charset || m[m.keyword] === oldMeta[m.keyword]);
});
if (newMeta) changeOrCreateMetaTag(newMeta);
else {
var result = document.head.querySelectorAll(oldMeta.charset ? "meta[" + oldMeta.keyword + "]" : "meta[" + oldMeta.keyword + '="' + oldMeta[oldMeta.keyword] + '"]');
document.head.removeChild(result[0]);
}
}, defaultDispatcher = (linkQueue = [], scriptQueue = [], titleQueue = [], titleTemplateQueue = [], metaQueue = [], currentTitleIndex = 0, currentTitleTemplateIndex = 0, currentMetaIndex = 0, processQueue = function() {
clearTimeout(timeout), timeout = setTimeout(function() {
timeout = null;
var visited = new Set();
document.title = applyTitleTemplate(titleQueue[0], titleTemplateQueue[0]), metaQueue.forEach(function(meta) {
visited.has(meta.charset ? meta.keyword : meta[meta.keyword]) || (visited.add(meta.charset ? meta.keyword : meta[meta.keyword]), changeOrCreateMetaTag(meta));
}), currentTitleIndex = currentTitleTemplateIndex = currentMetaIndex = 0;
}, 1000 / 60);
}, {
_setLang: function(l) {
lang = l;
},
_addToQueue: function(type, payload) {
isServerSide || processQueue(), "S" === type ? scriptQueue.push(payload) : "T" === type ? titleQueue.splice(currentTitleIndex++, 0, payload) : "P" === type ? titleTemplateQueue.splice(currentTitleTemplateIndex++, 0, payload) : "M" === type ? metaQueue.splice(currentMetaIndex++, 0, payload) : linkQueue.push(payload);
},
_removeFromQueue: function(type, payload) {
if ("T" === type || "P" === type) {
var queue = "P" === type ? titleTemplateQueue : titleQueue, index = queue.indexOf(payload);
queue.splice(index, 1), 0 === index && (document.title = applyTitleTemplate(titleQueue[0] || "", titleTemplateQueue[0]));
} else {
var oldMeta = metaQueue[metaQueue.indexOf(payload)];
if (oldMeta) {
metaQueue.splice(metaQueue.indexOf(payload), 1);
var newMeta = metaQueue.find(function(m) {
return m.keyword === oldMeta.keyword && (m.charset || m[m.keyword] === oldMeta[m.keyword]);
});
if (newMeta) changeOrCreateMetaTag(newMeta);
else {
var result = document.head.querySelectorAll(oldMeta.charset ? "meta[" + oldMeta.keyword + "]" : "meta[" + oldMeta.keyword + '="' + oldMeta[oldMeta.keyword] + '"]');
document.head.removeChild(result[0]);
}
}
},
_change: function(type, prevPayload, payload) {
if (type === TITLE || type === TEMPLATE) {
var queue = type === TEMPLATE ? titleTemplateQueue : titleQueue;
queue[queue.indexOf(prevPayload)] = payload, 0 === queue.indexOf(payload) && (document.title = applyTitleTemplate(queue[queue.indexOf(payload)], titleTemplateQueue[0]));
} else changeOrCreateMetaTag(metaQueue[metaQueue.indexOf(prevPayload)] = payload);
},
_reset: void 0,
toStatic: function() {
var title = applyTitleTemplate(titleQueue[titleQueue.length - 1], titleTemplateQueue[titleTemplateQueue.length - 1]), visited = new Set(), links = [].concat(linkQueue), scripts = [].concat(scriptQueue);
metaQueue.reverse();
var metas = [].concat(metaQueue).filter(function(meta) {
if (!visited.has(meta.charset ? meta.keyword : meta[meta.keyword])) return visited.add(meta.charset ? meta.keyword : meta[meta.keyword]), !0;
});
return titleQueue = [], titleTemplateQueue = [], metaQueue = [], linkQueue = [], scriptQueue = [], currentTitleIndex = currentTitleTemplateIndex = currentMetaIndex = 0, {
lang: lang,
title: title,
links: links,
scripts: scripts,
metas: metas.map(function(meta) {
var _ref;
return "charset" === meta.keyword ? {
charset: meta[meta.keyword]
} : ((_ref = {})[meta.keyword] = meta[meta.keyword], _ref.content = meta.content, _ref);
})
};
}
};
}, defaultDispatcher = createDispatcher(), DispatcherContext = D(defaultDispatcher), useLang = function(language) {
},
_change: function(type, prevPayload, payload) {
if ("T" === type || "P" === type) {
var queue = "P" === type ? titleTemplateQueue : titleQueue;
queue[queue.indexOf(prevPayload)] = payload, 0 === queue.indexOf(payload) && (document.title = applyTitleTemplate(queue[queue.indexOf(payload)], titleTemplateQueue[0]));
} else changeOrCreateMetaTag(metaQueue[metaQueue.indexOf(prevPayload)] = payload);
},
_reset: void 0,
toStatic: function() {
var title = applyTitleTemplate(titleQueue[titleQueue.length - 1], titleTemplateQueue[titleTemplateQueue.length - 1]), visited = new Set(), links = [].concat(linkQueue), scripts = [].concat(scriptQueue);
metaQueue.reverse();
var metas = [].concat(metaQueue).filter(function(meta) {
if (!visited.has(meta.charset ? meta.keyword : meta[meta.keyword])) return visited.add(meta.charset ? meta.keyword : meta[meta.keyword]), !0;
});
return titleQueue = [], titleTemplateQueue = [], metaQueue = [], linkQueue = [], scriptQueue = [], currentTitleIndex = currentTitleTemplateIndex = currentMetaIndex = 0, {
lang: lang,
title: title,
links: links,
scripts: scripts,
metas: metas.map(function(meta) {
var _ref;
return "charset" === meta.keyword ? {
charset: meta[meta.keyword]
} : ((_ref = {})[meta.keyword] = meta[meta.keyword], _ref.content = meta.content, _ref);
})
};
}
}), DispatcherContext = D(defaultDispatcher), useLang = function(language) {
var dispatcher = F(DispatcherContext);
isServerSide && dispatcher._setLang(language), y(function() {
document.getElementsByTagName("html")[0].setAttribute("lang", language);
Expand All @@ -80,7 +77,7 @@ var isServerSide = "undefined" == typeof document, META = "M", TITLE = "T", LINK
]);
}, useLink = function(options) {
var dispatcher = F(DispatcherContext), hasMounted = s(!1), node = s(), originalOptions = s();
isServerSide && !hasMounted.current && dispatcher._addToQueue(LINK, options), y(function() {
isServerSide && !hasMounted.current && dispatcher._addToQueue("L", options), y(function() {
hasMounted.current && Object.keys(options).forEach(function(key) {
node.current.setAttribute(key, options[key]);
});
Expand Down Expand Up @@ -108,21 +105,17 @@ var isServerSide = "undefined" == typeof document, META = "M", TITLE = "T", LINK
}) : document.head.removeChild(node.current);
};
}, []);
};
function extractKeyword(meta) {
return meta.charset ? "charset" : meta.name ? "name" : meta.property ? "property" : "http-equiv";
}
var useMeta = function(options) {
}, useMeta = function(options) {
var dispatcher = F(DispatcherContext), hasMounted = s(!1), keyword = s(), metaObject = s({
keyword: keyword.current = extractKeyword(options),
keyword: keyword.current = options.charset ? "charset" : options.name ? "name" : options.property ? "property" : "http-equiv",
name: options.name,
charset: options.charset,
"http-equiv": options.httpEquiv,
property: options.property,
content: options.content
});
isServerSide && !hasMounted.current && dispatcher._addToQueue(META, metaObject.current), y(function() {
hasMounted.current && dispatcher._change(META, metaObject.current, metaObject.current = {
isServerSide && !hasMounted.current && dispatcher._addToQueue("M", metaObject.current), y(function() {
hasMounted.current && dispatcher._change("M", metaObject.current, metaObject.current = {
keyword: keyword.current,
name: options.name,
charset: options.charset,
Expand All @@ -133,20 +126,20 @@ var useMeta = function(options) {
}, [
options.content
]), y(function() {
return dispatcher._addToQueue(META, metaObject.current), hasMounted.current = !0, function() {
hasMounted.current = !1, dispatcher._removeFromQueue(META, metaObject.current);
return dispatcher._addToQueue("M", metaObject.current), hasMounted.current = !0, function() {
hasMounted.current = !1, dispatcher._removeFromQueue("M", metaObject.current);
};
}, []);
}, useTitle = function(title, template) {
var dispatcher = F(DispatcherContext), hasMounted = s(!1), prevTitle = s();
isServerSide && !hasMounted.current && dispatcher._addToQueue(template ? TEMPLATE : TITLE, title), y(function() {
hasMounted.current && dispatcher._change(template ? TEMPLATE : TITLE, prevTitle.current, prevTitle.current = title);
isServerSide && !hasMounted.current && dispatcher._addToQueue(template ? "P" : "T", title), y(function() {
hasMounted.current && dispatcher._change(template ? "P" : "T", prevTitle.current, prevTitle.current = title);
}, [
title,
template
]), y(function() {
return hasMounted.current = !0, dispatcher._addToQueue(template ? TEMPLATE : TITLE, prevTitle.current = title), function() {
hasMounted.current = !1, dispatcher._removeFromQueue(template ? TEMPLATE : TITLE, prevTitle.current);
return hasMounted.current = !0, dispatcher._addToQueue(template ? "P" : "T", prevTitle.current = title), function() {
hasMounted.current = !1, dispatcher._removeFromQueue(template ? "P" : "T", prevTitle.current);
};
}, [
template
Expand Down
@@ -1,6 +1,5 @@
import { m } from "../index.f66dda46.js";
const jpg = "/assets/img.2dae108d.jpg";
function Files() {
export default function() {
return m`<div style="padding: 2rem;"><h1>Files</h1><p> jpg: ${jpg}<br/><img src=${jpg} alt="" height="320"/></p></div>`;
}
export default Files;
@@ -1,14 +1,13 @@
import { s as style, m } from "../index.f66dda46.js";
import { m } from "../index.f66dda46.js";
const process = {
browser: !0,
env: {
FOO: "bar",
OVERRIDE: "11",
EMPTY: "",
FOO_LOCAL: "bar",
NODE_ENV: "production"
}
}, foo = 42;
};
function Environment() {
return m`<table><thead><tr><th>Name ${42}</th><th>Value</th></tr></thead><tbody>${Object.keys(process.env).sort().map((key)=>m`<tr key=${key}><td>${key}</td><td>${String(process.env[key])}</td></tr>`)}</tbody></table>`;
}
Expand Down
@@ -1,10 +1,6 @@
import { s as style, y, m } from "../index.f66dda46.js";
const styles = {
about: "about_migxty"
};
function About({ query, title }) {
import { y, m } from "../index.f66dda46.js";
export default function({ query, title }) {
return y(()=>(console.log("Mounted About: ", title), ()=>{
console.log("Unmounting About: ", title);
}), []), m`<section class=${"about_migxty"}><h1>${title || "About"}</h1><p>My name is Jason.</p><pre>${JSON.stringify(query)}</pre></section>`;
}
export default About;
@@ -1,10 +1,7 @@
import "../index.f66dda46.js";
import { t as toStatic } from "./hoofd.module.6c5395cb.js";
function prerender$1(vnode, options) {
return import("../prerender.daa73035/input.js").then((m)=>m.default(vnode, options));
}
async function prerender(vnode) {
const res = await prerender$1(vnode), head = toStatic(), elements = new Set([
const res = await import("../prerender.daa73035/input.js").then((m)=>m.default(vnode, void 0)), head = toStatic(), elements = new Set([
...head.links.map((props)=>({
type: "link",
props
Expand Down
@@ -1,9 +1,6 @@
function f() {
return 2;
}
console.log(
f(),
(function () {
return 3;
})()
);
console.log(f(), function() {
return 3;
}());

0 comments on commit a7c5255

Please sign in to comment.