sveltejs / svelte · Issue No. 18609
REGEX_NTH_OF in src/compiler/phases/1-parse/read/style.js matches the <an+b> of <selector> form only with whitespace on both sides of of:
const REGEX_NTH_OF =
/(even|odd|\+?(\d+|\d*n(\s*[+-]\s*\d+)?)|-\d*n(\s*\+\s*\d+))((?=\s*[,)])|\s+of\s+)/y;
But CSS minifiers (cssnano/lightningcss) legally collapse 2n of .foo → 2n of.foo — the . delim token terminates the of ident, so no whitespace is required there. Browsers accept the minified form (we serve it in production today). Svelte's parser throws css_expected_identifier on it.
SvelteKit's inlineStyleThreshold re-parses the built (minified) CSS through this parser, so any component using :nth-child(... of .selector) compiles fine on its own but fails the production build the moment its emitted CSS file falls under the inline threshold:
[vite-plugin-sveltekit-compile] Expected a valid CSS identifier
https://svelte.dev/e/css_expected_identifier
Parser-level, no project needed:
import { parse } from 'svelte/compiler';
parse('<style>.x:nth-child(2n of .x){color:red}</style>', { modern: true }); // ok
parse('<style>.x:nth-child(2n of.x){color:red}</style>', { modern: true }); // throws css_expected_identifier
End-to-end: a SvelteKit app with kit.inlineStyleThreshold set and a component style containing :nth-child(even of .foo) — vite build fails.
The trailing \s+ requirement after of should allow any token that lawfully starts the following <complex-selector> (., #, [, :, *), e.g. something like \s+of(?=\s|[.#\[:*]).
annoyance (workaround: keep the affected CSS file above inlineStyleThreshold, or avoid the of syntax)
maininlineStyleThreshold + vite 7 css minificationRelay reads this issue against the repository's contribution signals: the files it is likely to touch, how the maintainers triage work this size, and what the first contribution would exercise.
The full analysis for this issue is still being assembled. Until then, the description above and the thread on GitHub are the most reliable context.