Skip to content

Commit

Permalink
fix(ecma/minifier): compress bug for script
Browse files Browse the repository at this point in the history
  • Loading branch information
alexander-akait committed Nov 17, 2022
1 parent 99dfa22 commit d0968c1
Show file tree
Hide file tree
Showing 11 changed files with 149 additions and 19 deletions.
4 changes: 4 additions & 0 deletions crates/swc_ecma_minifier/src/compress/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,10 @@ where
self.optimize_unit_repeatedly(n);
}

fn visit_mut_script(&mut self, n: &mut Script) {
self.optimize_unit_repeatedly(n);
}

fn visit_mut_module_items(&mut self, stmts: &mut Vec<ModuleItem>) {
stmts.retain(|stmt| match stmt {
ModuleItem::Stmt(Stmt::Empty(..)) => false,
Expand Down
93 changes: 92 additions & 1 deletion crates/swc_ecma_minifier/src/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ where
///
/// If the cargo feature `debug` is disabled or the environment variable
/// `SWC_RUN` is not `1`, this function is noop.
pub(crate) fn invoke(module: &Module) {
pub(crate) fn invoke_module(module: &Module) {
debug_assert_valid(module);

let _noop_sub = tracing::subscriber::set_default(tracing::subscriber::NoSubscriber::default());
Expand Down Expand Up @@ -152,3 +152,94 @@ pub(crate) fn invoke(module: &Module) {
)
}
}

/// Invokes code using node.js.
///
/// If the cargo feature `debug` is disabled or the environment variable
/// `SWC_RUN` is not `1`, this function is noop.
pub(crate) fn invoke_script(script: &Script) {
debug_assert_valid(script);

let _noop_sub = tracing::subscriber::set_default(tracing::subscriber::NoSubscriber::default());

let should_run =
cfg!(debug_assertions) && cfg!(feature = "debug") && option_env!("SWC_RUN") == Some("1");
let should_check = cfg!(debug_assertions) && option_env!("SWC_CHECK") == Some("1");

if !should_run && !should_check {
return;
}

let script = script
.clone()
.fold_with(&mut hygiene())
.fold_with(&mut fixer(None));
let script = drop_span(script);

let mut buf = vec![];
let cm = Lrc::new(SourceMap::default());

{
let mut emitter = Emitter {
cfg: Default::default(),
cm: cm.clone(),
comments: None,
wr: Box::new(JsWriter::new(cm, "\n", &mut buf, None)),
};

emitter.emit_script(&script).unwrap();
}

let code = String::from_utf8(buf).unwrap();

debug!("Validating with node.js:\n{}", code);

if should_check {
let mut child = Command::new("node")
.arg("-")
.arg("--check")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.expect("failed to spawn node");

{
let child_stdin = child.stdin.as_mut().unwrap();
child_stdin
.write_all(code.as_bytes())
.expect("failed to write");
}

let output = child.wait_with_output().expect("failed to check syntax");

if !output.status.success() {
panic!(
"[SWC_CHECK] Failed to validate code:\n{}\n===== ===== ===== ===== =====\n{}\n{}",
code,
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr),
);
}
} else {
let output = Command::new("node")
.arg("-e")
.arg(&code)
.output()
.expect("[SWC_RUN] failed to validate code using `node`");
if !output.status.success() {
panic!(
"[SWC_RUN] Failed to validate code:\n{}\n===== ===== ===== ===== =====\n{}\n{}",
code,
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr),
);
}

tracing::info!(
"[SWC_RUN]\n{}\n{}",
code,
String::from_utf8_lossy(&output.stdout)
)
}
}
37 changes: 36 additions & 1 deletion crates/swc_ecma_minifier/src/util/unit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,42 @@ impl CompileUnit for Module {
{
self.visit_mut_with(&mut *visitor);

crate::debug::invoke(self);
crate::debug::invoke_module(self);
}

fn remove_mark(&mut self) -> Mark {
Mark::root()
}
}

impl CompileUnit for Script {
fn is_module() -> bool {
false
}

fn force_dump(&self) -> String {
let _noop_sub =
tracing::subscriber::set_default(tracing::subscriber::NoSubscriber::default());

dump(
&self
.clone()
.fold_with(&mut fixer(None))
.fold_with(&mut hygiene())
.fold_with(&mut as_folder(DropSpan {
preserve_ctxt: false,
})),
true,
)
}

fn apply<V>(&mut self, visitor: &mut V)
where
V: VisitMut,
{
self.visit_mut_with(&mut *visitor);

crate::debug::invoke_script(self);
}

fn remove_mark(&mut self) -> Mark {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
<circle onmouseover='alert("test")' cx=50 cy=50 r=30 style=fill:url(#gradient) />
</svg>
<div type=text onmouseover=myFunction()>test</div>
<a href=https://datacadamia.com onclick="console.log(`Navigation to ${this.href} cancelled`);return false">Click me</a>
<a href=https://datacadamia.com onclick="console.log(`Navigation to ${this.href} cancelled`);return false">Click me</a>
<a href=https://datacadamia.com onclick="return console.log(`Navigation to ${this.href} cancelled`),!1">Click me</a>
<a href=https://datacadamia.com onclick="return console.log(`Navigation to ${this.href} cancelled`),!1">Click me</a>
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<!doctype html><script defer>console.log()</script><script>console.log();console.log()</script><script type=module>console.log(),console.log()</script><script>window.jQuery||document.write('<script src="jquery.js"><\/script>')</script><script type=text/html>
<!doctype html><script defer>console.log()</script><script>console.log(),console.log()</script><script type=module>console.log(),console.log()</script><script>window.jQuery||document.write('<script src="jquery.js"><\/script>')</script><script type=text/html>
<div>
test
</div>
<!-- aa -->\n
</script><script type="">alert(1)</script><script type=modules>alert(1)</script><script>alert(1);alert(1)</script><script type=module src=app.mjs></script><script nomodule defer src=classic-app-bundle.js></script><script>alert(1)</script><script type=text/vbscript>MsgBox("foo bar")</script><script type="">MsgBox("foo bar")</script><script type=;;;;;>MsgBox("foo bar")</script><script>alert(1);alert(1);alert(1);alert(1);alert(1);alert(1);alert(1)</script>
</script><script type="">alert(1)</script><script type=modules>alert(1)</script><script>alert(1),alert(1)</script><script type=module src=app.mjs></script><script nomodule defer src=classic-app-bundle.js></script><script>alert(1)</script><script type=text/vbscript>MsgBox("foo bar")</script><script type="">MsgBox("foo bar")</script><script type=;;;;;>MsgBox("foo bar")</script><script>alert(1),alert(1),alert(1),alert(1),alert(1),alert(1),alert(1)</script>
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@


<div>breaker</div>
<script>(function o(){let o="1";console.log(o)})();let o="1";console.log(o)</script>
<script>console.log("1");let o="1";console.log(o)</script>


<div>breaker</div>
Expand Down Expand Up @@ -75,19 +75,19 @@
<script type=module>let a="test";console.log(a),console.log(a),console.log(a);let a1="test";console.log(a1),console.log(a1),console.log(a1)</script>

<div>breaker</div>
<script>let o="test";console.log(o);console.log(o);console.log(o);let o="test";console.log(o);console.log(o);console.log(o)</script>
<script>let o="test";console.log(o),console.log(o),console.log(o);let o="test";console.log(o),console.log(o),console.log(o)</script>

<div>breaker</div>
<script>var o="test";console.log(o);console.log(o);console.log(o);var o="test";console.log(o);console.log(o);console.log(o)</script>
<script>var o="test";console.log(o),console.log(o),console.log(o);var o="test";console.log(o),console.log(o),console.log(o)</script>

<div>breaker</div>
<script>var o="test";console.log(o);console.log(o);console.log(o);var o="test";console.log(o);console.log(o);console.log(o);var o="test";console.log(o);console.log(o);console.log(o)</script>
<script>var o="test";console.log(o),console.log(o),console.log(o);var o="test";console.log(o),console.log(o),console.log(o);var o="test";console.log(o),console.log(o),console.log(o)</script>

<div>breaker</div>
<script type=module>var a="test";console.log(a),console.log(a),console.log(a);var a1="test";console.log(a1),console.log(a1),console.log(a1);var a2="test";console.log(a2),console.log(a2),console.log(a2)</script>

<div>breaker</div>
<script type=module>var a="test";console.log(a),console.log(a),console.log(a)</script><script>var o="test";console.log(o);console.log(o);console.log(o)</script><script type=module>var a="test";console.log(a),console.log(a),console.log(a)</script>
<script type=module>var a="test";console.log(a),console.log(a),console.log(a)</script><script>var o="test";console.log(o),console.log(o),console.log(o)</script><script type=module>var a="test";console.log(a),console.log(a),console.log(a)</script>

<div>breaker</div>
<script>var o="test";console.log(o);console.log(o);console.log(o)</script><script type=module>var a="test";console.log(a),console.log(a),console.log(a)</script><script>var o="test";console.log(o);console.log(o);console.log(o)</script>
<script>var o="test";console.log(o),console.log(o),console.log(o)</script><script type=module>var a="test";console.log(a),console.log(a),console.log(a)</script><script>var o="test";console.log(o),console.log(o),console.log(o)</script>
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

var q = "WRONG" ;

</script><script>let t="testtest";alert("<!--");alert("<!-- foo -->");alert("-->");alert("testtest");function e(){var t=1,e=2;alert(t+" "+e)}</script><h2>Party coffee cake recipe</h2>
</script><script>let t="testtest";function e(){alert("1 2")}alert("<!--"),alert("<!-- foo -->"),alert("-->"),alert("testtest")</script><h2>Party coffee cake recipe</h2>
<p>
<i>by Mary Stone, 2018-03-10</i>
</p>
Expand All @@ -54,10 +54,10 @@
alert('test')
</script>
</math>
<script blocking="a render">console.log("block")</script><script>(function(t){var t="test"+Math.random()+t,r=1,o=2+Math.random();alert(r+" "+o);console.log(Math.random())})("test");window.jQuery||document.write('<script src="jquery.js"><\/script>')</script>
<script blocking="a render">console.log("block")</script><script>!function(t){var t="test"+Math.random()+t;alert("1 "+(2+Math.random())),console.log(Math.random())}("test"),window.jQuery||document.write('<script src="jquery.js"><\/script>')</script>
<div>test</div>

<div>topLevel - script</div>
<script>var o=function o(){let o="bar";if(o){o+="baz"}console.log(o)}</script>
<script>var o=function(){let o="bar";o&&(o+="baz"),console.log(o)}</script>
<div>topLevel - module</div>
<script type=module>var topLevel=function(){let o="bar";o&&(o+="baz"),console.log(o)}</script>
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@
foo

baz
</pre> <div> a <input> c </div> <div>Empty </div> <!--[if lte IE 6]> <span>A</span> <span title=" sigificant whitespace ">blah blah</span> <![endif]--> <div> <a href=#> <span> <b> foo </b> <i> bar </i> </span> </a> </div> <div>a b</div> <div>a b c d</div> <div> text </div> <span> text </span> <span> text </span> <div> <style>a{color:red}</style> <span>test</span> <style>a{color:red}</style> </div> <div> <style>a{color:red}</style> </div> <div> <style>a{color:red}</style> <span>test</span> <span>test</span> <style>a{color:red}</style> </div> <div> <script>console.log("test");console.log("test")</script> </div>
</pre> <div> a <input> c </div> <div>Empty </div> <!--[if lte IE 6]> <span>A</span> <span title=" sigificant whitespace ">blah blah</span> <![endif]--> <div> <a href=#> <span> <b> foo </b> <i> bar </i> </span> </a> </div> <div>a b</div> <div>a b c d</div> <div> text </div> <span> text </span> <span> text </span> <div> <style>a{color:red}</style> <span>test</span> <style>a{color:red}</style> </div> <div> <style>a{color:red}</style> </div> <div> <style>a{color:red}</style> <span>test</span> <span>test</span> <style>a{color:red}</style> </div> <div> <script>console.log("test"),console.log("test")</script> </div>
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@
foo

baz
</pre><div>a <input> c</div><div>Empty</div><!--[if lte IE 6]> <span>A</span> <span title=" sigificant whitespace ">blah blah</span> <![endif]--><div><a href=#> <span><b>foo </b><i> bar </i></span></a></div><div>a b</div><div>a b c d</div><div>text</div><span> text </span><span> text </span><div><span>test</span> <span>test</span></div><div><span>test</span> <command>test</command><span>test</span></div><div><span>test</span><link rel=stylesheet href=""> <span>test</span></div><div><span>test</span><meta name=content> <span>test</span></div><div><span>test</span><script>console.log("test")</script> <span>test</span></div><div><span>test</span><style>a{color:red}</style> <span>test</span></div><div><span>test</span><title>test</title> <span>test</span></div><div><meta name=test><meta name=test></div><div><link rel=stylesheet href=""><link rel=stylesheet href=""></div><div><script>console.log("test");console.log("test")</script></div><div><script>console.log("test")</script> <span>test</span><script>console.log("test")</script></div><div><style>a{color:red}</style></div><div><script>console.log("test")</script><style>a{color:red}</style></div><div><span itemscope><meta itemprop=name content="The Castle">test</span> <span>test</span></div><div><meta name=test></div><div><style>a{color:red}</style></div><div><meta name=test><div>test</div><meta name=test></div><div><meta name=test> <span>test</span><meta name=test></div><svg> <title>test</title> <metadata>test</metadata> <desc>test</desc> </svg><svg> <a>test</a> <a>test</a> </svg><svg><text x=20 y=35><tspan font-weight=bold fill=red>This is bold and red</tspan> <tspan font-weight=bold fill=red>This is bold and red</tspan></text></svg><svg> <tspan>test</tspan><foreignObject>test</foreignObject></svg><svg><text x=20 y=35><tspan font-weight=bold fill=red>This is bold and red</tspan> <tspan font-weight=bold fill=red>This is bold and red</tspan></text></svg><svg viewBox="0 0 100 100" preserveAspectRatio="xMidYMid slice" style=width:100%;height:100%;position:absolute;top:0;left:0;z-index:-1> <linearGradient id=gradient><stop class=begin offset=0% /><stop class=end offset=100% /></linearGradient><rect width=100 height=100 style=fill:url(#gradient) /> <circle cx=50 cy=50 r=30 style=fill:url(#gradient) /> </svg><svg> <script>console.log("test")</script></svg><svg> <style>a{color:red}</style></svg><div><span>test</span> a b <span>test</span> <span>test</span> a b <span>test</span> <span>test</span> a b <span>test</span></div><div><foo-bar> <span>test</span> </foo-bar> <foo-bar> <span>test</span> </foo-bar></div><div><svg> <linearGradient id=gradient /> </svg><span>a</span></div>
</pre><div>a <input> c</div><div>Empty</div><!--[if lte IE 6]> <span>A</span> <span title=" sigificant whitespace ">blah blah</span> <![endif]--><div><a href=#> <span><b>foo </b><i> bar </i></span></a></div><div>a b</div><div>a b c d</div><div>text</div><span> text </span><span> text </span><div><span>test</span> <span>test</span></div><div><span>test</span> <command>test</command><span>test</span></div><div><span>test</span><link rel=stylesheet href=""> <span>test</span></div><div><span>test</span><meta name=content> <span>test</span></div><div><span>test</span><script>console.log("test")</script> <span>test</span></div><div><span>test</span><style>a{color:red}</style> <span>test</span></div><div><span>test</span><title>test</title> <span>test</span></div><div><meta name=test><meta name=test></div><div><link rel=stylesheet href=""><link rel=stylesheet href=""></div><div><script>console.log("test"),console.log("test")</script></div><div><script>console.log("test")</script> <span>test</span><script>console.log("test")</script></div><div><style>a{color:red}</style></div><div><script>console.log("test")</script><style>a{color:red}</style></div><div><span itemscope><meta itemprop=name content="The Castle">test</span> <span>test</span></div><div><meta name=test></div><div><style>a{color:red}</style></div><div><meta name=test><div>test</div><meta name=test></div><div><meta name=test> <span>test</span><meta name=test></div><svg> <title>test</title> <metadata>test</metadata> <desc>test</desc> </svg><svg> <a>test</a> <a>test</a> </svg><svg><text x=20 y=35><tspan font-weight=bold fill=red>This is bold and red</tspan> <tspan font-weight=bold fill=red>This is bold and red</tspan></text></svg><svg> <tspan>test</tspan><foreignObject>test</foreignObject></svg><svg><text x=20 y=35><tspan font-weight=bold fill=red>This is bold and red</tspan> <tspan font-weight=bold fill=red>This is bold and red</tspan></text></svg><svg viewBox="0 0 100 100" preserveAspectRatio="xMidYMid slice" style=width:100%;height:100%;position:absolute;top:0;left:0;z-index:-1> <linearGradient id=gradient><stop class=begin offset=0% /><stop class=end offset=100% /></linearGradient><rect width=100 height=100 style=fill:url(#gradient) /> <circle cx=50 cy=50 r=30 style=fill:url(#gradient) /> </svg><svg> <script>console.log("test")</script></svg><svg> <style>a{color:red}</style></svg><div><span>test</span> a b <span>test</span> <span>test</span> a b <span>test</span> <span>test</span> a b <span>test</span></div><div><foo-bar> <span>test</span> </foo-bar> <foo-bar> <span>test</span> </foo-bar></div><div><svg> <linearGradient id=gradient /> </svg><span>a</span></div>
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<!doctype html><meta charset=utf-8><title>element-details - web component using &lt;template> and &lt;slot></title><style>dl{margin-left:6px}dt{font-weight:700;color:#217ac0;font-size:110%;font-family:Consolas,"Liberation Mono",Courier}dd{margin-left:16px}</style><h1>element-details - web component using <code>&lt;template></code> and <code>&lt;slot></code></h1><template id=element-details-template-1> VALUE: !<slot>?</slot>! </template> <element-details> <span>test</span> <span>foo</span> </element-details> <script>customElements.define("element-details",class extends HTMLElement{constructor(){super();let e=document.getElementById("element-details-template-1").content;this.attachShadow({mode:"open"}).appendChild(e.cloneNode(true))}})</script>
<!doctype html><meta charset=utf-8><title>element-details - web component using &lt;template> and &lt;slot></title><style>dl{margin-left:6px}dt{font-weight:700;color:#217ac0;font-size:110%;font-family:Consolas,"Liberation Mono",Courier}dd{margin-left:16px}</style><h1>element-details - web component using <code>&lt;template></code> and <code>&lt;slot></code></h1><template id=element-details-template-1> VALUE: !<slot>?</slot>! </template> <element-details> <span>test</span> <span>foo</span> </element-details> <script>customElements.define("element-details",class extends HTMLElement{constructor(){super();let e=document.getElementById("element-details-template-1").content;this.attachShadow({mode:"open"}).appendChild(e.cloneNode(!0))}})</script>

0 comments on commit d0968c1

Please sign in to comment.