mirror of
https://github.com/swc-project/swc.git
synced 2024-12-23 21:54:36 +03:00
fix(es/minifier): Fix minifier (#1985)
swc_ecma_minifier: - Don't create an identifier starting with number. (#1983) - Fix panic. (#1984) - Don't use time api on wasm. (#1982)
This commit is contained in:
parent
d600d52157
commit
be23e66ca8
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -2502,7 +2502,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "swc_ecma_minifier"
|
||||
version = "0.16.0"
|
||||
version = "0.16.1"
|
||||
dependencies = [
|
||||
"ansi_term 0.12.1",
|
||||
"anyhow",
|
||||
@ -3197,7 +3197,7 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
||||
|
||||
[[package]]
|
||||
name = "wasm"
|
||||
version = "1.2.69"
|
||||
version = "1.2.70"
|
||||
dependencies = [
|
||||
"console_error_panic_hook",
|
||||
"once_cell",
|
||||
|
@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs", "src/lists/*.json"]
|
||||
license = "Apache-2.0/MIT"
|
||||
name = "swc_ecma_minifier"
|
||||
repository = "https://github.com/swc-project/swc.git"
|
||||
version = "0.16.0"
|
||||
version = "0.16.1"
|
||||
|
||||
[features]
|
||||
debug = []
|
||||
|
@ -1,6 +1,7 @@
|
||||
use self::ctx::Ctx;
|
||||
use crate::util::can_end_conditionally;
|
||||
use crate::util::idents_used_by;
|
||||
use crate::util::now;
|
||||
use fxhash::FxHashMap;
|
||||
use fxhash::FxHashSet;
|
||||
use std::collections::hash_map::Entry;
|
||||
@ -25,7 +26,7 @@ pub(crate) fn analyze<N>(n: &N) -> ProgramData
|
||||
where
|
||||
N: VisitWith<UsageAnalyzer>,
|
||||
{
|
||||
let start_time = Instant::now();
|
||||
let start_time = now();
|
||||
|
||||
let mut v = UsageAnalyzer {
|
||||
data: Default::default(),
|
||||
@ -36,9 +37,11 @@ where
|
||||
let top_scope = v.scope;
|
||||
v.data.top.merge(top_scope, false);
|
||||
|
||||
let end_time = Instant::now();
|
||||
if let Some(start_time) = start_time {
|
||||
let end_time = Instant::now();
|
||||
|
||||
log::debug!("Scope analysis took {:?}", end_time - start_time);
|
||||
log::debug!("Scope analysis took {:?}", end_time - start_time);
|
||||
}
|
||||
|
||||
v.data
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ use crate::debug::dump;
|
||||
use crate::debug::invoke;
|
||||
use crate::marks::Marks;
|
||||
use crate::option::CompressOptions;
|
||||
use crate::util::now;
|
||||
use crate::util::Optional;
|
||||
#[cfg(feature = "pretty_assertions")]
|
||||
use pretty_assertions::assert_eq;
|
||||
@ -157,7 +158,7 @@ impl VisitMut for Compressor<'_> {
|
||||
self.pass
|
||||
);
|
||||
|
||||
let start_time = Instant::now();
|
||||
let start_time = now();
|
||||
|
||||
let mut visitor = expr_simplifier();
|
||||
n.visit_mut_with(&mut visitor);
|
||||
@ -169,13 +170,15 @@ impl VisitMut for Compressor<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
let end_time = Instant::now();
|
||||
if let Some(start_time) = start_time {
|
||||
let end_time = Instant::now();
|
||||
|
||||
log::info!(
|
||||
"compress: expr_simplifier took {:?} (pass = {})",
|
||||
end_time - start_time,
|
||||
self.pass
|
||||
);
|
||||
log::info!(
|
||||
"compress: expr_simplifier took {:?} (pass = {})",
|
||||
end_time - start_time,
|
||||
self.pass
|
||||
);
|
||||
}
|
||||
|
||||
if cfg!(feature = "debug") && !visitor.changed() {
|
||||
let simplified = dump(&n.clone().fold_with(&mut fixer(None)));
|
||||
@ -193,7 +196,7 @@ impl VisitMut for Compressor<'_> {
|
||||
{
|
||||
log::info!("compress: Running optimizer (pass = {})", self.pass);
|
||||
|
||||
let start_time = Instant::now();
|
||||
let start_time = now();
|
||||
// TODO: reset_opt_flags
|
||||
//
|
||||
// This is swc version of `node.optimize(this);`.
|
||||
@ -207,13 +210,15 @@ impl VisitMut for Compressor<'_> {
|
||||
n.visit_mut_with(&mut visitor);
|
||||
self.changed |= visitor.changed();
|
||||
|
||||
let end_time = Instant::now();
|
||||
if let Some(start_time) = start_time {
|
||||
let end_time = Instant::now();
|
||||
|
||||
log::info!(
|
||||
"compress: Optimizer took {:?} (pass = {})",
|
||||
end_time - start_time,
|
||||
self.pass
|
||||
);
|
||||
log::info!(
|
||||
"compress: Optimizer took {:?} (pass = {})",
|
||||
end_time - start_time,
|
||||
self.pass
|
||||
);
|
||||
}
|
||||
// let done = dump(&*n);
|
||||
// log::debug!("===== Result =====\n{}", done);
|
||||
}
|
||||
@ -225,12 +230,20 @@ impl VisitMut for Compressor<'_> {
|
||||
"".into()
|
||||
};
|
||||
|
||||
let start_time = Instant::now();
|
||||
let start_time = now();
|
||||
|
||||
let mut v = dead_branch_remover();
|
||||
n.map_with_mut(|n| n.fold_with(&mut v));
|
||||
|
||||
let end_time = Instant::now();
|
||||
if let Some(start_time) = start_time {
|
||||
let end_time = Instant::now();
|
||||
|
||||
log::info!(
|
||||
"compress: dead_branch_remover took {:?} (pass = {})",
|
||||
end_time - start_time,
|
||||
self.pass
|
||||
);
|
||||
}
|
||||
|
||||
if cfg!(feature = "debug") {
|
||||
let simplified = dump(&*n);
|
||||
@ -244,12 +257,6 @@ impl VisitMut for Compressor<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
log::info!(
|
||||
"compress: dead_branch_remover took {:?} (pass = {})",
|
||||
end_time - start_time,
|
||||
self.pass
|
||||
);
|
||||
|
||||
self.changed |= v.changed();
|
||||
}
|
||||
|
||||
|
@ -681,6 +681,8 @@ impl Optimizer<'_> {
|
||||
if cons.callee.eq_ignore_span(&alt.callee) {
|
||||
if cons.args.as_ref().map(|v| v.len() <= 1).unwrap_or(true)
|
||||
&& alt.args.as_ref().map(|v| v.len() <= 1).unwrap_or(true)
|
||||
&& cons.args.as_ref().map(|v| v.len()).unwrap_or(0)
|
||||
== alt.args.as_ref().map(|v| v.len()).unwrap_or(0)
|
||||
&& (cons.args.is_some()
|
||||
&& cons
|
||||
.args
|
||||
@ -698,15 +700,17 @@ impl Optimizer<'_> {
|
||||
{
|
||||
let mut args = vec![];
|
||||
|
||||
args.push(ExprOrSpread {
|
||||
spread: None,
|
||||
expr: Box::new(Expr::Cond(CondExpr {
|
||||
span: DUMMY_SP,
|
||||
test: test.take(),
|
||||
cons: cons.args.as_mut().unwrap()[0].expr.take(),
|
||||
alt: alt.args.as_mut().unwrap()[0].expr.take(),
|
||||
})),
|
||||
});
|
||||
if cons.args.as_ref().map(|v| v.len()).unwrap_or(0) == 1 {
|
||||
args.push(ExprOrSpread {
|
||||
spread: None,
|
||||
expr: Box::new(Expr::Cond(CondExpr {
|
||||
span: DUMMY_SP,
|
||||
test: test.take(),
|
||||
cons: cons.args.as_mut().unwrap()[0].expr.take(),
|
||||
alt: alt.args.as_mut().unwrap()[0].expr.take(),
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
log::debug!(
|
||||
"Compreessing if statement into a condiotnal expression of `new` as \
|
||||
|
@ -25,6 +25,7 @@ pub use crate::pass::hygiene::optimize_hygiene;
|
||||
use crate::pass::mangle_names::name_mangler;
|
||||
use crate::pass::mangle_props::mangle_properties;
|
||||
use crate::pass::precompress::precompress_optimizer;
|
||||
use crate::util::now;
|
||||
use analyzer::analyze;
|
||||
use pass::postcompress::postcompress_optimizer;
|
||||
use std::time::Instant;
|
||||
@ -57,7 +58,7 @@ pub fn optimize(
|
||||
) -> Module {
|
||||
let marks = Marks::new();
|
||||
|
||||
let start = Instant::now();
|
||||
let start = now();
|
||||
if let Some(defs) = options.compress.as_ref().map(|c| &c.global_defs) {
|
||||
// Apply global defs.
|
||||
//
|
||||
@ -70,12 +71,16 @@ pub fn optimize(
|
||||
m.visit_mut_with(&mut global_defs::globals_defs(defs, extra.top_level_mark));
|
||||
}
|
||||
}
|
||||
log::info!("global_defs took {:?}", Instant::now() - start);
|
||||
if let Some(start) = start {
|
||||
log::info!("global_defs took {:?}", Instant::now() - start);
|
||||
}
|
||||
|
||||
if let Some(options) = &options.compress {
|
||||
let start = Instant::now();
|
||||
let start = now();
|
||||
m.visit_mut_with(&mut precompress_optimizer(options.clone()));
|
||||
log::info!("precompress took {:?}", Instant::now() - start);
|
||||
if let Some(start) = start {
|
||||
log::info!("precompress took {:?}", Instant::now() - start);
|
||||
}
|
||||
}
|
||||
|
||||
m.visit_mut_with(&mut unique_marker());
|
||||
@ -108,14 +113,18 @@ pub fn optimize(
|
||||
t.section("compress");
|
||||
}
|
||||
if let Some(options) = &options.compress {
|
||||
let start = Instant::now();
|
||||
let start = now();
|
||||
m = m.fold_with(&mut compressor(cm.clone(), marks, &options, comments));
|
||||
log::info!("compressor took {:?}", Instant::now() - start);
|
||||
if let Some(start) = start {
|
||||
log::info!("compressor took {:?}", Instant::now() - start);
|
||||
}
|
||||
// Again, we don't need to validate ast
|
||||
|
||||
let start = Instant::now();
|
||||
let start = now();
|
||||
m.visit_mut_with(&mut postcompress_optimizer(options));
|
||||
log::info!("postcompressor took {:?}", Instant::now() - start);
|
||||
if let Some(start) = start {
|
||||
log::info!("postcompressor took {:?}", Instant::now() - start);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref mut _t) = timings {
|
||||
|
@ -4,6 +4,7 @@ use crate::analyzer::analyze;
|
||||
use crate::analyzer::ProgramData;
|
||||
use crate::pass::hygiene::analyzer::HygieneAnalyzer;
|
||||
use crate::pass::hygiene::analyzer::HygieneData;
|
||||
use crate::util::now;
|
||||
use swc_common::Mark;
|
||||
use swc_common::SyntaxContext;
|
||||
use swc_common::DUMMY_SP;
|
||||
@ -70,7 +71,7 @@ impl VisitMut for Optimizer {
|
||||
|
||||
fn visit_mut_module(&mut self, n: &mut Module) {
|
||||
log::info!("hygiene: Analyzing span hygiene");
|
||||
let start = Instant::now();
|
||||
let start = now();
|
||||
|
||||
let mut analyzer = HygieneAnalyzer {
|
||||
data: &self.data,
|
||||
@ -81,13 +82,18 @@ impl VisitMut for Optimizer {
|
||||
n.visit_with(&Invalid { span: DUMMY_SP }, &mut analyzer);
|
||||
self.hygiene = analyzer.hygiene;
|
||||
|
||||
let end = Instant::now();
|
||||
log::info!("hygiene: Span hygiene analysis took {:?}", end - start);
|
||||
let start = end;
|
||||
if let Some(start) = start {
|
||||
let end = Instant::now();
|
||||
log::info!("hygiene: Span hygiene analysis took {:?}", end - start);
|
||||
}
|
||||
let start = now();
|
||||
|
||||
log::info!("hygiene: Optimizing span hygiene");
|
||||
n.visit_mut_children_with(self);
|
||||
let end = Instant::now();
|
||||
log::info!("hygiene: Span hygiene optimiation took {:?}", end - start);
|
||||
|
||||
if let Some(start) = start {
|
||||
let end = Instant::now();
|
||||
log::info!("hygiene: Span hygiene optimiation took {:?}", end - start);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -56,7 +56,15 @@ impl Mangler {
|
||||
}
|
||||
|
||||
loop {
|
||||
let sym: JsWord = base54(self.n).into();
|
||||
let sym = match base54(self.n) {
|
||||
Some(v) => v,
|
||||
None => {
|
||||
self.n += 1;
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let sym: JsWord = sym.into();
|
||||
self.n += 1;
|
||||
if self.preserved_symbols.contains(&sym) {
|
||||
continue;
|
||||
@ -75,12 +83,22 @@ impl Mangler {
|
||||
let new_sym = if let Some(cached) = self.renamed_private.get(&id) {
|
||||
cached.clone()
|
||||
} else {
|
||||
let sym: JsWord = base54(self.private_n).into();
|
||||
self.private_n += 1;
|
||||
loop {
|
||||
let sym = match base54(self.private_n) {
|
||||
Some(v) => v,
|
||||
None => {
|
||||
self.private_n += 1;
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
self.renamed_private.insert(id.clone(), sym.clone());
|
||||
let sym: JsWord = sym.into();
|
||||
self.private_n += 1;
|
||||
|
||||
sym
|
||||
self.renamed_private.insert(id.clone(), sym.clone());
|
||||
|
||||
break sym;
|
||||
}
|
||||
};
|
||||
|
||||
private_name.id.sym = new_sym;
|
||||
|
@ -91,11 +91,20 @@ impl ManglePropertiesState {
|
||||
if let Some(cached) = self.cache.get(name) {
|
||||
Some(cached.clone())
|
||||
} else {
|
||||
let n = self.n;
|
||||
self.n += 1;
|
||||
let mangled_name: JsWord = base54(n).into();
|
||||
self.cache.insert(name.clone(), mangled_name.clone());
|
||||
Some(mangled_name)
|
||||
loop {
|
||||
let n = self.n;
|
||||
self.n += 1;
|
||||
let sym = match base54(n) {
|
||||
Some(v) => v,
|
||||
None => {
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let mangled_name: JsWord = sym.into();
|
||||
self.cache.insert(name.clone(), mangled_name.clone());
|
||||
return Some(mangled_name);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
|
@ -1,6 +1,8 @@
|
||||
use std::io::{self, Write};
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use crate::util::now;
|
||||
|
||||
/// TOOD: Add timings.
|
||||
#[derive(Default, Debug)]
|
||||
pub struct Timings {
|
||||
@ -18,7 +20,7 @@ impl Timings {
|
||||
pub fn section(&mut self, name: &str) {
|
||||
self.end_section();
|
||||
|
||||
self.current_section = Some((String::from(name), Instant::now()));
|
||||
self.current_section = now().map(|now| (String::from(name), now));
|
||||
}
|
||||
|
||||
pub fn end_section(&mut self) {
|
||||
|
@ -1,7 +1,10 @@
|
||||
const CHARS: &[u8] = b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
|
||||
/// Note: This returns `a` for 0.
|
||||
pub(crate) fn base54(mut n: usize) -> String {
|
||||
///
|
||||
/// Returns [None] if the value is is not a valid ideitifer.
|
||||
pub(crate) fn base54(init: usize) -> Option<String> {
|
||||
let mut n = init;
|
||||
let mut ret = String::new();
|
||||
let mut base = 54;
|
||||
|
||||
@ -10,10 +13,21 @@ pub(crate) fn base54(mut n: usize) -> String {
|
||||
while n > 0 {
|
||||
n -= 1;
|
||||
|
||||
ret.push(CHARS[n % base] as char);
|
||||
let c = CHARS[n % base] as char;
|
||||
|
||||
if ret.is_empty() && c.is_digit(10) {
|
||||
return None;
|
||||
}
|
||||
|
||||
ret.push(c);
|
||||
|
||||
n = n / base;
|
||||
base = 64;
|
||||
}
|
||||
|
||||
ret
|
||||
if ret == "do" {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(ret)
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
use std::time::Instant;
|
||||
|
||||
use fxhash::FxHashSet;
|
||||
use swc_common::pass::CompilerPass;
|
||||
use swc_common::pass::Repeated;
|
||||
@ -475,3 +477,11 @@ pub(crate) fn can_end_conditionally(s: &Stmt) -> bool {
|
||||
|
||||
can_end(s, true)
|
||||
}
|
||||
|
||||
pub fn now() -> Option<Instant> {
|
||||
if cfg!(target_arch = "wasm32") {
|
||||
None
|
||||
} else {
|
||||
Some(Instant::now())
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@swc/core",
|
||||
"version": "1.2.69",
|
||||
"version": "1.2.70",
|
||||
"description": "Super-fast alternative for babel",
|
||||
"homepage": "https://swc.rs",
|
||||
"main": "./index.js",
|
||||
|
@ -715,3 +715,27 @@ fn tests(dir: PathBuf) {
|
||||
.map(|_| ())
|
||||
.expect("failed");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn issue_1984() {
|
||||
testing::run_test2(false, |cm, handler| {
|
||||
let c = Compiler::new(cm.clone(), Arc::new(handler));
|
||||
let fm = c.cm.new_source_file(
|
||||
FileName::Anon,
|
||||
"
|
||||
function Set() {}
|
||||
function useSelection(selectionType, derivedHalfSelectedKeys) {
|
||||
return selectionType === 'radio'
|
||||
? new Set()
|
||||
: new Set(derivedHalfSelectedKeys);
|
||||
}
|
||||
"
|
||||
.into(),
|
||||
);
|
||||
|
||||
c.minify(fm, &serde_json::from_str("{}").unwrap()).unwrap();
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ license = "Apache-2.0 AND MIT"
|
||||
name = "wasm"
|
||||
publish = false
|
||||
repository = "https://github.com/swc-project/swc.git"
|
||||
version = "1.2.69"
|
||||
version = "1.2.70"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
Loading…
Reference in New Issue
Block a user