From 35466322d6c2e3d09c9d43e0ce773203c9d239b1 Mon Sep 17 00:00:00 2001 From: Alexander Akait <4567934+alexander-akait@users.noreply.github.com> Date: Wed, 19 Oct 2022 06:25:18 +0300 Subject: [PATCH] fix(html/minifier): Fix bugs of merging and removing metadata elements (#6200) --- crates/swc_html_minifier/src/lib.rs | 65 ++++++++++++++----- .../fixture/element/style-group-2/config.json | 4 ++ .../fixture/element/style-group-2/input.html | 64 ++++++++++++++++++ .../element/style-group-2/output.min.html | 4 ++ .../element/style-group/output.min.html | 1 - 5 files changed, 120 insertions(+), 18 deletions(-) create mode 100644 crates/swc_html_minifier/tests/fixture/element/style-group-2/config.json create mode 100644 crates/swc_html_minifier/tests/fixture/element/style-group-2/input.html create mode 100644 crates/swc_html_minifier/tests/fixture/element/style-group-2/output.min.html diff --git a/crates/swc_html_minifier/src/lib.rs b/crates/swc_html_minifier/src/lib.rs index 88f97ec90c4a..36f56e6fdd55 100644 --- a/crates/swc_html_minifier/src/lib.rs +++ b/crates/swc_html_minifier/src/lib.rs @@ -1204,7 +1204,25 @@ impl Minifier<'_> { None } - fn empty_children(&self, children: &Vec) -> bool { + fn is_empty_metadata_element(&self, child: &Child) -> bool { + if let Child::Element(element) = child { + if (!self.is_element_displayed(element.namespace, &element.tag_name) + || (matches!(element.namespace, Namespace::HTML | Namespace::SVG) + && element.tag_name == js_word!("script")) + || (element.namespace == Namespace::HTML + && element.tag_name == js_word!("noscript"))) + && element.attributes.is_empty() + && self.is_empty_children(&element.children) + && element.content.is_none() + { + return true; + } + } + + false + } + + fn is_empty_children(&self, children: &Vec) -> bool { for child in children { match child { Child::Text(text) if text.data.chars().all(is_whitespace) => { @@ -1251,6 +1269,10 @@ impl Minifier<'_> { } fn minify_children(&mut self, children: &mut Vec) -> Vec { + if children.is_empty() { + return vec![]; + } + let (namespace, tag_name) = match &self.current_element { Some(element) => (element.namespace, &element.tag_name), _ => { @@ -1266,22 +1288,6 @@ impl Minifier<'_> { Child::Comment(comment) if self.options.remove_comments => { self.is_preserved_comment(&comment.data) } - Child::Element(element) - if self.options.remove_empty_metadata_elements - && (!self - .is_element_displayed(element.namespace, &element.tag_name) - || (matches!( - element.namespace, - Namespace::HTML | Namespace::SVG - ) && element.tag_name == js_word!("script")) - || (element.namespace == Namespace::HTML - && element.tag_name == js_word!("noscript"))) - && element.attributes.is_empty() - && self.empty_children(&element.children) - && element.content.is_none() => - { - false - } Child::Element(element) if self.options.merge_metadata_elements && self.allow_elements_to_merge(prev_children.last(), element) => @@ -1601,6 +1607,31 @@ impl Minifier<'_> { let result = child_will_be_retained(&mut child, &mut new_children, children); if result { + if self.options.remove_redundant_attributes + && self.is_empty_metadata_element(&child) + { + let need_continue = { + let next_element = if let Some(Child::Element(element)) = children.get(0) { + Some(element) + } else if let Some(Child::Element(element)) = children.get(1) { + Some(element) + } else { + None + }; + + if let Some(element) = next_element { + self.options.merge_metadata_elements + && !self.allow_elements_to_merge(Some(&child), element) + } else { + true + } + }; + + if need_continue { + continue; + } + } + new_children.push(child); } } diff --git a/crates/swc_html_minifier/tests/fixture/element/style-group-2/config.json b/crates/swc_html_minifier/tests/fixture/element/style-group-2/config.json new file mode 100644 index 000000000000..51608d00a98a --- /dev/null +++ b/crates/swc_html_minifier/tests/fixture/element/style-group-2/config.json @@ -0,0 +1,4 @@ +{ + "mergeMetadataElements": false, + "removeEmptyMetadataElements": false +} diff --git a/crates/swc_html_minifier/tests/fixture/element/style-group-2/input.html b/crates/swc_html_minifier/tests/fixture/element/style-group-2/input.html new file mode 100644 index 000000000000..634842353c31 --- /dev/null +++ b/crates/swc_html_minifier/tests/fixture/element/style-group-2/input.html @@ -0,0 +1,64 @@ + + + + Document + + + + + + + + + + + +
test
+ + +
test
+ + + + \ No newline at end of file diff --git a/crates/swc_html_minifier/tests/fixture/element/style-group-2/output.min.html b/crates/swc_html_minifier/tests/fixture/element/style-group-2/output.min.html new file mode 100644 index 000000000000..10c43b6212e5 --- /dev/null +++ b/crates/swc_html_minifier/tests/fixture/element/style-group-2/output.min.html @@ -0,0 +1,4 @@ +Document
test
+ +
test
+ \ No newline at end of file diff --git a/crates/swc_html_minifier/tests/fixture/element/style-group/output.min.html b/crates/swc_html_minifier/tests/fixture/element/style-group/output.min.html index 82a7f7fca393..a5e2c3ab00ec 100644 --- a/crates/swc_html_minifier/tests/fixture/element/style-group/output.min.html +++ b/crates/swc_html_minifier/tests/fixture/element/style-group/output.min.html @@ -4,5 +4,4 @@
test
test
- \ No newline at end of file