diff --git a/CHANGELOG.md b/CHANGELOG.md index d8e26b27303..3e532d27f00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -125,6 +125,27 @@ In addition to the breaking changes above, the following changes are also includ Note that this behavior does **not** work across files. Each file is still compiled independently so the namespaces in each file are still resolved independently per-file. Implicit namespace cross-references still do not work across files. Getting this to work is counter to esbuild's parallel architecture and does not fit in with esbuild's design. It also doesn't make sense with esbuild's bundling model where input files are either in ESM or CommonJS format and therefore each have their own scope. +* Fix legal comment parsing in CSS ([#1796](https://github.com/evanw/esbuild/issues/1796)) + + Legal comments in CSS either start with `/*!` or contain `@preserve` or `@license` and are preserved by esbuild in the generated CSS output. This release fixes a bug where non-top-level legal comments inside a CSS file caused esbuild to skip any following legal comments even if those following comments are top-level: + + ```css + /* Original code */ + .example { + --some-var: var(--tw-empty, /*!*/ /*!*/); + } + /*! Some legal comment */ + body { + background-color: red; + } + + /* Old output (with --minify) */ + .example{--some-var: var(--tw-empty, )}body{background-color:red} + + /* New output (with --minify) */ + .example{--some-var: var(--tw-empty, )}/*! Some legal comment */body{background-color:red} + ``` + ## 0.13.15 * Fix `super` in lowered `async` arrow functions ([#1777](https://github.com/evanw/esbuild/issues/1777)) diff --git a/internal/css_parser/css_parser.go b/internal/css_parser/css_parser.go index 7911ada83c3..b89e5cae2e5 100644 --- a/internal/css_parser/css_parser.go +++ b/internal/css_parser/css_parser.go @@ -173,12 +173,14 @@ loop: // turn them all into comment rules and append them to the current rule list for p.legalCommentIndex < len(p.legalComments) { comment := p.legalComments[p.legalCommentIndex] - if comment.TokenIndexAfter != uint32(p.index) { + if comment.TokenIndexAfter > uint32(p.index) { break } - rules = append(rules, css_ast.Rule{Loc: comment.Loc, Data: &css_ast.RComment{Text: comment.Text}}) - if context.isTopLevel { - locs = append(locs, comment.Loc) + if comment.TokenIndexAfter == uint32(p.index) { + rules = append(rules, css_ast.Rule{Loc: comment.Loc, Data: &css_ast.RComment{Text: comment.Text}}) + if context.isTopLevel { + locs = append(locs, comment.Loc) + } } p.legalCommentIndex++ } diff --git a/internal/css_parser/css_parser_test.go b/internal/css_parser/css_parser_test.go index d0f8dafec70..5b340dc2df6 100644 --- a/internal/css_parser/css_parser_test.go +++ b/internal/css_parser/css_parser_test.go @@ -858,6 +858,8 @@ func TestLegalComment(t *testing.T) { expectPrinted(t, "@charset \"UTF-8\";/*!*/", "@charset \"UTF-8\";\n/*!*/\n") expectPrinted(t, "@import \"x\"; /*!*/", "@import \"x\";\n/*!*/\n") expectPrinted(t, "@charset \"UTF-8\"; /*!*/", "@charset \"UTF-8\";\n/*!*/\n") + + expectPrinted(t, "/*! before */ a { --b: var(--c, /*!*/ /*!*/); } /*! after */\n", "/*! before */\na {\n --b: var(--c, );\n}\n/*! after */\n") } func TestAtKeyframes(t *testing.T) {