diff --git a/crates/swc_html_minifier/src/lib.rs b/crates/swc_html_minifier/src/lib.rs index dbb855c50104..f64873216cee 100644 --- a/crates/swc_html_minifier/src/lib.rs +++ b/crates/swc_html_minifier/src/lib.rs @@ -221,10 +221,10 @@ static COMMA_SEPARATED_SVG_ATTRIBUTES: &[(&str, &str)] = &[("style", "media")]; static SPACE_SEPARATED_GLOBAL_ATTRIBUTES: &[&str] = &[ "class", - "part", - "itemtype", - "itemref", "itemprop", + "itemref", + "itemtype", + "part", "accesskey", "aria-describedby", "aria-labelledby", @@ -238,15 +238,16 @@ static SPACE_SEPARATED_HTML_ATTRIBUTES: &[(&str, &str)] = &[ ("area", "ping"), ("link", "rel"), ("link", "sizes"), - ("input", "autocomplete"), - ("form", "autocomplete"), + ("link", "blocking"), ("iframe", "sandbox"), ("td", "headers"), ("th", "headers"), ("output", "for"), - ("link", "blocking"), ("script", "blocking"), ("style", "blocking"), + ("input", "autocomplete"), + ("form", "rel"), + ("form", "autocomplete"), ]; enum CssMinificationMode { @@ -331,6 +332,8 @@ struct Minifier { minify_css: bool, minify_additional_attributes: Option>, minify_additional_scripts_content: Option>, + + sort_space_separated_attribute_values: bool, } fn get_white_space(namespace: Namespace, tag_name: &str) -> WhiteSpace { @@ -418,16 +421,40 @@ impl Minifier { } } - fn is_additional_minifier_attribute(&self, name: &str) -> Option { - if let Some(minify_additional_attributes) = &self.minify_additional_attributes { - for item in minify_additional_attributes { - if item.0.is_match(name) { - return Some(item.1.clone()); - } - } + fn is_attribute_value_unordered_set(&self, element: &Element, attribute_name: &str) -> bool { + if matches!( + attribute_name, + "class" | "part" | "itemprop" | "itemref" | "itemtype" + ) { + return true; } - None + match element.namespace { + Namespace::HTML => match &*element.tag_name { + "link" if attribute_name == "blocking" => true, + "script" if attribute_name == "blocking" => true, + "style" if attribute_name == "blocking" => true, + "output" if attribute_name == "for" => true, + "td" if attribute_name == "headers" => true, + "th" if attribute_name == "headers" => true, + "form" if attribute_name == "rel" => true, + "a" if attribute_name == "rel" => true, + "area" if attribute_name == "rel" => true, + "link" if attribute_name == "rel" => true, + "iframe" if attribute_name == "sandbox" => true, + "link" + if self.element_has_attribute_with_value( + element, + "rel", + &["icon", "apple-touch-icon", "apple-touch-icon-precomposed"], + ) && attribute_name == "sizes" => + { + true + } + _ => false, + }, + _ => false, + } } fn element_has_attribute_with_value( @@ -866,6 +893,18 @@ impl Minifier { collapsed } + fn is_additional_minifier_attribute(&self, name: &str) -> Option { + if let Some(minify_additional_attributes) = &self.minify_additional_attributes { + for item in minify_additional_attributes { + if item.0.is_match(name) { + return Some(item.1.clone()); + } + } + } + + None + } + fn minify_children(&mut self, children: &mut Vec) { let (namespace, tag_name) = match &self.current_element { Some(element) => (element.namespace, &element.tag_name), @@ -1472,6 +1511,7 @@ impl Minifier { minify_css: self.minify_css, minify_additional_scripts_content: self.minify_additional_scripts_content.clone(), minify_additional_attributes: self.minify_additional_attributes.clone(), + sort_space_separated_attribute_values: self.sort_space_separated_attribute_values, }; match document_or_document_fragment { @@ -1735,12 +1775,12 @@ impl VisitMut for Minifier { } } - if &*n.name == "class" { + if self.sort_space_separated_attribute_values + && self.is_attribute_value_unordered_set(current_element, &n.name) + { let mut values = value.split_whitespace().collect::>(); - if &*n.name == "class" { - values.sort_unstable(); - } + values.sort_unstable(); value = values.join(" "); } else if self.is_event_handler_attribute(&n.name) { @@ -2025,6 +2065,8 @@ fn create_minifier(context_element: Option<&Element>, options: &MinifyOptions) - minify_css: options.minify_css, minify_additional_attributes: options.minify_additional_attributes.clone(), minify_additional_scripts_content: options.minify_additional_scripts_content.clone(), + + sort_space_separated_attribute_values: options.sort_space_separated_attribute_values, } } diff --git a/crates/swc_html_minifier/src/option.rs b/crates/swc_html_minifier/src/option.rs index b8091798a031..2994a9c34f79 100644 --- a/crates/swc_html_minifier/src/option.rs +++ b/crates/swc_html_minifier/src/option.rs @@ -49,14 +49,6 @@ pub struct MinifyOptions { pub minify_json: bool, #[serde(default = "true_by_default")] pub minify_css: bool, - /// Allow to compress value of custom attributes, - /// i.e. `
` - /// - /// The first item is tag_name - /// The second is attribute name - /// The third is type of minifier - #[serde(default)] - pub minify_additional_attributes: Option>, // Allow to compress value of custom script elements, // i.e. `` // @@ -65,6 +57,16 @@ pub struct MinifyOptions { // The third is type of minifier #[serde(default)] pub minify_additional_scripts_content: Option>, + /// Allow to compress value of custom attributes, + /// i.e. `
` + /// + /// The first item is tag_name + /// The second is attribute name + /// The third is type of minifier + pub minify_additional_attributes: Option>, + /// Sorting the values of `class`, `rel`, etc. of attributes + #[serde(default = "true_by_default")] + pub sort_space_separated_attribute_values: bool, } /// Implement default using serde. diff --git a/crates/swc_html_minifier/tests/fixture/attribute/disabled-normalize_attributes/output.min.html b/crates/swc_html_minifier/tests/fixture/attribute/disabled-normalize_attributes/output.min.html index 53871d1dbf80..b4c123c2b3cb 100644 --- a/crates/swc_html_minifier/tests/fixture/attribute/disabled-normalize_attributes/output.min.html +++ b/crates/swc_html_minifier/tests/fixture/attribute/disabled-normalize_attributes/output.min.html @@ -1,2 +1,2 @@ -Document +Document
\ No newline at end of file diff --git a/crates/swc_html_minifier/tests/fixture/attribute/disabled-sort-classes/config.json b/crates/swc_html_minifier/tests/fixture/attribute/disabled-sort-classes/config.json new file mode 100644 index 000000000000..c5f920933712 --- /dev/null +++ b/crates/swc_html_minifier/tests/fixture/attribute/disabled-sort-classes/config.json @@ -0,0 +1,3 @@ +{ + "sortSpaceSeparatedAttributeValues": false +} \ No newline at end of file diff --git a/crates/swc_html_minifier/tests/fixture/attribute/disabled-sort-classes/input.html b/crates/swc_html_minifier/tests/fixture/attribute/disabled-sort-classes/input.html new file mode 100644 index 000000000000..10fdeda9e661 --- /dev/null +++ b/crates/swc_html_minifier/tests/fixture/attribute/disabled-sort-classes/input.html @@ -0,0 +1,10 @@ + + + + + Document + + +
+ + \ No newline at end of file diff --git a/crates/swc_html_minifier/tests/fixture/attribute/disabled-sort-classes/output.min.html b/crates/swc_html_minifier/tests/fixture/attribute/disabled-sort-classes/output.min.html new file mode 100644 index 000000000000..f2d19c943072 --- /dev/null +++ b/crates/swc_html_minifier/tests/fixture/attribute/disabled-sort-classes/output.min.html @@ -0,0 +1 @@ +Document
\ No newline at end of file diff --git a/crates/swc_html_minifier/tests/fixture/attribute/headers/input.html b/crates/swc_html_minifier/tests/fixture/attribute/headers/input.html index c5d6521aa9a2..ffd9e6976497 100644 --- a/crates/swc_html_minifier/tests/fixture/attribute/headers/input.html +++ b/crates/swc_html_minifier/tests/fixture/attribute/headers/input.html @@ -21,6 +21,12 @@ +45342323 Rosevn 56,4300 Sandnes,Norway + + John Doe + someone@example.com + +45342323 + Rosevn 56,4300 Sandnes,Norway + \ No newline at end of file diff --git a/crates/swc_html_minifier/tests/fixture/attribute/headers/output.min.html b/crates/swc_html_minifier/tests/fixture/attribute/headers/output.min.html index ec562270104a..34562677a317 100644 --- a/crates/swc_html_minifier/tests/fixture/attribute/headers/output.min.html +++ b/crates/swc_html_minifier/tests/fixture/attribute/headers/output.min.html @@ -11,4 +11,10 @@ +45342323 Rosevn 56,4300 Sandnes,Norway + + John Doe + someone@example.com + +45342323 + Rosevn 56,4300 Sandnes,Norway + \ No newline at end of file diff --git a/crates/swc_html_minifier/tests/fixture/attribute/itemtype/output.min.html b/crates/swc_html_minifier/tests/fixture/attribute/itemtype/output.min.html index 80f4f6adf8e0..2d9be1df9c0f 100644 --- a/crates/swc_html_minifier/tests/fixture/attribute/itemtype/output.min.html +++ b/crates/swc_html_minifier/tests/fixture/attribute/itemtype/output.min.html @@ -11,7 +11,7 @@ in excellent condition
In stock! Order now! -
+
Name:
Tank Locomotive (DB 80)
Product code: diff --git a/crates/swc_html_minifier/tests/fixture/attribute/link/input.html b/crates/swc_html_minifier/tests/fixture/attribute/link/input.html index 4a045e0a326e..5caf821484cf 100644 --- a/crates/swc_html_minifier/tests/fixture/attribute/link/input.html +++ b/crates/swc_html_minifier/tests/fixture/attribute/link/input.html @@ -8,6 +8,20 @@ + + + + + + + + + + + +
test
diff --git a/crates/swc_html_minifier/tests/fixture/attribute/link/output.min.html b/crates/swc_html_minifier/tests/fixture/attribute/link/output.min.html index fab621e34358..b97cb4407a19 100644 --- a/crates/swc_html_minifier/tests/fixture/attribute/link/output.min.html +++ b/crates/swc_html_minifier/tests/fixture/attribute/link/output.min.html @@ -1 +1 @@ -Document
test
\ No newline at end of file +Document
test
\ No newline at end of file diff --git a/crates/swc_html_minifier/tests/fixture/attribute/part/output.min.html b/crates/swc_html_minifier/tests/fixture/attribute/part/output.min.html index 0b5a3d8eebad..d8fa624da376 100644 --- a/crates/swc_html_minifier/tests/fixture/attribute/part/output.min.html +++ b/crates/swc_html_minifier/tests/fixture/attribute/part/output.min.html @@ -1,7 +1,7 @@ Document \ No newline at end of file diff --git a/crates/swc_html_minifier/tests/fixture/attribute/rel/input.html b/crates/swc_html_minifier/tests/fixture/attribute/rel/input.html index a81310f664c5..796f3c7e69f9 100644 --- a/crates/swc_html_minifier/tests/fixture/attribute/rel/input.html +++ b/crates/swc_html_minifier/tests/fixture/attribute/rel/input.html @@ -7,5 +7,9 @@ Link Link Link +
+ + +
\ No newline at end of file diff --git a/crates/swc_html_minifier/tests/fixture/attribute/rel/output.min.html b/crates/swc_html_minifier/tests/fixture/attribute/rel/output.min.html index 97b0740ad52e..86da69997e9a 100644 --- a/crates/swc_html_minifier/tests/fixture/attribute/rel/output.min.html +++ b/crates/swc_html_minifier/tests/fixture/attribute/rel/output.min.html @@ -1,3 +1,7 @@ -DocumentLink -Link -Link \ No newline at end of file +DocumentLink +Link +Link +
+ + +
\ No newline at end of file diff --git a/crates/swc_html_minifier/tests/fixture/element/iframe/output.min.html b/crates/swc_html_minifier/tests/fixture/element/iframe/output.min.html index 89858418a885..a13eb63c8ff9 100644 --- a/crates/swc_html_minifier/tests/fixture/element/iframe/output.min.html +++ b/crates/swc_html_minifier/tests/fixture/element/iframe/output.min.html @@ -1 +1 @@ -Document \ No newline at end of file +Document \ No newline at end of file diff --git a/crates/swc_html_minifier/tests/fixture/element/output/input.html b/crates/swc_html_minifier/tests/fixture/element/output/input.html new file mode 100644 index 000000000000..aaeee57007bd --- /dev/null +++ b/crates/swc_html_minifier/tests/fixture/element/output/input.html @@ -0,0 +1,16 @@ + + + + + + Document + + +
+ + + = + 60 +
+ + \ No newline at end of file diff --git a/crates/swc_html_minifier/tests/fixture/element/output/output.min.html b/crates/swc_html_minifier/tests/fixture/element/output/output.min.html new file mode 100644 index 000000000000..395164dc12d5 --- /dev/null +++ b/crates/swc_html_minifier/tests/fixture/element/output/output.min.html @@ -0,0 +1,5 @@ +Document
+ + + = + 60 +
\ No newline at end of file diff --git a/crates/swc_html_minifier/tests/fixture/element/script/input.html b/crates/swc_html_minifier/tests/fixture/element/script/input.html index 9ab29aa356f5..fced9c2e9ffc 100644 --- a/crates/swc_html_minifier/tests/fixture/element/script/input.html +++ b/crates/swc_html_minifier/tests/fixture/element/script/input.html @@ -181,5 +181,6 @@

Party coffee cake recipe

alert('test') + diff --git a/crates/swc_html_minifier/tests/fixture/element/script/output.min.html b/crates/swc_html_minifier/tests/fixture/element/script/output.min.html index 9fa486fca056..e396a1bbb6ac 100644 --- a/crates/swc_html_minifier/tests/fixture/element/script/output.min.html +++ b/crates/swc_html_minifier/tests/fixture/element/script/output.min.html @@ -53,4 +53,5 @@ alert('test') - \ No newline at end of file + + \ No newline at end of file diff --git a/crates/swc_html_minifier/tests/fixture/element/style/input.html b/crates/swc_html_minifier/tests/fixture/element/style/input.html index ef4e8a4d8b00..92eb5ff820d7 100644 --- a/crates/swc_html_minifier/tests/fixture/element/style/input.html +++ b/crates/swc_html_minifier/tests/fixture/element/style/input.html @@ -60,5 +60,6 @@ } + \ 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 2f66caeb94a2..2fe67eadc5bf 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 @@ -23,4 +23,5 @@ color: red } - \ No newline at end of file + + \ No newline at end of file