From 8b3c08275b6d2df4433d6b7b40c79dbf0e1db310 Mon Sep 17 00:00:00 2001 From: "alexander.akait" Date: Thu, 15 Dec 2022 21:01:06 +0300 Subject: [PATCH 1/5] test: more --- .../fixture/compress-at-rule/supports/input.css | 12 ++++++++++++ .../fixture/compress-at-rule/supports/output.min.css | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/crates/swc_css_minifier/tests/fixture/compress-at-rule/supports/input.css b/crates/swc_css_minifier/tests/fixture/compress-at-rule/supports/input.css index 3dbdf527f0fe..26c9a8a534df 100644 --- a/crates/swc_css_minifier/tests/fixture/compress-at-rule/supports/input.css +++ b/crates/swc_css_minifier/tests/fixture/compress-at-rule/supports/input.css @@ -215,3 +215,15 @@ animation: fade 3s cubic-bezier(0.25, 0.1, 0.25, 1) } } + +@supports (display: table-cell) and (display: list-item) and (display: list-item) and (display: contents) and (display: contents) { + .color { + color: red; + } +} + +@supports (display: table-cell) and ((display: list-item) and (display: contents)) and ((display: list-item) and (display: contents)) { + .color { + color: blue; + } +} \ No newline at end of file diff --git a/crates/swc_css_minifier/tests/fixture/compress-at-rule/supports/output.min.css b/crates/swc_css_minifier/tests/fixture/compress-at-rule/supports/output.min.css index beaa669541a1..631eea5c408b 100644 --- a/crates/swc_css_minifier/tests/fixture/compress-at-rule/supports/output.min.css +++ b/crates/swc_css_minifier/tests/fixture/compress-at-rule/supports/output.min.css @@ -1 +1 @@ -@supports(display:flex){a{color:red}}@supports(display:grid)and (display:flex){a{color:red}}@supports(display:grid)or (display:flex){a{color:red}}@supports(display:flex){a{color:red}}@supports(not (display:grid)){div{float:right}}@supports(transform-origin:5%5%){div{float:right}}@supports(display:grid)and (not (display:inline-grid)){div{float:right}}@supports(display:grid)and (display:flex){a{color:red}}@supports(display:flex)or (display:grid)or (display:table)or (display:inline-grid){div{color:red}}@supports(display:flex)and (display:grid)and (display:table)and (display:inline-grid){div{color:red}}@supports((display:flex)and (display:grid))or (display:table)or (display:inline-grid){div{color:red}}@supports((display:flex)or (display:grid))and (display:table)and (display:inline-grid){div{color:red}}@supports(display:flex)and ((display:grid)or (display:table))and (display:inline-grid){div{color:red}}@supports(display:flex)or ((display:grid)and (display:table))or (display:inline-grid){div{color:red}}@supports(display:flex)and (display:grid)and ((display:table)or (display:inline-grid)){div{color:red}}@supports(display:flex)or (display:grid)or ((display:table)and (display:inline-grid)){div{color:red}}@supports(display:flex!important){div{color:red}}@supports((display:grid)and (display:table))or ((display:flex)and (display:inline)){a{color:red}}@supports((display:grid)or (display:table))and ((display:flex)or (display:inline)){a{color:red}}@supports(display:grid)and (display:table)and (display:flex)and (display:inline){a{color:red}}@supports(display:grid)or (display:table)or (display:flex)or (display:inline){a{color:red}}@supports(display:grid)or (display:table)or ((display:flex)and (display:inline)){a{color:red}}@supports(display:grid)and (display:table)and ((display:flex)or (display:inline)){a{color:red}}@supports((display:grid)and (display:table))or (display:flex)or (display:inline){a{color:red}}@supports((display:grid)or (display:table))and (display:flex)and (display:inline){a{color:red}}@supports(display:grid)and (display:table)and (display:flex)and (display:inline-table){a{color:red}}@supports(display:grid)or (display:table)or (display:flex)or (display:inline-table){a{color:red}}@supports(display:grid)or ((display:table)and (display:flex))or (display:inline-table){a{color:red}}@supports(display:grid)and ((display:table)or (display:flex))and (display:inline-table){a{color:red}}@supports(animation:fade 3s cubic-bezier(.25,.1,.25,1)){a{animation:fade 3s ease}} +@supports(display:flex){a{color:red}}@supports(display:grid)and (display:flex){a{color:red}}@supports(display:grid)or (display:flex){a{color:red}}@supports(display:flex){a{color:red}}@supports(not (display:grid)){div{float:right}}@supports(transform-origin:5%5%){div{float:right}}@supports(display:grid)and (not (display:inline-grid)){div{float:right}}@supports(display:grid)and (display:flex){a{color:red}}@supports(display:flex)or (display:grid)or (display:table)or (display:inline-grid){div{color:red}}@supports(display:flex)and (display:grid)and (display:table)and (display:inline-grid){div{color:red}}@supports((display:flex)and (display:grid))or (display:table)or (display:inline-grid){div{color:red}}@supports((display:flex)or (display:grid))and (display:table)and (display:inline-grid){div{color:red}}@supports(display:flex)and ((display:grid)or (display:table))and (display:inline-grid){div{color:red}}@supports(display:flex)or ((display:grid)and (display:table))or (display:inline-grid){div{color:red}}@supports(display:flex)and (display:grid)and ((display:table)or (display:inline-grid)){div{color:red}}@supports(display:flex)or (display:grid)or ((display:table)and (display:inline-grid)){div{color:red}}@supports(display:flex!important){div{color:red}}@supports((display:grid)and (display:table))or ((display:flex)and (display:inline)){a{color:red}}@supports((display:grid)or (display:table))and ((display:flex)or (display:inline)){a{color:red}}@supports(display:grid)and (display:table)and (display:flex)and (display:inline){a{color:red}}@supports(display:grid)or (display:table)or (display:flex)or (display:inline){a{color:red}}@supports(display:grid)or (display:table)or ((display:flex)and (display:inline)){a{color:red}}@supports(display:grid)and (display:table)and ((display:flex)or (display:inline)){a{color:red}}@supports((display:grid)and (display:table))or (display:flex)or (display:inline){a{color:red}}@supports((display:grid)or (display:table))and (display:flex)and (display:inline){a{color:red}}@supports(display:grid)and (display:table)and (display:flex)and (display:inline-table){a{color:red}}@supports(display:grid)or (display:table)or (display:flex)or (display:inline-table){a{color:red}}@supports(display:grid)or ((display:table)and (display:flex))or (display:inline-table){a{color:red}}@supports(display:grid)and ((display:table)or (display:flex))and (display:inline-table){a{color:red}}@supports(animation:fade 3s cubic-bezier(.25,.1,.25,1)){a{animation:fade 3s ease}}@supports(display:table-cell)and (display:list-item)and (display:contents){.color{color:red;color:blue}} From f61fa3ae5698dfc3f826aad970058c4f42f887cf Mon Sep 17 00:00:00 2001 From: "alexander.akait" Date: Thu, 15 Dec 2022 21:20:42 +0300 Subject: [PATCH 2/5] test: more --- .../tests/fixture/compress-at-rule/media/input.css | 13 +++++++++++++ .../fixture/compress-at-rule/media/output.min.css | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/crates/swc_css_minifier/tests/fixture/compress-at-rule/media/input.css b/crates/swc_css_minifier/tests/fixture/compress-at-rule/media/input.css index d0367c207708..4448fbaa8ff5 100644 --- a/crates/swc_css_minifier/tests/fixture/compress-at-rule/media/input.css +++ b/crates/swc_css_minifier/tests/fixture/compress-at-rule/media/input.css @@ -73,3 +73,16 @@ @media (max-width: calc(5px + 1rem)) { body { color: red; } } @media (-webkit-calc(10px + 100px) < width <= calc(1000px + 10px)) { body { color: red; } } + +@media (color) { body { color: red; } } +@media (min-color: 1) { body { color: red; } } +@media (color >= 1) { body { color: red; } } + +@media (color-index) { body { color: red; } } +@media (min-color-index: 1) { body { color: red; } } +@media (color-index >= 1) { body { color: red; } } + +@media (monochrome) { body { color: red; } } +@media (min-monochrome: 1) { body { color: red; } } +@media (monochrome >= 1) { body { color: red; } } + diff --git a/crates/swc_css_minifier/tests/fixture/compress-at-rule/media/output.min.css b/crates/swc_css_minifier/tests/fixture/compress-at-rule/media/output.min.css index 8d32e1ab40b3..5928ef3b69bb 100644 --- a/crates/swc_css_minifier/tests/fixture/compress-at-rule/media/output.min.css +++ b/crates/swc_css_minifier/tests/fixture/compress-at-rule/media/output.min.css @@ -1 +1 @@ -@media print{body{font-size:10pt}}@media(min-width:900px){a{color:red}}@media only screen and (min-width:320px){body{line-height:1.4}}@media(400px<=width<=700px){body{line-height:1.4}}@media screen and (min-width:900px){article{padding:1rem 3rem}}@media(height>600px){body{line-height:1.4}}@media(400px<=width<=700px){body{line-height:1.4}}@media(foo:bar){body{line-height:1.4}}@media(min-width:30em)and (orientation:landscape){.test{color:red}}@media screen and (min-width:30em)and (orientation:landscape){.test{color:red}}@media screen and (min-width:30em)and (max-width:300px)and (orientation:landscape){.test{color:red}}@media(min-height:680px),screen and (orientation:portrait){.test{color:red}}@media(not (color))or (hover){.test{color:red}}@media only screen and ((min-width:320px)and (max-width:1480px)){body{background:red}}@media((min-width:320px)and (max-width:1480px)){body{background:red}}@media((min-width:320px)or (max-width:1480px)){body{background:red}}@media(min-width:320px)and (max-width:1480px)and (orientation:landscape){body{background:red}}@media(min-width:320px)or (max-width:1480px)or (orientation:landscape){body{background:red}}@media screen and (min-width:320px)and (max-width:1480px)and (orientation:landscape){body{background:red}}@media not (resolution:-300dpi){body{background:green}}@media(grid)and (max-width:15em){body{background:green}}@media(max-width:calc(5px + 1rem)){body{color:red}}@media(110px600px){body{line-height:1.4}}@media(400px<=width<=700px){body{line-height:1.4}}@media(foo:bar){body{line-height:1.4}}@media(min-width:30em)and (orientation:landscape){.test{color:red}}@media screen and (min-width:30em)and (orientation:landscape){.test{color:red}}@media screen and (min-width:30em)and (max-width:300px)and (orientation:landscape){.test{color:red}}@media(min-height:680px),screen and (orientation:portrait){.test{color:red}}@media(not (color))or (hover){.test{color:red}}@media only screen and ((min-width:320px)and (max-width:1480px)){body{background:red}}@media((min-width:320px)and (max-width:1480px)){body{background:red}}@media((min-width:320px)or (max-width:1480px)){body{background:red}}@media(min-width:320px)and (max-width:1480px)and (orientation:landscape){body{background:red}}@media(min-width:320px)or (max-width:1480px)or (orientation:landscape){body{background:red}}@media screen and (min-width:320px)and (max-width:1480px)and (orientation:landscape){body{background:red}}@media not (resolution:-300dpi){body{background:green}}@media(grid)and (max-width:15em){body{background:green}}@media(max-width:calc(5px + 1rem)){body{color:red}}@media(110px=1){body{color:red}}@media(color-index){body{color:red}}@media(min-color-index:1){body{color:red}}@media(color-index>=1){body{color:red}}@media(monochrome){body{color:red}}@media(min-monochrome:1){body{color:red}}@media(monochrome>=1){body{color:red}} From 8ee518923cd365a225cfee3cba24bc1970e0a34a Mon Sep 17 00:00:00 2001 From: "alexander.akait" Date: Thu, 15 Dec 2022 21:46:28 +0300 Subject: [PATCH 3/5] feat(css/minifier): compress media --- .../swc_css_minifier/src/compressor/media.rs | 56 +++++++++++++++++++ crates/swc_css_minifier/src/compressor/mod.rs | 6 ++ .../fixture/compress-at-rule/media/input.css | 3 + .../compress-at-rule/media/output.min.css | 2 +- 4 files changed, 66 insertions(+), 1 deletion(-) diff --git a/crates/swc_css_minifier/src/compressor/media.rs b/crates/swc_css_minifier/src/compressor/media.rs index 1e7697f9d747..6efe0dde30b8 100644 --- a/crates/swc_css_minifier/src/compressor/media.rs +++ b/crates/swc_css_minifier/src/compressor/media.rs @@ -1,5 +1,6 @@ use std::mem::take; +use swc_atoms::js_word; use swc_common::DUMMY_SP; use swc_css_ast::*; @@ -377,4 +378,59 @@ impl Compressor { } } } + + pub(super) fn compress_media_feature(&mut self, n: &mut MediaFeature) { + match n { + MediaFeature::Plain(MediaFeaturePlain { + span, + name: MediaFeatureName::Ident(name), + value: box MediaFeatureValue::Number(value), + }) => { + if matches!( + name.value, + js_word!("min-color") + | js_word!("min-color-index") + | js_word!("min-monochrome") + ) && value.value == 1.0 + { + *n = MediaFeature::Boolean(MediaFeatureBoolean { + span: *span, + name: MediaFeatureName::Ident(Ident { + span: name.span, + value: (*name.value).chars().skip(4).collect::().into(), + raw: None, + }), + }); + } + } + MediaFeature::Range(range) => { + if let MediaFeatureValue::Ident(name) = &*range.left { + if matches!( + name.value, + js_word!("color") | js_word!("color-index") | js_word!("monochrome") + ) && matches!(&*range.right, MediaFeatureValue::Number(number) if number.value == 1.0) + && range.comparison == MediaFeatureRangeComparison::Ge + { + *n = MediaFeature::Boolean(MediaFeatureBoolean { + span: range.span, + name: MediaFeatureName::Ident(name.clone()), + }); + } + } else if let MediaFeatureValue::Ident(name) = &*range.right { + if matches!( + name.value, + js_word!("color") | js_word!("color-index") | js_word!("monochrome") + ) && matches!(&*range.left, MediaFeatureValue::Number(number) if number.value == 1.0) + && range.comparison == MediaFeatureRangeComparison::Le + { + *n = MediaFeature::Boolean(MediaFeatureBoolean { + span: range.span, + name: MediaFeatureName::Ident(name.clone()), + }); + } + } + } + _ => {} + } + } } diff --git a/crates/swc_css_minifier/src/compressor/mod.rs b/crates/swc_css_minifier/src/compressor/mod.rs index 1a4b3e6c6c71..cecde666d895 100644 --- a/crates/swc_css_minifier/src/compressor/mod.rs +++ b/crates/swc_css_minifier/src/compressor/mod.rs @@ -175,6 +175,12 @@ impl VisitMut for Compressor { self.compress_media_in_parens(n); } + fn visit_mut_media_feature(&mut self, n: &mut MediaFeature) { + n.visit_mut_children_with(self); + + self.compress_media_feature(n); + } + fn visit_mut_media_feature_value(&mut self, n: &mut MediaFeatureValue) { n.visit_mut_children_with(self); diff --git a/crates/swc_css_minifier/tests/fixture/compress-at-rule/media/input.css b/crates/swc_css_minifier/tests/fixture/compress-at-rule/media/input.css index 4448fbaa8ff5..6ef79565201f 100644 --- a/crates/swc_css_minifier/tests/fixture/compress-at-rule/media/input.css +++ b/crates/swc_css_minifier/tests/fixture/compress-at-rule/media/input.css @@ -77,12 +77,15 @@ @media (color) { body { color: red; } } @media (min-color: 1) { body { color: red; } } @media (color >= 1) { body { color: red; } } +@media (1 <= color) { body { color: red; } } @media (color-index) { body { color: red; } } @media (min-color-index: 1) { body { color: red; } } @media (color-index >= 1) { body { color: red; } } +@media (1 <= color-index) { body { color: red; } } @media (monochrome) { body { color: red; } } @media (min-monochrome: 1) { body { color: red; } } @media (monochrome >= 1) { body { color: red; } } +@media (1 <= monochrome) { body { color: red; } } diff --git a/crates/swc_css_minifier/tests/fixture/compress-at-rule/media/output.min.css b/crates/swc_css_minifier/tests/fixture/compress-at-rule/media/output.min.css index 5928ef3b69bb..5dffe3b3e754 100644 --- a/crates/swc_css_minifier/tests/fixture/compress-at-rule/media/output.min.css +++ b/crates/swc_css_minifier/tests/fixture/compress-at-rule/media/output.min.css @@ -1 +1 @@ -@media print{body{font-size:10pt}}@media(min-width:900px){a{color:red}}@media only screen and (min-width:320px){body{line-height:1.4}}@media(400px<=width<=700px){body{line-height:1.4}}@media screen and (min-width:900px){article{padding:1rem 3rem}}@media(height>600px){body{line-height:1.4}}@media(400px<=width<=700px){body{line-height:1.4}}@media(foo:bar){body{line-height:1.4}}@media(min-width:30em)and (orientation:landscape){.test{color:red}}@media screen and (min-width:30em)and (orientation:landscape){.test{color:red}}@media screen and (min-width:30em)and (max-width:300px)and (orientation:landscape){.test{color:red}}@media(min-height:680px),screen and (orientation:portrait){.test{color:red}}@media(not (color))or (hover){.test{color:red}}@media only screen and ((min-width:320px)and (max-width:1480px)){body{background:red}}@media((min-width:320px)and (max-width:1480px)){body{background:red}}@media((min-width:320px)or (max-width:1480px)){body{background:red}}@media(min-width:320px)and (max-width:1480px)and (orientation:landscape){body{background:red}}@media(min-width:320px)or (max-width:1480px)or (orientation:landscape){body{background:red}}@media screen and (min-width:320px)and (max-width:1480px)and (orientation:landscape){body{background:red}}@media not (resolution:-300dpi){body{background:green}}@media(grid)and (max-width:15em){body{background:green}}@media(max-width:calc(5px + 1rem)){body{color:red}}@media(110px=1){body{color:red}}@media(color-index){body{color:red}}@media(min-color-index:1){body{color:red}}@media(color-index>=1){body{color:red}}@media(monochrome){body{color:red}}@media(min-monochrome:1){body{color:red}}@media(monochrome>=1){body{color:red}} +@media print{body{font-size:10pt}}@media(min-width:900px){a{color:red}}@media only screen and (min-width:320px){body{line-height:1.4}}@media(400px<=width<=700px){body{line-height:1.4}}@media screen and (min-width:900px){article{padding:1rem 3rem}}@media(height>600px){body{line-height:1.4}}@media(400px<=width<=700px){body{line-height:1.4}}@media(foo:bar){body{line-height:1.4}}@media(min-width:30em)and (orientation:landscape){.test{color:red}}@media screen and (min-width:30em)and (orientation:landscape){.test{color:red}}@media screen and (min-width:30em)and (max-width:300px)and (orientation:landscape){.test{color:red}}@media(min-height:680px),screen and (orientation:portrait){.test{color:red}}@media(not (color))or (hover){.test{color:red}}@media only screen and ((min-width:320px)and (max-width:1480px)){body{background:red}}@media((min-width:320px)and (max-width:1480px)){body{background:red}}@media((min-width:320px)or (max-width:1480px)){body{background:red}}@media(min-width:320px)and (max-width:1480px)and (orientation:landscape){body{background:red}}@media(min-width:320px)or (max-width:1480px)or (orientation:landscape){body{background:red}}@media screen and (min-width:320px)and (max-width:1480px)and (orientation:landscape){body{background:red}}@media not (resolution:-300dpi){body{background:green}}@media(grid)and (max-width:15em){body{background:green}}@media(max-width:calc(5px + 1rem)){body{color:red}}@media(110px Date: Thu, 15 Dec 2022 22:04:05 +0300 Subject: [PATCH 4/5] feat(css/minifier): compress media --- .../swc_css_minifier/src/compressor/media.rs | 16 ++++++++++++++++ .../fixture/compress-at-rule/media/input.css | 19 +++++++++++++++++++ .../compress-at-rule/media/output.min.css | 2 +- 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/crates/swc_css_minifier/src/compressor/media.rs b/crates/swc_css_minifier/src/compressor/media.rs index 6efe0dde30b8..e0172c822410 100644 --- a/crates/swc_css_minifier/src/compressor/media.rs +++ b/crates/swc_css_minifier/src/compressor/media.rs @@ -38,6 +38,8 @@ impl Compressor { } pub(super) fn compress_media_condition(&mut self, n: &mut MediaCondition) { + dedup(&mut n.conditions); + match n.conditions.get(1) { Some(MediaConditionAllType::Or(_)) => { let need_compress = n.conditions.iter().any(|item| match item { @@ -196,6 +198,8 @@ impl Compressor { } pub(super) fn compress_media_condition_without_or(&mut self, n: &mut MediaConditionWithoutOr) { + dedup(&mut n.conditions); + if let Some(MediaConditionWithoutOrType::And(_)) = n.conditions.get(1) { let need_compress = n.conditions.iter().any(|item| match item { MediaConditionWithoutOrType::MediaInParens(MediaInParens::MediaCondition( @@ -415,6 +419,12 @@ impl Compressor { span: range.span, name: MediaFeatureName::Ident(name.clone()), }); + } else if range.comparison == MediaFeatureRangeComparison::Eq { + *n = MediaFeature::Plain(MediaFeaturePlain { + span: range.span, + name: MediaFeatureName::Ident(name.clone()), + value: range.right.clone(), + }); } } else if let MediaFeatureValue::Ident(name) = &*range.right { if matches!( @@ -427,6 +437,12 @@ impl Compressor { span: range.span, name: MediaFeatureName::Ident(name.clone()), }); + } else if range.comparison == MediaFeatureRangeComparison::Eq { + *n = MediaFeature::Plain(MediaFeaturePlain { + span: range.span, + name: MediaFeatureName::Ident(name.clone()), + value: range.left.clone(), + }); } } } diff --git a/crates/swc_css_minifier/tests/fixture/compress-at-rule/media/input.css b/crates/swc_css_minifier/tests/fixture/compress-at-rule/media/input.css index 6ef79565201f..4a0b61a5076c 100644 --- a/crates/swc_css_minifier/tests/fixture/compress-at-rule/media/input.css +++ b/crates/swc_css_minifier/tests/fixture/compress-at-rule/media/input.css @@ -89,3 +89,22 @@ @media (monochrome >= 1) { body { color: red; } } @media (1 <= monochrome) { body { color: red; } } +@media (width = 1024px) { body {background: green;} } +@media (1024px = width) { body {background: green;} } +@media (width: 1024px) { body {background: green;} } + +@media (min-width: 900px) and (min-width: 900px) and (min-width: 900px), + (min-width: 900px) or (min-width: 900px) or (min-width: 900px) or (min-width: 900px) +{ + a { + color: red; + } +} + +@media screen and (min-width: 900px) and (min-width: 900px) and (min-width: 900px), + (min-width: 900px) or (min-width: 900px) or (min-width: 900px) or (min-width: 900px) +{ + a { + color: red; + } +} \ No newline at end of file diff --git a/crates/swc_css_minifier/tests/fixture/compress-at-rule/media/output.min.css b/crates/swc_css_minifier/tests/fixture/compress-at-rule/media/output.min.css index 5dffe3b3e754..04999cb1f487 100644 --- a/crates/swc_css_minifier/tests/fixture/compress-at-rule/media/output.min.css +++ b/crates/swc_css_minifier/tests/fixture/compress-at-rule/media/output.min.css @@ -1 +1 @@ -@media print{body{font-size:10pt}}@media(min-width:900px){a{color:red}}@media only screen and (min-width:320px){body{line-height:1.4}}@media(400px<=width<=700px){body{line-height:1.4}}@media screen and (min-width:900px){article{padding:1rem 3rem}}@media(height>600px){body{line-height:1.4}}@media(400px<=width<=700px){body{line-height:1.4}}@media(foo:bar){body{line-height:1.4}}@media(min-width:30em)and (orientation:landscape){.test{color:red}}@media screen and (min-width:30em)and (orientation:landscape){.test{color:red}}@media screen and (min-width:30em)and (max-width:300px)and (orientation:landscape){.test{color:red}}@media(min-height:680px),screen and (orientation:portrait){.test{color:red}}@media(not (color))or (hover){.test{color:red}}@media only screen and ((min-width:320px)and (max-width:1480px)){body{background:red}}@media((min-width:320px)and (max-width:1480px)){body{background:red}}@media((min-width:320px)or (max-width:1480px)){body{background:red}}@media(min-width:320px)and (max-width:1480px)and (orientation:landscape){body{background:red}}@media(min-width:320px)or (max-width:1480px)or (orientation:landscape){body{background:red}}@media screen and (min-width:320px)and (max-width:1480px)and (orientation:landscape){body{background:red}}@media not (resolution:-300dpi){body{background:green}}@media(grid)and (max-width:15em){body{background:green}}@media(max-width:calc(5px + 1rem)){body{color:red}}@media(110px600px){body{line-height:1.4}}@media(400px<=width<=700px){body{line-height:1.4}}@media(foo:bar){body{line-height:1.4}}@media(min-width:30em)and (orientation:landscape){.test{color:red}}@media screen and (min-width:30em)and (orientation:landscape){.test{color:red}}@media screen and (min-width:30em)and (max-width:300px)and (orientation:landscape){.test{color:red}}@media(min-height:680px),screen and (orientation:portrait){.test{color:red}}@media(not (color))or (hover){.test{color:red}}@media only screen and ((min-width:320px)and (max-width:1480px)){body{background:red}}@media((min-width:320px)and (max-width:1480px)){body{background:red}}@media((min-width:320px)or (max-width:1480px)){body{background:red}}@media(min-width:320px)and (max-width:1480px)and (orientation:landscape){body{background:red}}@media(min-width:320px)or (max-width:1480px)or (orientation:landscape){body{background:red}}@media screen and (min-width:320px)and (max-width:1480px)and (orientation:landscape){body{background:red}}@media not (resolution:-300dpi){body{background:green}}@media(grid)and (max-width:15em){body{background:green}}@media(max-width:calc(5px + 1rem)){body{color:red}}@media(110px Date: Thu, 15 Dec 2022 22:08:25 +0300 Subject: [PATCH 5/5] feat(css/minifier): compress media --- .../swc_css_minifier/src/compressor/media.rs | 277 +++++++++--------- .../compress-at-rule/media/output.min.css | 2 +- 2 files changed, 142 insertions(+), 137 deletions(-) diff --git a/crates/swc_css_minifier/src/compressor/media.rs b/crates/swc_css_minifier/src/compressor/media.rs index e0172c822410..cb4cf2e0e6f9 100644 --- a/crates/swc_css_minifier/src/compressor/media.rs +++ b/crates/swc_css_minifier/src/compressor/media.rs @@ -38,8 +38,6 @@ impl Compressor { } pub(super) fn compress_media_condition(&mut self, n: &mut MediaCondition) { - dedup(&mut n.conditions); - match n.conditions.get(1) { Some(MediaConditionAllType::Or(_)) => { let need_compress = n.conditions.iter().any(|item| match item { @@ -63,59 +61,59 @@ impl Compressor { }); if !need_compress { - return; - } - - let mut new_conditions = Vec::with_capacity(n.conditions.len()); - - for item in take(&mut n.conditions) { - match item { - MediaConditionAllType::MediaInParens(MediaInParens::MediaCondition( - media_condition, - )) if self.is_first_or_media_type(&media_condition) - && self.is_first_media_in_parens(&media_condition) => - { - let mut iter = media_condition.conditions.into_iter(); + let mut new_conditions = Vec::with_capacity(n.conditions.len()); - if let Some(MediaConditionAllType::MediaInParens(media_in_parens)) = - iter.next() - { - new_conditions - .push(MediaConditionAllType::MediaInParens(media_in_parens)); - - new_conditions.extend(iter); - } - } - MediaConditionAllType::Or(media_or) => match media_or.condition { - MediaInParens::MediaCondition(media_condition) - if self.is_first_or_media_type(&media_condition) - && self.is_first_media_in_parens(&media_condition) => + for item in take(&mut n.conditions) { + match item { + MediaConditionAllType::MediaInParens( + MediaInParens::MediaCondition(media_condition), + ) if self.is_first_or_media_type(&media_condition) + && self.is_first_media_in_parens(&media_condition) => { let mut iter = media_condition.conditions.into_iter(); if let Some(MediaConditionAllType::MediaInParens(media_in_parens)) = iter.next() { - new_conditions.push(MediaConditionAllType::Or(MediaOr { - span: DUMMY_SP, - keyword: None, - condition: media_in_parens, - })); + new_conditions.push(MediaConditionAllType::MediaInParens( + media_in_parens, + )); new_conditions.extend(iter); } } + MediaConditionAllType::Or(media_or) => match media_or.condition { + MediaInParens::MediaCondition(media_condition) + if self.is_first_or_media_type(&media_condition) + && self.is_first_media_in_parens(&media_condition) => + { + let mut iter = media_condition.conditions.into_iter(); + + if let Some(MediaConditionAllType::MediaInParens( + media_in_parens, + )) = iter.next() + { + new_conditions.push(MediaConditionAllType::Or(MediaOr { + span: DUMMY_SP, + keyword: None, + condition: media_in_parens, + })); + + new_conditions.extend(iter); + } + } + _ => { + new_conditions.push(MediaConditionAllType::Or(media_or)); + } + }, _ => { - new_conditions.push(MediaConditionAllType::Or(media_or)); + new_conditions.push(item); } - }, - _ => { - new_conditions.push(item); } } - } - n.conditions = new_conditions; + n.conditions = new_conditions; + } } Some(MediaConditionAllType::And(_)) => { let need_compress = n.conditions.iter().any(|item| match item { @@ -139,67 +137,67 @@ impl Compressor { }); if !need_compress { - return; - } - - let mut new_conditions = Vec::with_capacity(n.conditions.len()); - - for item in take(&mut n.conditions) { - match item { - MediaConditionAllType::MediaInParens(MediaInParens::MediaCondition( - media_condition, - )) if self.is_first_and_media_type(&media_condition) - && self.is_first_media_in_parens(&media_condition) => - { - let mut iter = media_condition.conditions.into_iter(); + let mut new_conditions = Vec::with_capacity(n.conditions.len()); - if let Some(MediaConditionAllType::MediaInParens(media_in_parens)) = - iter.next() - { - new_conditions - .push(MediaConditionAllType::MediaInParens(media_in_parens)); - - new_conditions.extend(iter); - } - } - MediaConditionAllType::And(media_and) => match media_and.condition { - MediaInParens::MediaCondition(media_condition) - if self.is_first_and_media_type(&media_condition) - && self.is_first_media_in_parens(&media_condition) => + for item in take(&mut n.conditions) { + match item { + MediaConditionAllType::MediaInParens( + MediaInParens::MediaCondition(media_condition), + ) if self.is_first_and_media_type(&media_condition) + && self.is_first_media_in_parens(&media_condition) => { let mut iter = media_condition.conditions.into_iter(); if let Some(MediaConditionAllType::MediaInParens(media_in_parens)) = iter.next() { - new_conditions.push(MediaConditionAllType::And(MediaAnd { - span: DUMMY_SP, - keyword: None, - condition: media_in_parens, - })); + new_conditions.push(MediaConditionAllType::MediaInParens( + media_in_parens, + )); new_conditions.extend(iter); } } + MediaConditionAllType::And(media_and) => match media_and.condition { + MediaInParens::MediaCondition(media_condition) + if self.is_first_and_media_type(&media_condition) + && self.is_first_media_in_parens(&media_condition) => + { + let mut iter = media_condition.conditions.into_iter(); + + if let Some(MediaConditionAllType::MediaInParens( + media_in_parens, + )) = iter.next() + { + new_conditions.push(MediaConditionAllType::And(MediaAnd { + span: DUMMY_SP, + keyword: None, + condition: media_in_parens, + })); + + new_conditions.extend(iter); + } + } + _ => { + new_conditions.push(MediaConditionAllType::And(media_and)); + } + }, _ => { - new_conditions.push(MediaConditionAllType::And(media_and)); + new_conditions.push(item); } - }, - _ => { - new_conditions.push(item); } } - } - n.conditions = new_conditions; + n.conditions = new_conditions; + } } _ => {} } - } - pub(super) fn compress_media_condition_without_or(&mut self, n: &mut MediaConditionWithoutOr) { dedup(&mut n.conditions); + } + pub(super) fn compress_media_condition_without_or(&mut self, n: &mut MediaConditionWithoutOr) { if let Some(MediaConditionWithoutOrType::And(_)) = n.conditions.get(1) { let need_compress = n.conditions.iter().any(|item| match item { MediaConditionWithoutOrType::MediaInParens(MediaInParens::MediaCondition( @@ -222,65 +220,23 @@ impl Compressor { }); if !need_compress { - return; - } - - let mut new_conditions = Vec::with_capacity(n.conditions.len()); - - for item in take(&mut n.conditions) { - match item { - MediaConditionWithoutOrType::MediaInParens(MediaInParens::MediaCondition( - media_condition, - )) if self.is_first_and_media_type(&media_condition) - && self.is_first_media_in_parens(&media_condition) => - { - let mut iter = media_condition.conditions.into_iter(); + let mut new_conditions = Vec::with_capacity(n.conditions.len()); - if let Some(MediaConditionAllType::MediaInParens(media_in_parens)) = - iter.next() - { - new_conditions - .push(MediaConditionWithoutOrType::MediaInParens(media_in_parens)); - - for new_item in iter { - match new_item { - MediaConditionAllType::Not(media_not) => { - new_conditions - .push(MediaConditionWithoutOrType::Not(media_not)); - } - MediaConditionAllType::And(media_and) => { - new_conditions - .push(MediaConditionWithoutOrType::And(media_and)); - } - MediaConditionAllType::MediaInParens(media_in_parens) => { - new_conditions.push( - MediaConditionWithoutOrType::MediaInParens( - media_in_parens, - ), - ); - } - _ => { - unreachable!(); - } - } - } - } - } - MediaConditionWithoutOrType::And(media_and) => match media_and.condition { - MediaInParens::MediaCondition(media_condition) - if self.is_first_and_media_type(&media_condition) - && self.is_first_media_in_parens(&media_condition) => + for item in take(&mut n.conditions) { + match item { + MediaConditionWithoutOrType::MediaInParens( + MediaInParens::MediaCondition(media_condition), + ) if self.is_first_and_media_type(&media_condition) + && self.is_first_media_in_parens(&media_condition) => { let mut iter = media_condition.conditions.into_iter(); if let Some(MediaConditionAllType::MediaInParens(media_in_parens)) = iter.next() { - new_conditions.push(MediaConditionWithoutOrType::And(MediaAnd { - span: DUMMY_SP, - keyword: None, - condition: media_in_parens, - })); + new_conditions.push(MediaConditionWithoutOrType::MediaInParens( + media_in_parens, + )); for new_item in iter { match new_item { @@ -306,18 +262,67 @@ impl Compressor { } } } + MediaConditionWithoutOrType::And(media_and) => match media_and.condition { + MediaInParens::MediaCondition(media_condition) + if self.is_first_and_media_type(&media_condition) + && self.is_first_media_in_parens(&media_condition) => + { + let mut iter = media_condition.conditions.into_iter(); + + if let Some(MediaConditionAllType::MediaInParens(media_in_parens)) = + iter.next() + { + new_conditions.push(MediaConditionWithoutOrType::And( + MediaAnd { + span: DUMMY_SP, + keyword: None, + condition: media_in_parens, + }, + )); + + for new_item in iter { + match new_item { + MediaConditionAllType::Not(media_not) => { + new_conditions.push( + MediaConditionWithoutOrType::Not(media_not), + ); + } + MediaConditionAllType::And(media_and) => { + new_conditions.push( + MediaConditionWithoutOrType::And(media_and), + ); + } + MediaConditionAllType::MediaInParens( + media_in_parens, + ) => { + new_conditions.push( + MediaConditionWithoutOrType::MediaInParens( + media_in_parens, + ), + ); + } + _ => { + unreachable!(); + } + } + } + } + } + _ => { + new_conditions.push(MediaConditionWithoutOrType::And(media_and)); + } + }, _ => { - new_conditions.push(MediaConditionWithoutOrType::And(media_and)); + new_conditions.push(item); } - }, - _ => { - new_conditions.push(item); } } - } - n.conditions = new_conditions; + n.conditions = new_conditions; + } } + + dedup(&mut n.conditions); } pub(super) fn compress_media_in_parens(&mut self, n: &mut MediaInParens) { diff --git a/crates/swc_css_minifier/tests/fixture/compress-at-rule/media/output.min.css b/crates/swc_css_minifier/tests/fixture/compress-at-rule/media/output.min.css index 04999cb1f487..424075fdcc5e 100644 --- a/crates/swc_css_minifier/tests/fixture/compress-at-rule/media/output.min.css +++ b/crates/swc_css_minifier/tests/fixture/compress-at-rule/media/output.min.css @@ -1 +1 @@ -@media print{body{font-size:10pt}}@media(min-width:900px){a{color:red}}@media only screen and (min-width:320px){body{line-height:1.4}}@media(400px<=width<=700px){body{line-height:1.4}}@media screen and (min-width:900px){article{padding:1rem 3rem}}@media(height>600px){body{line-height:1.4}}@media(400px<=width<=700px){body{line-height:1.4}}@media(foo:bar){body{line-height:1.4}}@media(min-width:30em)and (orientation:landscape){.test{color:red}}@media screen and (min-width:30em)and (orientation:landscape){.test{color:red}}@media screen and (min-width:30em)and (max-width:300px)and (orientation:landscape){.test{color:red}}@media(min-height:680px),screen and (orientation:portrait){.test{color:red}}@media(not (color))or (hover){.test{color:red}}@media only screen and ((min-width:320px)and (max-width:1480px)){body{background:red}}@media((min-width:320px)and (max-width:1480px)){body{background:red}}@media((min-width:320px)or (max-width:1480px)){body{background:red}}@media(min-width:320px)and (max-width:1480px)and (orientation:landscape){body{background:red}}@media(min-width:320px)or (max-width:1480px)or (orientation:landscape){body{background:red}}@media screen and (min-width:320px)and (max-width:1480px)and (orientation:landscape){body{background:red}}@media not (resolution:-300dpi){body{background:green}}@media(grid)and (max-width:15em){body{background:green}}@media(max-width:calc(5px + 1rem)){body{color:red}}@media(110px600px){body{line-height:1.4}}@media(400px<=width<=700px){body{line-height:1.4}}@media(foo:bar){body{line-height:1.4}}@media(min-width:30em)and (orientation:landscape){.test{color:red}}@media screen and (min-width:30em)and (orientation:landscape){.test{color:red}}@media screen and ((min-width:30em)and (max-width:300px))and (orientation:landscape){.test{color:red}}@media(min-height:680px),screen and (orientation:portrait){.test{color:red}}@media(not (color))or (hover){.test{color:red}}@media only screen and ((min-width:320px)and (max-width:1480px)){body{background:red}}@media((min-width:320px)and (max-width:1480px)){body{background:red}}@media((min-width:320px)or (max-width:1480px)){body{background:red}}@media((min-width:320px)and (max-width:1480px))and (orientation:landscape){body{background:red}}@media(min-width:320px)and ((max-width:1480px)and (orientation:landscape)){body{background:red}}@media((min-width:320px)or (max-width:1480px))or (orientation:landscape){body{background:red}}@media(min-width:320px)or ((max-width:1480px)or (orientation:landscape)){body{background:red}}@media screen and ((min-width:320px)and (max-width:1480px))and (orientation:landscape){body{background:red}}@media screen and (min-width:320px)and ((max-width:1480px)and (orientation:landscape)){body{background:red}}@media not (resolution:-300dpi){body{background:green}}@media(grid)and (max-width:15em){body{background:green}}@media(max-width:calc(5px + 1rem)){body{color:red}}@media(110px