Skip to content

Commit 39c3962

Browse files
committed
minify: removes duplicates from CSS selector lists
1 parent 8362c37 commit 39c3962

File tree

3 files changed

+39
-0
lines changed

3 files changed

+39
-0
lines changed

CHANGELOG.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,22 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
* Minification now removes duplicates from CSS selector lists
6+
7+
This release introduces the following CSS minification optimization:
8+
9+
```css
10+
/* Original input */
11+
div, div { color: red }
12+
13+
/* Old output (with --minify) */
14+
div,div{color:red}
15+
16+
/* New output (with --minify) */
17+
div{color:red}
18+
```
19+
320
## 0.17.13
421

522
* Work around an issue with `NODE_PATH` and Go's WebAssembly internals ([#3001](https://github.com/evanw/esbuild/issues/3001))

internal/css_parser/css_parser_selector.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ func (p *parser) parseSelectorList(opts parseSelectorOpts) (list []css_ast.Compl
1515
list = append(list, sel)
1616

1717
// Parse the remaining selectors
18+
skip:
1819
for {
1920
p.eat(css_lexer.TWhitespace)
2021
if !p.eat(css_lexer.TComma) {
@@ -25,6 +26,16 @@ func (p *parser) parseSelectorList(opts parseSelectorOpts) (list []css_ast.Compl
2526
if !good {
2627
return
2728
}
29+
30+
// Omit duplicate selectors
31+
if p.options.MinifySyntax {
32+
for _, existing := range list {
33+
if sel.Equal(existing, nil) {
34+
continue skip
35+
}
36+
}
37+
}
38+
2839
list = append(list, sel)
2940
}
3041

internal/css_parser/css_parser_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1774,6 +1774,17 @@ func TestMangleAlpha(t *testing.T) {
17741774
expectPrintedLowerMangle(t, "a { color: #000000FF }", "a {\n color: #000;\n}\n")
17751775
}
17761776

1777+
func TestMangleDuplicateSelectors(t *testing.T) {
1778+
expectPrinted(t, "a, a { color: red }", "a,\na {\n color: red;\n}\n")
1779+
expectPrintedMangle(t, "a, a { color: red }", "a {\n color: red;\n}\n")
1780+
expectPrintedMangle(t, "a, b { color: red }", "a,\nb {\n color: red;\n}\n")
1781+
expectPrintedMangle(t, "a, a.foo, a.foo, a.bar, a { color: red }", "a,\na.foo,\na.bar {\n color: red;\n}\n")
1782+
1783+
expectPrintedMangle(t, "@media screen { a, a { color: red } }", "@media screen {\n a {\n color: red;\n }\n}\n")
1784+
expectPrintedMangle(t, "@media screen { a, b { color: red } }", "@media screen {\n a,\n b {\n color: red;\n }\n}\n")
1785+
expectPrintedMangle(t, "@media screen { a, a.foo, a.foo, a.bar, a { color: red } }", "@media screen {\n a,\n a.foo,\n a.bar {\n color: red;\n }\n}\n")
1786+
}
1787+
17771788
func TestMangleDuplicateSelectorRules(t *testing.T) {
17781789
expectPrinted(t, "a { color: red } b { color: red }", "a {\n color: red;\n}\nb {\n color: red;\n}\n")
17791790
expectPrintedMangle(t, "a { color: red } b { color: red }", "a,\nb {\n color: red;\n}\n")

0 commit comments

Comments
 (0)