mirror of
https://github.com/swc-project/swc.git
synced 2024-11-23 09:38:16 +03:00
feat(html/minifier): Compress whitespaces (#4463)
This commit is contained in:
parent
8c520919fd
commit
0ae43502f3
@ -47,6 +47,22 @@ static BOOLEAN_ATTRIBUTES: &[&str] = &[
|
||||
"visible",
|
||||
];
|
||||
|
||||
// TODO improve list - event handlers + remove multiple whitespace from class +
|
||||
// test for custom elements
|
||||
static ALLOW_TO_TRIM_ATTRIBUTES: &[&str] = &[
|
||||
"id",
|
||||
"class",
|
||||
"style",
|
||||
"tabindex",
|
||||
"maxlength",
|
||||
"size",
|
||||
"rows",
|
||||
"cols",
|
||||
"span",
|
||||
"rowspan",
|
||||
"colspan",
|
||||
];
|
||||
|
||||
struct Minifier {}
|
||||
|
||||
impl Minifier {
|
||||
@ -54,6 +70,10 @@ impl Minifier {
|
||||
BOOLEAN_ATTRIBUTES.contains(&name)
|
||||
}
|
||||
|
||||
fn allow_to_trim(&self, name: &str) -> bool {
|
||||
ALLOW_TO_TRIM_ATTRIBUTES.contains(&name)
|
||||
}
|
||||
|
||||
fn is_default_attribute_value(
|
||||
&self,
|
||||
namespace: Namespace,
|
||||
@ -178,6 +198,11 @@ impl VisitMut for Minifier {
|
||||
{
|
||||
false
|
||||
}
|
||||
_ if matches!(&*attribute.name, "id" | "class" | "style")
|
||||
&& (&*attribute.value.as_ref().unwrap()).trim().is_empty() =>
|
||||
{
|
||||
false
|
||||
}
|
||||
_ => true,
|
||||
}
|
||||
});
|
||||
@ -186,12 +211,23 @@ impl VisitMut for Minifier {
|
||||
fn visit_mut_attribute(&mut self, n: &mut Attribute) {
|
||||
n.visit_mut_children_with(self);
|
||||
|
||||
match &n.name {
|
||||
name if n.value.is_some() && self.is_boolean_attribute(name) => {
|
||||
n.value = None;
|
||||
}
|
||||
_ => {}
|
||||
if n.value.is_none() {
|
||||
return;
|
||||
}
|
||||
|
||||
if self.is_boolean_attribute(&n.name) {
|
||||
n.value = None;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
let mut value: &str = &*(n.value.as_ref().unwrap().clone());
|
||||
|
||||
if self.allow_to_trim(&n.name) {
|
||||
value = value.trim();
|
||||
}
|
||||
|
||||
n.value = Some(value.into());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
<p><button autofocus value="next">Button</button></p>
|
||||
<p><button autofocus="autofocus" value="next">Button</button></p>
|
||||
<p><button autofocus=" autofocus " value="next">Button</button></p>
|
||||
<p><button autofocus="true" value="next">Button</button></p>
|
||||
<p><button autofocus="false" value="next">Button</button></p>
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
<p><button autofocus value=next>Button</button></p>
|
||||
<p><button autofocus value=next>Button</button></p>
|
||||
<p><button autofocus value=next>Button</button></p>
|
||||
<p><button autofocus value=next>Button</button></p>
|
||||
|
||||
<img draggable=false>
|
||||
<img draggable=true>
|
||||
|
@ -0,0 +1,25 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<p class=" foo bar ">foo bar baz</p>
|
||||
<p class=" foo ">foo bar baz</p>
|
||||
<p class="
|
||||
|
||||
foo
|
||||
|
||||
|
||||
">foo bar baz</p>
|
||||
<p class="
|
||||
|
||||
|
||||
foo
|
||||
|
||||
|
||||
|
||||
|
||||
class1 class-23 ">foo bar baz</p>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,15 @@
|
||||
<!doctype html><html lang=en><head>
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<p class="foo bar">foo bar baz</p>
|
||||
<p class=foo>foo bar baz</p>
|
||||
<p class=foo>foo bar baz</p>
|
||||
<p class="foo
|
||||
|
||||
|
||||
|
||||
|
||||
class1 class-23">foo bar baz</p>
|
||||
|
||||
</body></html>
|
@ -0,0 +1,19 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<input
|
||||
class="form-control"
|
||||
type="text"
|
||||
style=""
|
||||
id="{{vm.formInputName}}"
|
||||
name="{{vm.formInputName}}"
|
||||
placeholder="YYYY-MM-DD" date-range-picker
|
||||
data-ng-model="vm.value"
|
||||
data-ng-model-options="{ debounce: 1000 }"
|
||||
data-ng-pattern="vm.options.format"
|
||||
data-options="vm.datepickerOptions">
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,7 @@
|
||||
<!doctype html><html lang=en><head>
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<input class=form-control id={{vm.formInputName}} name={{vm.formInputName}} placeholder=YYYY-MM-DD date-range-picker data-ng-model=vm.value data-ng-model-options="{ debounce: 1000 }" data-ng-pattern=vm.options.format data-options=vm.datepickerOptions>
|
||||
|
||||
</body></html>
|
@ -0,0 +1,18 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport"
|
||||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<div
|
||||
data-test="one"
|
||||
data-test="two"
|
||||
></div>
|
||||
|
||||
<img src="test.png" alt="one" alt="two">
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,12 @@
|
||||
<!doctype html><html lang=en><head>
|
||||
<meta charset=UTF-8>
|
||||
<meta name=viewport content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<meta http-equiv=X-UA-Compatible content="ie=edge">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<div data-test=one data-test=two></div>
|
||||
|
||||
<img src=test.png alt=one alt=two>
|
||||
|
||||
</body></html>
|
@ -0,0 +1,25 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<p id="" class="" STYLE=" " title="\n" lang="" dir="">x</p>
|
||||
<p
|
||||
onclick=""
|
||||
ondblclick=" "
|
||||
onmousedown=""
|
||||
ONMOUSEUP=""
|
||||
onmouseover=" "
|
||||
onmousemove=""
|
||||
onmouseout=""
|
||||
onkeypress=
|
||||
|
||||
"
|
||||
"
|
||||
onkeydown=
|
||||
""
|
||||
onkeyup
|
||||
="">x</p>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,9 @@
|
||||
<!doctype html><html lang=en><head>
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<p title=\n lang="" dir="">x</p>
|
||||
<p onclick="" ondblclick=" " onmousedown="" onmouseup="" onmouseover=" " onmousemove="" onmouseout="" onkeypress="
|
||||
" onkeydown="" onkeyup="">x</p>
|
||||
|
||||
</body></html>
|
@ -12,6 +12,8 @@
|
||||
<form action="handler.php" method="get">
|
||||
<input type="text" name="str">
|
||||
<input type="submit" value="send">
|
||||
<input type=" TEXT " value="foo">
|
||||
<input type="checkbox">
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -10,6 +10,8 @@
|
||||
<form action=handler.php>
|
||||
<input name=str>
|
||||
<input type=submit value=send>
|
||||
<input value=foo>
|
||||
<input type=checkbox>
|
||||
</form>
|
||||
|
||||
|
||||
|
@ -16,5 +16,8 @@
|
||||
test"></div>
|
||||
<div data-test=" test ' test ' test"></div>
|
||||
<div data-test=' test " test " test'></div>
|
||||
<div data='{ "test": "test" }'></div>
|
||||
<div data="{ 'test': 'test' }"></div>
|
||||
<div data="{"test":"\\"test\\""}"></div>'
|
||||
</body>
|
||||
</html>
|
@ -13,5 +13,8 @@
|
||||
test"></div>
|
||||
<div data-test=" test ' test ' test"></div>
|
||||
<div data-test=' test " test " test'></div>
|
||||
<div data='{ "test": "test" }'></div>
|
||||
<div data="{ 'test': 'test' }"></div>
|
||||
<div data='{"test":"\\"test\\""}'></div>'
|
||||
|
||||
</body></html>
|
||||
|
@ -7,3 +7,4 @@
|
||||
<script type="module">
|
||||
console.log();
|
||||
</script>
|
||||
<script>window.jQuery || document.write('<script src="jquery.js"><\/script>')</script>
|
@ -7,4 +7,4 @@
|
||||
<script type=module>
|
||||
console.log();
|
||||
</script>
|
||||
</head><body></body></html>
|
||||
<script>window.jQuery || document.write('<script src="jquery.js"><\/script>')</script></head><body></body></html>
|
||||
|
@ -0,0 +1,32 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<p title="bar">foo</p>
|
||||
<p
|
||||
title
|
||||
=
|
||||
"bar"
|
||||
>foo</p
|
||||
>
|
||||
<img src="test"/>
|
||||
<img src="test"
|
||||
|
||||
|
||||
/>
|
||||
<img
|
||||
|
||||
|
||||
|
||||
src="test"
|
||||
|
||||
|
||||
>
|
||||
<p title = "bar">foo</p>
|
||||
<p title = "bar">foo</p>
|
||||
<p title = 'bar'>foo</p>
|
||||
<p title = bar>foo</p>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,15 @@
|
||||
<!doctype html><html lang=en><head>
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<p title=bar>foo</p>
|
||||
<p title=bar>foo</p>
|
||||
<img src=test>
|
||||
<img src=test>
|
||||
<img src=test>
|
||||
<p title=bar>foo</p>
|
||||
<p title=bar>foo</p>
|
||||
<p title=bar>foo</p>
|
||||
<p title=bar>foo</p>
|
||||
|
||||
</body></html>
|
@ -28,6 +28,7 @@
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p style=" color: red; background-color: rgb(100, 75, 200); "></p>
|
||||
<p style=" "></p>
|
||||
</body>
|
||||
</html>
|
@ -26,6 +26,7 @@
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p style="color: red; background-color: rgb(100, 75, 200);"></p>
|
||||
<p></p>
|
||||
|
||||
</body></html>
|
||||
|
@ -0,0 +1 @@
|
||||
<a href="#" tabindex=" 1 ">x</a><button tabindex=" 2 ">y</button>
|
@ -0,0 +1 @@
|
||||
<html><head></head><body><a href=# tabindex=1>x</a><button tabindex=2>y</button></body></html>
|
@ -24,6 +24,20 @@
|
||||
|
||||
<p>This is a paragraph.</p>
|
||||
|
||||
<!-- Test -->
|
||||
<!-- foo --><div>baz</div><!-- bar
|
||||
|
||||
moo -->
|
||||
<script><!-- alert(1) --></script>
|
||||
<script><!--
|
||||
alert(1);
|
||||
--></script>
|
||||
<style type="text/css"><!-- p { color: red } --></style>
|
||||
<script>/*<![CDATA[*/alert(8)/*]]>*/</script>
|
||||
<script type="text/javascript"> /*
|
||||
<![CDATA[ */
|
||||
alert(10)
|
||||
/* ]]> */
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -21,6 +21,18 @@
|
||||
|
||||
<p>This is a paragraph.</p>
|
||||
|
||||
|
||||
|
||||
<div>baz</div>
|
||||
<script><!-- alert(1) --></script>
|
||||
<script><!--
|
||||
alert(1);
|
||||
--></script>
|
||||
<style><!-- p { color: red } --></style>
|
||||
<script>/*<![CDATA[*/alert(8)/*]]>*/</script>
|
||||
<script> /*
|
||||
<![CDATA[ */
|
||||
alert(10)
|
||||
/* ]]> */
|
||||
</script>
|
||||
|
||||
</body></html>
|
||||
|
@ -0,0 +1,20 @@
|
||||
<!DOCTYPE HTML>
|
||||
<HTML LANG="EN">
|
||||
<HEAD>
|
||||
<META CHARSET="UTF-8">
|
||||
<META NAME="viewport"
|
||||
CONTENT="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<META HTTP-EQUIV="X-UA-Compatible" CONTENT="ie=edge">
|
||||
<TITLE>Document</TITLE>
|
||||
</HEAD>
|
||||
<BODY>
|
||||
<DIV DATA-TEST="Test">TEST</DIV>
|
||||
<P>blah<SPAN>blah 2<SPAN>blah 3</SPAN></SPAN></P>
|
||||
<P>foo</p>
|
||||
<DIV>boo</DIV>
|
||||
<DIV title="moo">boo</DiV>
|
||||
<DIV TITLE="blah">boo</DIV>
|
||||
<DIV tItLe="blah">boo</DIV>
|
||||
<DiV tItLe="blah">boo</DIV>
|
||||
</BODY>
|
||||
</HTML>
|
@ -0,0 +1,17 @@
|
||||
<!doctype html><html lang=EN><head>
|
||||
<meta charset=UTF-8>
|
||||
<meta name=viewport content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<meta http-equiv=X-UA-Compatible content="ie=edge">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<div data-test=Test>TEST</div>
|
||||
<p>blah<span>blah 2<span>blah 3</span></span></p>
|
||||
<p>foo</p>
|
||||
<div>boo</div>
|
||||
<div title=moo>boo</div>
|
||||
<div title=blah>boo</div>
|
||||
<div title=blah>boo</div>
|
||||
<div title=blah>boo</div>
|
||||
|
||||
</body></html>
|
11
crates/swc_html_minifier/tests/fixture/element/a/input.html
Normal file
11
crates/swc_html_minifier/tests/fixture/element/a/input.html
Normal file
@ -0,0 +1,11 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<a href="test.html"><div>hey</div></a>
|
||||
<a href>ok</a>
|
||||
<a onclick></a>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,9 @@
|
||||
<!doctype html><html lang=en><head>
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<a href=test.html><div>hey</div></a>
|
||||
<a href>ok</a>
|
||||
<a onclick></a>
|
||||
|
||||
</body></html>
|
10
crates/swc_html_minifier/tests/fixture/element/br/input.html
Normal file
10
crates/swc_html_minifier/tests/fixture/element/br/input.html
Normal file
@ -0,0 +1,10 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
test<br>test
|
||||
test<br/>test
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,8 @@
|
||||
<!doctype html><html lang=en><head>
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
test<br>test
|
||||
test<br>test
|
||||
|
||||
</body></html>
|
@ -0,0 +1,14 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<begriffs.pagination ng-init="perPage=20" collection="logs" url="\'/api/logs?user=-1\'" per-page="perPage" per-page-presets="[10,20,50,100]" template-url="/assets/paginate-anything.html"></begriffs.pagination>
|
||||
<some-tag-1></some-tag-1><some-tag-2></some-tag-2>
|
||||
[\']["]
|
||||
<CUSTOM-TAG></CUSTOM-TAG><div>Hello :)</div>
|
||||
<tag v-ref:vm_pv :imgs=" objpicsurl_ "></tag>
|
||||
<span><phrasing-element></phrasing-element></span>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,12 @@
|
||||
<!doctype html><html lang=en><head>
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<begriffs.pagination ng-init="perPage=20" collection=logs url="\'/api/logs?user=-1\'" per-page=perPage per-page-presets=[10,20,50,100] template-url=/assets/paginate-anything.html></begriffs.pagination>
|
||||
<some-tag-1></some-tag-1><some-tag-2></some-tag-2>
|
||||
[\']["]
|
||||
<custom-tag></custom-tag><div>Hello :)</div>
|
||||
<tag v-ref:vm_pv :imgs=" objpicsurl_ "></tag>
|
||||
<span><phrasing-element></phrasing-element></span>
|
||||
|
||||
</body></html>
|
12
crates/swc_html_minifier/tests/fixture/element/p/input.html
Normal file
12
crates/swc_html_minifier/tests/fixture/element/p/input.html
Normal file
@ -0,0 +1,12 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>For more information, read <a href=https://stackoverflow.com/questions/17408815/fieldset-resizes-wrong-appears-to-have-unremovable-min-width-min-content/17863685#17863685>this Stack Overflow answer</a>.</p>
|
||||
<p>a<div>b</div>
|
||||
<p>a<ul><li>item</li></ul>
|
||||
<p>a</p><ol><li>item</li></ol>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,10 @@
|
||||
<!doctype html><html lang=en><head>
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>For more information, read <a href=https://stackoverflow.com/questions/17408815/fieldset-resizes-wrong-appears-to-have-unremovable-min-width-min-content/17863685#17863685>this Stack Overflow answer</a>.</p>
|
||||
<p>a</p><div>b</div>
|
||||
<p>a</p><ul><li>item</li></ul>
|
||||
<p>a</p><ol><li>item</li></ol>
|
||||
|
||||
</body></html>
|
@ -29,5 +29,7 @@
|
||||
<div>The cent sign: ¢</div>
|
||||
<div>The cent sign: ¢</div>
|
||||
|
||||
:) <a href="http://example.com">link</a>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -27,5 +27,7 @@
|
||||
<div>The cent sign: ¢</div>
|
||||
<div>The cent sign: ¢</div>
|
||||
|
||||
:) <a href=http://example.com>link</a>
|
||||
|
||||
|
||||
</body></html>
|
||||
|
Loading…
Reference in New Issue
Block a user