feat(html/minifier): Compress application/ld+json (#4628)

This commit is contained in:
Alexander Akait 2022-05-12 22:32:49 +03:00 committed by GitHub
parent e21a40e55e
commit c41aca6b24
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 135 additions and 0 deletions

1
Cargo.lock generated
View File

@ -3877,6 +3877,7 @@ dependencies = [
name = "swc_html_minifier" name = "swc_html_minifier"
version = "0.4.0" version = "0.4.0"
dependencies = [ dependencies = [
"serde_json",
"swc_atoms", "swc_atoms",
"swc_common", "swc_common",
"swc_html_ast", "swc_html_ast",

View File

@ -13,6 +13,7 @@ version = "0.4.0"
bench = false bench = false
[dependencies] [dependencies]
serde_json = "1.0.61"
swc_atoms = {version = "0.2.9", path = "../swc_atoms"} swc_atoms = {version = "0.2.9", path = "../swc_atoms"}
swc_common = { version = "0.18.0", path = "../swc_common"} swc_common = { version = "0.18.0", path = "../swc_common"}
swc_html_ast = {version = "0.6.0", path = "../swc_html_ast"} swc_html_ast = {version = "0.6.0", path = "../swc_html_ast"}

View File

@ -1,5 +1,6 @@
#![deny(clippy::all)] #![deny(clippy::all)]
use serde_json::Value;
use swc_atoms::JsWord; use swc_atoms::JsWord;
use swc_common::collections::AHashSet; use swc_common::collections::AHashSet;
use swc_html_ast::*; use swc_html_ast::*;
@ -173,6 +174,7 @@ static SPACE_SEPARATED_ATTRIBUTES: &[&str] = &[
struct Minifier { struct Minifier {
current_element_namespace: Option<Namespace>, current_element_namespace: Option<Namespace>,
is_script_json_ld: bool,
} }
impl Minifier { impl Minifier {
@ -315,12 +317,25 @@ impl Minifier {
impl VisitMut for Minifier { impl VisitMut for Minifier {
fn visit_mut_element(&mut self, n: &mut Element) { fn visit_mut_element(&mut self, n: &mut Element) {
let old_current_element_namespace = self.current_element_namespace.take(); let old_current_element_namespace = self.current_element_namespace.take();
let old_value_is_script_json_ld = self.is_script_json_ld;
self.current_element_namespace = Some(n.namespace); self.current_element_namespace = Some(n.namespace);
self.is_script_json_ld = n.namespace == Namespace::HTML
&& &*n.tag_name == "script"
&& n.attributes.iter().any(|attribute| match &*attribute.name {
"type"
if attribute.value.is_some()
&& (&*attribute.value.as_ref().unwrap()) == "application/ld+json" =>
{
true
}
_ => false,
});
n.visit_mut_children_with(self); n.visit_mut_children_with(self);
self.current_element_namespace = old_current_element_namespace; self.current_element_namespace = old_current_element_namespace;
self.is_script_json_ld = old_value_is_script_json_ld;
n.children.retain(|child| !matches!(child, Child::Comment(comment) if !self.is_conditional_comment(&comment.data))); n.children.retain(|child| !matches!(child, Child::Comment(comment) if !self.is_conditional_comment(&comment.data)));
@ -421,10 +436,28 @@ impl VisitMut for Minifier {
n.value = Some(value.into()); n.value = Some(value.into());
} }
fn visit_mut_text(&mut self, n: &mut Text) {
n.visit_mut_children_with(self);
if self.is_script_json_ld {
let json = match serde_json::from_str::<Value>(&*n.value) {
Ok(json) => json,
_ => return,
};
let minified_json = match serde_json::to_string(&json) {
Ok(minified_json) => minified_json,
_ => return,
};
n.value = minified_json.into()
}
}
} }
pub fn minify(document: &mut Document) { pub fn minify(document: &mut Document) {
document.visit_mut_with(&mut Minifier { document.visit_mut_with(&mut Minifier {
current_element_namespace: None, current_element_namespace: None,
is_script_json_ld: false,
}); });
} }

View File

@ -0,0 +1,63 @@
<html>
<head>
<title>Party Coffee Cake</title>
<script type="application/ld+json">
{
"@context": "https://schema.org/",
"@type": "Recipe",
"name": "Party Coffee Cake",
"author": {
"@type": "Person",
"name": "Mary Stone"
},
"datePublished": "2018-03-10",
"description": "This coffee cake is awesome and perfect for parties.",
"prepTime": "PT20M"
}
</script>
<script type="application/ld+json" crossorigin="anonymous">
{
"@context": "https://schema.org/",
"@type": "Recipe",
"name": "Party Coffee Cake",
"author": {
"@type": "Person",
"name": "Mary Stone"
},
"datePublished": "2018-03-10",
"description": "This coffee cake is awesome and perfect for parties.",
"prepTime": "PT20M"
}
</script>
<script type="application/ld+json" crossorigin="anonymous">
{
broken
</script>
<script type="unknown">
{
"@context": "https://schema.org/",
"@type": "Recipe",
"name": "Party Coffee Cake",
"author": {
"@type": "Person",
"name": "Mary Stone"
},
"datePublished": "2018-03-10",
"description": "This coffee cake is awesome and perfect for parties.",
"prepTime": "PT20M"
}
</script>
</head>
<body>
<h2>Party coffee cake recipe</h2>
<p>
<i>by Mary Stone, 2018-03-10</i>
</p>
<p>
This coffee cake is awesome and perfect for parties.
</p>
<p>
Preparation time: 20 minutes
</p>
</body>
</html>

View File

@ -0,0 +1,37 @@
<html><head>
<title>Party Coffee Cake</title>
<script type=application/ld+json>{"@context":"https://schema.org/","@type":"Recipe","author":{"@type":"Person","name":"Mary Stone"},"datePublished":"2018-03-10","description":"This coffee cake is awesome and perfect for parties.","name":"Party Coffee Cake","prepTime":"PT20M"}</script>
<script type=application/ld+json crossorigin=anonymous>{"@context":"https://schema.org/","@type":"Recipe","author":{"@type":"Person","name":"Mary Stone"},"datePublished":"2018-03-10","description":"This coffee cake is awesome and perfect for parties.","name":"Party Coffee Cake","prepTime":"PT20M"}</script>
<script type=application/ld+json crossorigin=anonymous>
{
broken
</script>
<script type=unknown>
{
"@context": "https://schema.org/",
"@type": "Recipe",
"name": "Party Coffee Cake",
"author": {
"@type": "Person",
"name": "Mary Stone"
},
"datePublished": "2018-03-10",
"description": "This coffee cake is awesome and perfect for parties.",
"prepTime": "PT20M"
}
</script>
</head>
<body>
<h2>Party coffee cake recipe</h2>
<p>
<i>by Mary Stone, 2018-03-10</i>
</p>
<p>
This coffee cake is awesome and perfect for parties.
</p>
<p>
Preparation time: 20 minutes
</p>
</body></html>