diff --git a/crates/swc_html_minifier/src/lib.rs b/crates/swc_html_minifier/src/lib.rs
index b6f743da2085..563aad1aa493 100644
--- a/crates/swc_html_minifier/src/lib.rs
+++ b/crates/swc_html_minifier/src/lib.rs
@@ -8,8 +8,8 @@ use serde_json::Value;
use swc_atoms::{js_word, JsWord};
use swc_cached::regex::CachedRegex;
use swc_common::{
- collections::AHashMap, comments::SingleThreadedComments, sync::Lrc, FileName, FilePathMapping,
- Mark, SourceMap, DUMMY_SP,
+ collections::AHashMap, comments::SingleThreadedComments, sync::Lrc, EqIgnoreSpan, FileName,
+ FilePathMapping, Mark, SourceMap, DUMMY_SP,
};
use swc_html_ast::*;
use swc_html_parser::parser::ParserConfig;
@@ -1201,6 +1201,39 @@ impl Minifier<'_> {
true
}
+ fn allow_elements_to_merge(&self, left: Option<&Child>, right: &Element) -> bool {
+ if let Some(left) = left {
+ return matches!((left, right), (Child::Element(left), right)
+ if matches!(left.namespace, Namespace::HTML | Namespace::SVG)
+ && left.tag_name == js_word!("style")
+ && matches!(right.namespace, Namespace::HTML | Namespace::SVG)
+ && right.tag_name == js_word!("style")
+ && left.attributes.eq_ignore_span(&right.attributes));
+ }
+
+ false
+ }
+
+ fn merge_text_children(&self, left: &Element, right: &Element) -> Vec {
+ let data = left.children.iter().chain(right.children.iter()).fold(
+ String::new(),
+ |mut acc, child| match child {
+ Child::Text(text) => {
+ acc.push_str(&text.data);
+
+ acc
+ }
+ _ => acc,
+ },
+ );
+
+ vec![Child::Text(Text {
+ span: DUMMY_SP,
+ data: data.into(),
+ raw: None,
+ })]
+ }
+
fn minify_children(&mut self, children: &mut Vec) -> Vec {
let (namespace, tag_name) = match &self.current_element {
Some(element) => (element.namespace, &element.tag_name),
@@ -1212,7 +1245,7 @@ impl Minifier<'_> {
let mode = self.get_whitespace_minification_for_tag(namespace, tag_name);
let child_will_be_retained =
- |child: &mut Child, prev_children: &Vec, next_children: &Vec| {
+ |child: &mut Child, prev_children: &mut Vec, next_children: &mut Vec| {
match child {
Child::Comment(comment) if self.options.remove_comments => {
self.is_preserved_comment(&comment.data)
@@ -1233,6 +1266,16 @@ impl Minifier<'_> {
{
false
}
+ Child::Element(element)
+ if self.options.merge_metadata_elements
+ && self.allow_elements_to_merge(prev_children.last(), element) =>
+ {
+ if let Some(Child::Element(prev)) = prev_children.last_mut() {
+ prev.children = self.merge_text_children(prev, element);
+ }
+
+ false
+ }
Child::Text(text) if text.data.is_empty() => false,
Child::Text(text)
if self.need_collapse_whitespace()
@@ -1539,7 +1582,7 @@ impl Minifier<'_> {
}
};
- let result = child_will_be_retained(&mut child, &new_children, children);
+ let result = child_will_be_retained(&mut child, &mut new_children, children);
if result {
new_children.push(child);
diff --git a/crates/swc_html_minifier/src/option.rs b/crates/swc_html_minifier/src/option.rs
index 74931134b61b..c40c9c6fb017 100644
--- a/crates/swc_html_minifier/src/option.rs
+++ b/crates/swc_html_minifier/src/option.rs
@@ -140,6 +140,10 @@ pub struct MinifyOptions {
pub remove_redundant_attributes: bool,
#[serde(default = "true_by_default")]
pub collapse_boolean_attributes: bool,
+ /// Merge the same metadata elements into one (for example, consecutive
+ /// `style` elements will be merged into one `style` element)
+ #[serde(default = "true_by_default")]
+ pub merge_metadata_elements: bool,
/// Remove extra whitespace in space and comma separated attribute values
/// (where it is safe) and remove `javascript:` prefix for event handler
/// attributes
diff --git a/crates/swc_html_minifier/tests/fixture/attribute/custom-attribute/input.html b/crates/swc_html_minifier/tests/fixture/attribute/custom-attribute/input.html
index d43b283a6a11..bbc3f84f4fea 100644
--- a/crates/swc_html_minifier/tests/fixture/attribute/custom-attribute/input.html
+++ b/crates/swc_html_minifier/tests/fixture/attribute/custom-attribute/input.html
@@ -10,6 +10,8 @@
+
+
diff --git a/crates/swc_html_minifier/tests/fixture/attribute/custom-attribute/output.min.html b/crates/swc_html_minifier/tests/fixture/attribute/custom-attribute/output.min.html
index b79c6b143454..31e213f41d74 100644
--- a/crates/swc_html_minifier/tests/fixture/attribute/custom-attribute/output.min.html
+++ b/crates/swc_html_minifier/tests/fixture/attribute/custom-attribute/output.min.html
@@ -1,6 +1,8 @@
Document
+
+
\ No newline at end of file
diff --git a/crates/swc_html_minifier/tests/fixture/attribute/srcdoc/input.html b/crates/swc_html_minifier/tests/fixture/attribute/srcdoc/input.html
new file mode 100644
index 000000000000..d5699a5cf5bf
--- /dev/null
+++ b/crates/swc_html_minifier/tests/fixture/attribute/srcdoc/input.html
@@ -0,0 +1,9 @@
+
+
+
+ Document
+
+
+
+
+
\ No newline at end of file
diff --git a/crates/swc_html_minifier/tests/fixture/attribute/srcdoc/output.min.html b/crates/swc_html_minifier/tests/fixture/attribute/srcdoc/output.min.html
new file mode 100644
index 000000000000..cee262308af6
--- /dev/null
+++ b/crates/swc_html_minifier/tests/fixture/attribute/srcdoc/output.min.html
@@ -0,0 +1 @@
+Document
\ No newline at end of file
diff --git a/crates/swc_html_minifier/tests/fixture/element/custom/input.html b/crates/swc_html_minifier/tests/fixture/element/custom/input.html
index d7b5cc76c7d8..b860e1797250 100644
--- a/crates/swc_html_minifier/tests/fixture/element/custom/input.html
+++ b/crates/swc_html_minifier/tests/fixture/element/custom/input.html
@@ -10,5 +10,6 @@
Hello :)
+
Click here and here
\ No newline at end of file
diff --git a/crates/swc_html_minifier/tests/fixture/element/custom/output.min.html b/crates/swc_html_minifier/tests/fixture/element/custom/output.min.html
index 425f07211f34..5e531192aa2d 100644
--- a/crates/swc_html_minifier/tests/fixture/element/custom/output.min.html
+++ b/crates/swc_html_minifier/tests/fixture/element/custom/output.min.html
@@ -3,4 +3,5 @@
[\']["]
Hello :)
-
\ No newline at end of file
+
+
Click here and here
\ No newline at end of file
diff --git a/crates/swc_html_minifier/tests/fixture/element/style-group-1/config.json b/crates/swc_html_minifier/tests/fixture/element/style-group-1/config.json
new file mode 100644
index 000000000000..c1343bc13e51
--- /dev/null
+++ b/crates/swc_html_minifier/tests/fixture/element/style-group-1/config.json
@@ -0,0 +1,3 @@
+{
+ "removeEmptyMetadataElements": false
+}
diff --git a/crates/swc_html_minifier/tests/fixture/element/style-group-1/input.html b/crates/swc_html_minifier/tests/fixture/element/style-group-1/input.html
new file mode 100644
index 000000000000..634842353c31
--- /dev/null
+++ b/crates/swc_html_minifier/tests/fixture/element/style-group-1/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-1/output.min.html b/crates/swc_html_minifier/tests/fixture/element/style-group-1/output.min.html
new file mode 100644
index 000000000000..c80d458981d0
--- /dev/null
+++ b/crates/swc_html_minifier/tests/fixture/element/style-group-1/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/input.html b/crates/swc_html_minifier/tests/fixture/element/style-group/input.html
new file mode 100644
index 000000000000..104ff9737aa0
--- /dev/null
+++ b/crates/swc_html_minifier/tests/fixture/element/style-group/input.html
@@ -0,0 +1,76 @@
+
+
+
+ Document
+
+
+
+
+
+
+
+
+
+
+
+
Text
+
Text
+
+
+
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
new file mode 100644
index 000000000000..82a7f7fca393
--- /dev/null
+++ b/crates/swc_html_minifier/tests/fixture/element/style-group/output.min.html
@@ -0,0 +1,8 @@
+Document
Text
+
Text
+
+
test
+
+
test
+
+
\ No newline at end of file
diff --git a/crates/swc_html_minifier/tests/fixture/element/style/output.min.html b/crates/swc_html_minifier/tests/fixture/element/style/output.min.html
index 9dbc891e19ed..148cc3bc5434 100644
--- a/crates/swc_html_minifier/tests/fixture/element/style/output.min.html
+++ b/crates/swc_html_minifier/tests/fixture/element/style/output.min.html
@@ -4,7 +4,7 @@
-
+