mirror of
https://github.com/swc-project/swc.git
synced 2024-11-24 10:12:42 +03:00
feat(html/minifier): Compress default values of attributes (#4427)
This commit is contained in:
parent
c7aa0fe86b
commit
4c699f2554
@ -47,16 +47,6 @@ static BOOLEAN_ATTRIBUTES: &[&str] = &[
|
||||
"visible",
|
||||
];
|
||||
|
||||
static EXECUTABLE_SCRIPTS_MIME_TYPES: &[&str] = &[
|
||||
"text/javascript",
|
||||
"text/ecmascript",
|
||||
"text/jscript",
|
||||
"application/javascript",
|
||||
"application/x-javascript",
|
||||
"application/ecmascript",
|
||||
"module",
|
||||
];
|
||||
|
||||
struct Minifier {}
|
||||
|
||||
impl Minifier {
|
||||
@ -64,6 +54,99 @@ impl Minifier {
|
||||
BOOLEAN_ATTRIBUTES.contains(&name)
|
||||
}
|
||||
|
||||
fn is_default_attribute_value(
|
||||
&self,
|
||||
namespace: Namespace,
|
||||
tag_name: &str,
|
||||
attribute_name: &str,
|
||||
attribute_value: &str,
|
||||
) -> bool {
|
||||
matches!(
|
||||
(
|
||||
namespace,
|
||||
tag_name,
|
||||
attribute_name,
|
||||
attribute_value.to_ascii_lowercase().trim()
|
||||
),
|
||||
(Namespace::HTML, "iframe", "height", "150")
|
||||
| (Namespace::HTML, "iframe", "width", "300")
|
||||
| (Namespace::HTML, "iframe", "frameborder", "1")
|
||||
| (Namespace::HTML, "iframe", "loading", "eager")
|
||||
| (Namespace::HTML, "iframe", "fetchpriority", "auto")
|
||||
| (
|
||||
Namespace::HTML,
|
||||
"iframe",
|
||||
"referrerpolicy",
|
||||
"strict-origin-when-cross-origin"
|
||||
)
|
||||
| (
|
||||
Namespace::HTML,
|
||||
"a",
|
||||
"referrerpolicy",
|
||||
"strict-origin-when-cross-origin"
|
||||
)
|
||||
| (Namespace::HTML, "a", "target", "_self")
|
||||
| (Namespace::HTML, "area", "target", "_self")
|
||||
| (Namespace::HTML, "area", "shape", "rect")
|
||||
| (
|
||||
Namespace::HTML,
|
||||
"area",
|
||||
"referrerpolicy",
|
||||
"strict-origin-when-cross-origin"
|
||||
)
|
||||
| (Namespace::HTML, "form", "method", "get")
|
||||
| (Namespace::HTML, "form", "target", "_self")
|
||||
| (Namespace::HTML, "input", "type", "text")
|
||||
| (Namespace::HTML, "input", "size", "20")
|
||||
| (Namespace::HTML, "track", "kind", "subtitles")
|
||||
| (Namespace::HTML, "textarea", "cols", "20")
|
||||
| (Namespace::HTML, "textarea", "rows", "2")
|
||||
| (Namespace::HTML, "textarea", "wrap", "sort")
|
||||
| (Namespace::HTML, "progress", "max", "1")
|
||||
| (Namespace::HTML, "meter", "min", "0")
|
||||
| (Namespace::HTML, "img", "decoding", "auto")
|
||||
| (Namespace::HTML, "img", "fetchpriority", "auto")
|
||||
| (Namespace::HTML, "img", "loading", "eager")
|
||||
| (
|
||||
Namespace::HTML,
|
||||
"img",
|
||||
"referrerpolicy",
|
||||
"strict-origin-when-cross-origin"
|
||||
)
|
||||
| (Namespace::HTML, "link", "type", "text/css")
|
||||
| (Namespace::HTML, "link", "fetchpriority", "auto")
|
||||
| (
|
||||
Namespace::HTML,
|
||||
"link",
|
||||
"referrerpolicy",
|
||||
"strict-origin-when-cross-origin"
|
||||
)
|
||||
| (Namespace::HTML, "style", "type", "text/css")
|
||||
| (Namespace::HTML, "script", "type", "text/javascript")
|
||||
| (Namespace::HTML, "script", "type", "text/ecmascript")
|
||||
| (Namespace::HTML, "script", "type", "text/jscript")
|
||||
| (Namespace::HTML, "script", "type", "application/javascript")
|
||||
| (
|
||||
Namespace::HTML,
|
||||
"script",
|
||||
"type",
|
||||
"application/x-javascript"
|
||||
)
|
||||
| (Namespace::HTML, "script", "type", "application/ecmascript")
|
||||
| (Namespace::HTML, "script", "fetchpriority", "auto")
|
||||
| (
|
||||
Namespace::HTML,
|
||||
"script",
|
||||
"referrerpolicy",
|
||||
"strict-origin-when-cross-origin"
|
||||
)
|
||||
| (Namespace::HTML, "ol", "type", "1")
|
||||
| (Namespace::HTML, "base", "target", "_self")
|
||||
| (Namespace::HTML, "canvas", "height", "150")
|
||||
| (Namespace::HTML, "canvas", "width", "300")
|
||||
)
|
||||
}
|
||||
|
||||
fn is_conditional_comment(&self, data: &str) -> bool {
|
||||
let trimmed = data.trim();
|
||||
|
||||
@ -80,40 +163,23 @@ impl VisitMut for Minifier {
|
||||
n.visit_mut_children_with(self);
|
||||
|
||||
n.children.retain(|child| !matches!(child, Child::Comment(comment) if !self.is_conditional_comment(&comment.data)));
|
||||
n.attributes.retain(|attribute| match &*attribute.name {
|
||||
"type"
|
||||
if n.namespace == Namespace::HTML
|
||||
&& matches!(n.tag_name.as_ref(), "script")
|
||||
&& (attribute.value.is_some()
|
||||
&& attribute
|
||||
.value
|
||||
.as_ref()
|
||||
.map(|v| {
|
||||
EXECUTABLE_SCRIPTS_MIME_TYPES
|
||||
.iter()
|
||||
.any(|mime| v.eq_str_ignore_ascii_case(mime))
|
||||
})
|
||||
.unwrap_or_default()) =>
|
||||
{
|
||||
false
|
||||
n.attributes.retain(|attribute| {
|
||||
if attribute.value.is_none() {
|
||||
return true;
|
||||
}
|
||||
"type"
|
||||
if n.namespace == Namespace::HTML
|
||||
&& matches!(n.tag_name.as_ref(), "style" | "link")
|
||||
&& (attribute.value.is_some()
|
||||
&& matches!(
|
||||
attribute
|
||||
.value
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.to_ascii_lowercase()
|
||||
.trim(),
|
||||
"text/css"
|
||||
)) =>
|
||||
|
||||
match &*attribute.name {
|
||||
_ if self.is_default_attribute_value(
|
||||
n.namespace,
|
||||
&n.tag_name,
|
||||
&attribute.name,
|
||||
attribute.value.as_ref().unwrap(),
|
||||
) =>
|
||||
{
|
||||
false
|
||||
}
|
||||
_ => true,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,13 @@
|
||||
<!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>
|
||||
<iframe id="test" src="test.html" frameborder="1" height="150" width="300" loading="eager" fetchpriority="auto" referrerpolicy="strict-origin-when-cross-origin"></iframe>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,10 @@
|
||||
<!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>
|
||||
<iframe id=test src=test.html></iframe>
|
||||
|
||||
</body></html>
|
@ -0,0 +1,9 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<img src="test.png" alt="test" decoding="auto" loading="eager" referrerpolicy="strict-origin-when-cross-origin">
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,7 @@
|
||||
<!doctype html><html lang=en><head>
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<img src=test.png alt=test>
|
||||
|
||||
</body></html>
|
@ -0,0 +1,12 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<input name="a" type="text">
|
||||
<input name="b" type="TEXT">
|
||||
<input name="c" type=" TEXT ">
|
||||
<input name="d" size=" 20 ">
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,10 @@
|
||||
<!doctype html><html lang=en><head>
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<input name=a>
|
||||
<input name=b>
|
||||
<input name=c>
|
||||
<input name=d>
|
||||
|
||||
</body></html>
|
@ -0,0 +1,14 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<meter id="fuel"
|
||||
min="0" max="100"
|
||||
low="33" high="66" optimum="80"
|
||||
value="50">
|
||||
at 50/100
|
||||
</meter>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,9 @@
|
||||
<!doctype html><html lang=en><head>
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<meter id=fuel max=100 low=33 high=66 optimum=80 value=50>
|
||||
at 50/100
|
||||
</meter>
|
||||
|
||||
</body></html>
|
@ -0,0 +1,15 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<ol type="1">
|
||||
<li>Mix flour, baking powder, sugar, and salt.</li>
|
||||
<li>In another bowl, mix eggs, milk, and oil.</li>
|
||||
<li>Stir both mixtures together.</li>
|
||||
<li>Fill muffin tray 3/4 full.</li>
|
||||
<li>Bake for 20 minutes.</li>
|
||||
</ol>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,13 @@
|
||||
<!doctype html><html lang=en><head>
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<ol>
|
||||
<li>Mix flour, baking powder, sugar, and salt.</li>
|
||||
<li>In another bowl, mix eggs, milk, and oil.</li>
|
||||
<li>Stir both mixtures together.</li>
|
||||
<li>Fill muffin tray 3/4 full.</li>
|
||||
<li>Bake for 20 minutes.</li>
|
||||
</ol>
|
||||
|
||||
</body></html>
|
@ -0,0 +1,9 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<progress max="1"></progress>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,7 @@
|
||||
<!doctype html><html lang=en><head>
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<progress></progress>
|
||||
|
||||
</body></html>
|
@ -4,7 +4,7 @@
|
||||
<script>
|
||||
console.log();
|
||||
</script>
|
||||
<script>
|
||||
<script type=module>
|
||||
console.log();
|
||||
</script>
|
||||
</head><body></body></html>
|
||||
|
@ -0,0 +1,9 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<textarea name="test" id="test" cols="20" rows="2"></textarea>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,7 @@
|
||||
<!doctype html><html lang=en><head>
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<textarea name=test id=test></textarea>
|
||||
</>
|
||||
</></body></html>
|
@ -0,0 +1,31 @@
|
||||
<!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>
|
||||
|
||||
<video controls
|
||||
src="/media/cc0-videos/friday.mp4">
|
||||
<track default
|
||||
kind="captions"
|
||||
srclang="en"
|
||||
src="/media/examples/friday.vtt" />
|
||||
Sorry, your browser doesn't support embedded videos.
|
||||
</video>
|
||||
|
||||
<video controls
|
||||
src="/media/cc0-videos/friday.mp4">
|
||||
<track default
|
||||
kind="subtitles"
|
||||
srclang="en"
|
||||
src="/media/examples/friday.vtt" />
|
||||
Sorry, your browser doesn't support embedded videos.
|
||||
</video>
|
||||
|
||||
</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>
|
||||
|
||||
<video controls src=/media/cc0-videos/friday.mp4>
|
||||
<track default kind=captions srclang=en src=/media/examples/friday.vtt>
|
||||
Sorry, your browser doesn't support embedded videos.
|
||||
</video>
|
||||
|
||||
<video controls src=/media/cc0-videos/friday.mp4>
|
||||
<track default srclang=en src=/media/examples/friday.vtt>
|
||||
Sorry, your browser doesn't support embedded videos.
|
||||
</video>
|
||||
|
||||
|
||||
</body></html>
|
Loading…
Reference in New Issue
Block a user