Skip to content

fix: preserve trailing semicolon on nested at-rule statements#323

Open
kernoeb wants to merge 1 commit into
danielroe:mainfrom
kernoeb:fix/nested-at-rule-semicolon
Open

fix: preserve trailing semicolon on nested at-rule statements#323
kernoeb wants to merge 1 commit into
danielroe:mainfrom
kernoeb:fix/nested-at-rule-semicolon

Conversation

@kernoeb

@kernoeb kernoeb commented May 19, 2026

Copy link
Copy Markdown

Summary

Fixes #322.

serializeStylesheet's compress path stripped the trailing ; of any container whose raws.semicolon was set, on the assumption it terminated a redundant declaration body. For a nested at-rule statement (e.g. @layer parent { @layer a, b; }) the ; is the statement terminator — stripping it yields invalid CSS, and browsers then bail on subsequent rules in the parent at-rule.

The fix narrows the strip to cases where the parent's last child is a decl, leaving nested at-rule statements untouched.

Before

@layer parent {@layer a, b}@layer parent.a {.foo{color:red}}

After

@layer parent {@layer a, b;}@layer parent.a {.foo{color:red}}

Verification

  • New serialize.test.ts cases:
    • Preserves ; on nested at-rule sub-layer declaration (the bug pattern)
    • Still strips the redundant ; inside an at-rule whose last child is a declaration (e.g. @font-face) — locks in that the new guard doesn't over-restrict
  • Ran the serializer end-to-end on real-world bundles before/after the patch:
    • Bootstrap 5.3 minified (232 KB): output byte-for-byte identical
    • Vuetify 4.0 unminified (652 KB): only 3 character differences in the whole bundle, all of them being the ; previously stripped from @layer vuetify-core { @layer reset, base; }, @layer vuetify-utilities { …; @layer theme-foreground; }, and @layer vuetify-final { @layer transitions, trumps; }. Both outputs round-trip through postcss.parse without error.

Test plan

  • pnpm --filter beasties exec vitest run — 56/56 pass (2 new)
  • pnpm lint
  • pnpm test:types

The compress path in `serializeStylesheet` stripped the trailing `;` of
any container whose `raws.semicolon` was set, on the assumption it was a
redundant declaration-body terminator. For a nested at-rule statement
(e.g. `@layer parent { @layer a, b; }`), that `;` is the statement
terminator and removing it yields invalid CSS — browsers then bail on
subsequent rules in the parent layer.

Gate the strip on the parent's last child being a declaration, leaving
nested at-rule statements untouched.

Fixes danielroe#322
@codspeed-hq

codspeed-hq Bot commented Jun 16, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 9 untouched benchmarks


Comparing kernoeb:fix/nested-at-rule-semicolon (896f320) with main (3e5e694)

Open in CodSpeed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: nested @layer declaration loses trailing semicolon during compression

1 participant