diff --git a/crates/swc_html_minifier/src/lib.rs b/crates/swc_html_minifier/src/lib.rs index 0ca4fa68fc21..f3e71a6e86d9 100644 --- a/crates/swc_html_minifier/src/lib.rs +++ b/crates/swc_html_minifier/src/lib.rs @@ -318,7 +318,7 @@ struct Minifier { descendant_of_pre: bool, force_set_html5_doctype: bool, - collapse_whitespaces: Option, + collapse_whitespaces: CollapseWhitespaces, remove_comments: bool, preserve_comments: Option>, @@ -650,6 +650,10 @@ impl Minifier { false } + fn need_collapse_whitespace(&self) -> bool { + !matches!(self.collapse_whitespaces, CollapseWhitespaces::None) + } + fn get_display(&self, namespace: Namespace, tag_name: &str) -> Display { match namespace { Namespace::HTML => { @@ -836,13 +840,15 @@ impl Minifier { fn get_whitespace_minification_for_tag( &self, - mode: &CollapseWhitespaces, namespace: Namespace, tag_name: &str, ) -> WhitespaceMinificationMode { - let default_trim = match mode { + let default_trim = match self.collapse_whitespaces { CollapseWhitespaces::All => true, - CollapseWhitespaces::Smart | CollapseWhitespaces::Conservative => false, + CollapseWhitespaces::Smart + | CollapseWhitespaces::Conservative + | CollapseWhitespaces::OnlyMetadata + | CollapseWhitespaces::None => false, }; match namespace { @@ -952,10 +958,7 @@ impl Minifier { _ => return, }; - let mode = self - .collapse_whitespaces - .as_ref() - .map(|mode| self.get_whitespace_minification_for_tag(mode, namespace, tag_name)); + let mode = self.get_whitespace_minification_for_tag(namespace, tag_name); let child_will_be_retained = |child: &mut Child, prev: Option<&Child>, next: Option<&Child>| { @@ -963,26 +966,29 @@ impl Minifier { Child::Comment(comment) if self.remove_comments => { self.is_preserved_comment(&comment.data) } - // Always remove whitespaces from html and head elements (except nested - // elements), it should be safe + Child::Text(text) if text.data.is_empty() => false, Child::Text(text) - if namespace == Namespace::HTML + if self.need_collapse_whitespace() + && namespace == Namespace::HTML && matches!(&**tag_name, "html" | "head") && text.data.chars().all(is_whitespace) => { false } - Child::Text(text) if text.data.is_empty() => false, Child::Text(text) if !self.descendant_of_pre && get_white_space(namespace, tag_name) == WhiteSpace::Normal - && mode.is_some() => + && matches!( + self.collapse_whitespaces, + CollapseWhitespaces::All + | CollapseWhitespaces::Smart + | CollapseWhitespaces::Conservative + ) => { - let mode = mode.unwrap(); let mut is_smart_left_trim = false; let mut is_smart_right_trim = false; - if self.collapse_whitespaces == Some(CollapseWhitespaces::Smart) { + if self.collapse_whitespaces == CollapseWhitespaces::Smart { let prev_display = if let Some(Child::Element(Element { namespace, tag_name, @@ -1653,7 +1659,7 @@ impl VisitMut for Minifier { self.current_element = None; - if self.collapse_whitespaces == Some(CollapseWhitespaces::Smart) { + if self.need_collapse_whitespace() { self.latest_element = Some(n.clone()); } } @@ -1672,7 +1678,7 @@ impl VisitMut for Minifier { let old_descendant_of_pre = self.descendant_of_pre; - if self.collapse_whitespaces.is_some() && !old_descendant_of_pre { + if self.need_collapse_whitespace() && !old_descendant_of_pre { self.descendant_of_pre = get_white_space(n.namespace, &n.tag_name) == WhiteSpace::Pre; } @@ -1680,7 +1686,7 @@ impl VisitMut for Minifier { n.visit_mut_children_with(self); - if self.collapse_whitespaces.is_some() { + if self.need_collapse_whitespace() { self.descendant_of_pre = old_descendant_of_pre; } diff --git a/crates/swc_html_minifier/src/option.rs b/crates/swc_html_minifier/src/option.rs index 2994a9c34f79..451a55bc1cb2 100644 --- a/crates/swc_html_minifier/src/option.rs +++ b/crates/swc_html_minifier/src/option.rs @@ -12,14 +12,32 @@ pub enum MinifierType { Html, } +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +#[serde(rename_all = "kebab-case")] +pub enum CollapseWhitespaces { + /// Keep whitespaces + None, + /// Remove all whitespaces + All, + /// Remove and collapse whitespaces based on the `display` CSS property + Smart, + /// Remove and collapse multiple whitespace into one whitespace + Conservative, + /// Remove whitespace in the `head` element, trim whitespaces for the `body` + /// element, remove spaces between `metadata` elements (i.e. + /// `script`/`style`/etc) + OnlyMetadata, +} + #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] #[serde(deny_unknown_fields)] pub struct MinifyOptions { #[serde(default)] pub force_set_html5_doctype: bool, - #[serde(default)] - pub collapse_whitespaces: Option, + #[serde(default = "default_collapse_whitespaces")] + pub collapse_whitespaces: CollapseWhitespaces, #[serde(default = "true_by_default")] pub remove_comments: bool, #[serde(default = "default_preserve_comments")] @@ -76,13 +94,8 @@ impl Default for MinifyOptions { } } -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -#[serde(rename_all = "kebab-case")] -pub enum CollapseWhitespaces { - All, - Smart, - Conservative, +const fn default_collapse_whitespaces() -> CollapseWhitespaces { + CollapseWhitespaces::OnlyMetadata } const fn true_by_default() -> bool { diff --git a/crates/swc_html_minifier/tests/fixture/text/collapse-whitespace-disabled/config.json b/crates/swc_html_minifier/tests/fixture/text/collapse-whitespace-disabled/config.json new file mode 100644 index 000000000000..3631d0e846ff --- /dev/null +++ b/crates/swc_html_minifier/tests/fixture/text/collapse-whitespace-disabled/config.json @@ -0,0 +1,3 @@ +{ + "collapseWhitespaces": "none" +} \ No newline at end of file diff --git a/crates/swc_html_minifier/tests/fixture/text/collapse-whitespace-disabled/input.html b/crates/swc_html_minifier/tests/fixture/text/collapse-whitespace-disabled/input.html new file mode 100644 index 000000000000..b579ce15b599 --- /dev/null +++ b/crates/swc_html_minifier/tests/fixture/text/collapse-whitespace-disabled/input.html @@ -0,0 +1,290 @@ + + + + Document + + +
test
+ +
+

blah

+
+ +

blah

+ +
foo baz bar
+
foobazbar
+ +
foo bazbar
+
foobaz bar
+ +
foo baz bar
+
foo baz bar
+ +
foo baz bar
+
foo baz bar
+ +
Foo Bar
+
Foo Bar
+ +

+ The quick brown fox + jumps over the lazy + dog. +

+ +
    +
  • A
  • +
  • B
  • +
  • C
  • +
+ +

+ Hey, I just found + out about this cool website! + [1] +

+ +
+
+    Text
+
+    
+
+        Text
+
+    
+
+    
+
+        Text
+
+    
+
+
+ +
foo + + + + + bar
+ + + +
Text
+ +
Text
+ +
+ + + + + + + + + + + + + + + + + + + + <circle> + + + + + + + + + + + test + + + +
foo baz bar foo baz bar foo baz bar
+
+ foo baz bar foo baz bar foo baz bar +
+ +
+ foo +
+ +
+ text test test +
+ +testtest +test test + +
+ +

blah

+ +
+ +
test
test
+
test test
+
a c
+ +
a
b
+ +
a b
+
test
test
+
+
test
+ test +
+
+ test +
test
+
+
+ test + test +
+
+
test
+
test
+
+ +
+ test +

test

+

test

+

test

+
+ +
+

test

+

test

+

test

+ test +
+ +
+ + test + + test +
+ +
+ testtest +
+ +
+ +

blah

+ +
+ +
test
+
+
foo foo
+
foofoo
+
foo foo
+
foo foo
+
foofoo
+
foo foo
+
foo foo
+ +
foo
+

foo bar

+

foobar

+

foo bar

+

foo bar

+

foo bar

+

foo
bar

+

foo a bar

+
 fo o 
+
 fo o 
+

+

a b

+ +
foo bar
+
foo bar
+
foo bar
+

foo

+

foo

+ +
foo foo
+
foo foo foo
+
foo foo foo
+
foo foofoo
+ +
a b c
+
a b c
+
a b c
+ +
foo baz
+
foo baz
+
foo baz
+
foobaz
+ +test foo baz +foo baztest + +
test
foo baz +foo baz
test
+ +
+ + + +
+ +
+    foo
+    
+    baz
+
+ +
a c
+ +
Empty
+ + + +
foo bar
+ +
a b
+ +
a b c d
+ +
text
+ + text + text + + + \ No newline at end of file diff --git a/crates/swc_html_minifier/tests/fixture/text/collapse-whitespace-disabled/output.min.html b/crates/swc_html_minifier/tests/fixture/text/collapse-whitespace-disabled/output.min.html new file mode 100644 index 000000000000..ee8aeb754e2d --- /dev/null +++ b/crates/swc_html_minifier/tests/fixture/text/collapse-whitespace-disabled/output.min.html @@ -0,0 +1,274 @@ + + Document + +
test
+ +
+

blah

+
+ +

blah

+ +
foo baz bar
+
foobazbar
+ +
foo bazbar
+
foobaz bar
+ +
foo baz bar
+
foo baz bar
+ +
foo baz bar
+
foo baz bar
+ +
Foo Bar
+
Foo Bar
+ +

+ The quick brown fox + jumps over the lazy + dog. +

+ +
    +
  • A
  • +
  • B
  • +
  • C
  • +
+ +

+ Hey, I just found + out about this cool website! + [1] +

+ +
+
+    Text
+
+    
+
+        Text
+
+    
+
+    
+
+        Text
+
+    
+
+
+ +
foo + + + + + bar
+ + + +
Text
+ +
Text
+ +
+ + + + + + + + + + + + + + + + + + + + <circle> + + + + + + + + + + + test + + + +
foo baz bar foo baz bar foo baz bar
+
+ foo baz bar foo baz bar foo baz bar +
+ +
+ foo +
+ +
+ text test test +
+ +testtest +test test + +
+ +

blah

+ +
+ +
test
test
+
test test
+
a c
+ +
a
b
+ +
a b
+
test
test
+
+
test
+ test +
+
+ test +
test
+
+
+ test + test +
+
+
test
+
test
+
+ +
+ test +

test

+

test

+

test

+
+ +
+

test

+

test

+

test

+ test +
+ +
+ + test + + test +
+ +
+ testtest +
+ +
+ +

blah

+ +
+ +
test
+
+
foo foo
+
foofoo
+
foo foo
+
foo foo
+
foofoo
+
foo foo
+
foo foo
+ +
foo
+

foo bar

+

foobar

+

foo bar

+

foo bar

+

foo bar

+

foo
bar

+

foo a bar

+
 fo o 
+
 fo o 
+

+

a b

+ +
foo bar
+
foo bar
+
foo bar
+

foo

+

foo

+ +
foo foo
+
foo foo foo
+
foo foo foo
+
foo foofoo
+ +
a b c
+
a b c
+
a b c
+ +
foo baz
+
foo baz
+
foo baz
+
foobaz
+ +test foo baz +foo baztest + +
test
foo baz +foo baz
test
+ +
+ + + +
+ +
+    foo
+    
+    baz
+
+ +
a c
+ +
Empty
+ + + +
foo bar
+ +
a b
+ +
a b c d
+ +
text
+ + text + text \ No newline at end of file diff --git a/crates/swc_html_minifier/tests/fixture/text/collapse-whitespace-only-metadata/config.json b/crates/swc_html_minifier/tests/fixture/text/collapse-whitespace-only-metadata/config.json new file mode 100644 index 000000000000..1e5187093c5c --- /dev/null +++ b/crates/swc_html_minifier/tests/fixture/text/collapse-whitespace-only-metadata/config.json @@ -0,0 +1,3 @@ +{ + "collapseWhitespaces": "only-metadata" +} \ No newline at end of file diff --git a/crates/swc_html_minifier/tests/fixture/text/collapse-whitespace-only-metadata/input.html b/crates/swc_html_minifier/tests/fixture/text/collapse-whitespace-only-metadata/input.html new file mode 100644 index 000000000000..b579ce15b599 --- /dev/null +++ b/crates/swc_html_minifier/tests/fixture/text/collapse-whitespace-only-metadata/input.html @@ -0,0 +1,290 @@ + + + + Document + + +
test
+ +
+

blah

+
+ +

blah

+ +
foo baz bar
+
foobazbar
+ +
foo bazbar
+
foobaz bar
+ +
foo baz bar
+
foo baz bar
+ +
foo baz bar
+
foo baz bar
+ +
Foo Bar
+
Foo Bar
+ +

+ The quick brown fox + jumps over the lazy + dog. +

+ +
    +
  • A
  • +
  • B
  • +
  • C
  • +
+ +

+ Hey, I just found + out about this cool website! + [1] +

+ +
+
+    Text
+
+    
+
+        Text
+
+    
+
+    
+
+        Text
+
+    
+
+
+ +
foo + + + + + bar
+ + + +
Text
+ +
Text
+ +
+ + + + + + + + + + + + + + + + + + + + <circle> + + + + + + + + + + + test + + + +
foo baz bar foo baz bar foo baz bar
+
+ foo baz bar foo baz bar foo baz bar +
+ +
+ foo +
+ +
+ text test test +
+ +testtest +test test + +
+ +

blah

+ +
+ +
test
test
+
test test
+
a c
+ +
a
b
+ +
a b
+
test
test
+
+
test
+ test +
+
+ test +
test
+
+
+ test + test +
+
+
test
+
test
+
+ +
+ test +

test

+

test

+

test

+
+ +
+

test

+

test

+

test

+ test +
+ +
+ + test + + test +
+ +
+ testtest +
+ +
+ +

blah

+ +
+ +
test
+
+
foo foo
+
foofoo
+
foo foo
+
foo foo
+
foofoo
+
foo foo
+
foo foo
+ +
foo
+

foo bar

+

foobar

+

foo bar

+

foo bar

+

foo bar

+

foo
bar

+

foo a bar

+
 fo o 
+
 fo o 
+

+

a b

+ +
foo bar
+
foo bar
+
foo bar
+

foo

+

foo

+ +
foo foo
+
foo foo foo
+
foo foo foo
+
foo foofoo
+ +
a b c
+
a b c
+
a b c
+ +
foo baz
+
foo baz
+
foo baz
+
foobaz
+ +test foo baz +foo baztest + +
test
foo baz +foo baz
test
+ +
+ + + +
+ +
+    foo
+    
+    baz
+
+ +
a c
+ +
Empty
+ + + +
foo bar
+ +
a b
+ +
a b c d
+ +
text
+ + text + text + + + \ No newline at end of file diff --git a/crates/swc_html_minifier/tests/fixture/text/collapse-whitespace-only-metadata/output.min.html b/crates/swc_html_minifier/tests/fixture/text/collapse-whitespace-only-metadata/output.min.html new file mode 100644 index 000000000000..51fd7248b36a --- /dev/null +++ b/crates/swc_html_minifier/tests/fixture/text/collapse-whitespace-only-metadata/output.min.html @@ -0,0 +1,271 @@ +Document
test
+ +
+

blah

+
+ +

blah

+ +
foo baz bar
+
foobazbar
+ +
foo bazbar
+
foobaz bar
+ +
foo baz bar
+
foo baz bar
+ +
foo baz bar
+
foo baz bar
+ +
Foo Bar
+
Foo Bar
+ +

+ The quick brown fox + jumps over the lazy + dog. +

+ +
    +
  • A
  • +
  • B
  • +
  • C
  • +
+ +

+ Hey, I just found + out about this cool website! + [1] +

+ +
+
+    Text
+
+    
+
+        Text
+
+    
+
+    
+
+        Text
+
+    
+
+
+ +
foo + + + + + bar
+ + + +
Text
+ +
Text
+ +
+ + + + + + + + + + + + + + + + + + + + <circle> + + + + + + + + + + + test + + + +
foo baz bar foo baz bar foo baz bar
+
+ foo baz bar foo baz bar foo baz bar +
+ +
+ foo +
+ +
+ text test test +
+ +testtest +test test + +
+ +

blah

+ +
+ +
test
test
+
test test
+
a c
+ +
a
b
+ +
a b
+
test
test
+
+
test
+ test +
+
+ test +
test
+
+
+ test + test +
+
+
test
+
test
+
+ +
+ test +

test

+

test

+

test

+
+ +
+

test

+

test

+

test

+ test +
+ +
+ + test + + test +
+ +
+ testtest +
+ +
+ +

blah

+ +
+ +
test
+
+
foo foo
+
foofoo
+
foo foo
+
foo foo
+
foofoo
+
foo foo
+
foo foo
+ +
foo
+

foo bar

+

foobar

+

foo bar

+

foo bar

+

foo bar

+

foo
bar

+

foo a bar

+
 fo o 
+
 fo o 
+

+

a b

+ +
foo bar
+
foo bar
+
foo bar
+

foo

+

foo

+ +
foo foo
+
foo foo foo
+
foo foo foo
+
foo foofoo
+ +
a b c
+
a b c
+
a b c
+ +
foo baz
+
foo baz
+
foo baz
+
foobaz
+ +test foo baz +foo baztest + +
test
foo baz +foo baz
test
+ +
+ + + +
+ +
+    foo
+    
+    baz
+
+ +
a c
+ +
Empty
+ + + +
foo bar
+ +
a b
+ +
a b c d
+ +
text
+ + text + text \ No newline at end of file