Skip to content

Commit

Permalink
minify: removes duplicates from CSS selector lists
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Mar 25, 2023
1 parent 8362c37 commit 39c3962
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 0 deletions.
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
# Changelog

## Unreleased

* Minification now removes duplicates from CSS selector lists

This release introduces the following CSS minification optimization:

```css
/* Original input */
div, div { color: red }

/* Old output (with --minify) */
div,div{color:red}

/* New output (with --minify) */
div{color:red}
```

## 0.17.13

* Work around an issue with `NODE_PATH` and Go's WebAssembly internals ([#3001](https://github.com/evanw/esbuild/issues/3001))
Expand Down
11 changes: 11 additions & 0 deletions internal/css_parser/css_parser_selector.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ func (p *parser) parseSelectorList(opts parseSelectorOpts) (list []css_ast.Compl
list = append(list, sel)

// Parse the remaining selectors
skip:
for {
p.eat(css_lexer.TWhitespace)
if !p.eat(css_lexer.TComma) {
Expand All @@ -25,6 +26,16 @@ func (p *parser) parseSelectorList(opts parseSelectorOpts) (list []css_ast.Compl
if !good {
return
}

// Omit duplicate selectors
if p.options.MinifySyntax {
for _, existing := range list {
if sel.Equal(existing, nil) {
continue skip
}
}
}

list = append(list, sel)
}

Expand Down
11 changes: 11 additions & 0 deletions internal/css_parser/css_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1774,6 +1774,17 @@ func TestMangleAlpha(t *testing.T) {
expectPrintedLowerMangle(t, "a { color: #000000FF }", "a {\n color: #000;\n}\n")
}

func TestMangleDuplicateSelectors(t *testing.T) {
expectPrinted(t, "a, a { color: red }", "a,\na {\n color: red;\n}\n")
expectPrintedMangle(t, "a, a { color: red }", "a {\n color: red;\n}\n")
expectPrintedMangle(t, "a, b { color: red }", "a,\nb {\n color: red;\n}\n")
expectPrintedMangle(t, "a, a.foo, a.foo, a.bar, a { color: red }", "a,\na.foo,\na.bar {\n color: red;\n}\n")

expectPrintedMangle(t, "@media screen { a, a { color: red } }", "@media screen {\n a {\n color: red;\n }\n}\n")
expectPrintedMangle(t, "@media screen { a, b { color: red } }", "@media screen {\n a,\n b {\n color: red;\n }\n}\n")
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")
}

func TestMangleDuplicateSelectorRules(t *testing.T) {
expectPrinted(t, "a { color: red } b { color: red }", "a {\n color: red;\n}\nb {\n color: red;\n}\n")
expectPrintedMangle(t, "a { color: red } b { color: red }", "a,\nb {\n color: red;\n}\n")
Expand Down

0 comments on commit 39c3962

Please sign in to comment.