Generating many styles with identifiers: "short"
, triple &
selector (&&&
), in a file whose hash starts with a letter in base36 leads to compilation errors
#1501
Labels
css
Issue related to the core css package
Describe the bug
Say you have a
bug-repro.css.ts
file that looks like this:(I use the selector
&&&
as an easy way to surgically increase the specificity of some CSS rule instead of using the cudgel!important
.)On my machine the file hash for this is
lfv1o4
(which seems to be generated here). So class names follow the pattern:At
i = 93
we generate the classlfv1o42l
. Wherelfv1o4
is the file hash and2l
is the base36 encoded ref count.vanilla-extract/packages/css/src/identifier.ts
Lines 50 to 58 in 729f209
When
@vanilla-extract
generates the selector&&&
forlfv1o42
(our class name ati = 2
) it generates the stringlfv1o42lfv1o42lfv1o42
. ThenStylesheet.transformSelector()
is responsible for transforming it into the actual selector we'll add to the CSS file. Which should be.lfv1o42.lfv1o42.lfv1o42
.vanilla-extract/packages/css/src/transformCss.ts
Lines 296 to 342 in 729f209
The problem is, it's ambiguous how to transform this class name! Given both
lfv1o42
(ati = 2
) andlfv1o402l
(ati = 93
) are valid class names.@vanilla-extract
resolves this by always picking the longest match:vanilla-extract/packages/css/src/transformCss.ts
Lines 320 to 326 in 729f209
…but that means in
lfv1o42lfv1o42lfv1o42
(from the selector&&&
) is parsed such thatlfv1o42lf
is considered to be the first class name. In my local example I get the following error:Clearly something is broken with how
@vanilla-extract
is parsing the class name then printing it back out if it thinks my selector&&&
is actually&lffv1o42lffv1o42
.This issue is non-deterministic. It doesn't effect files who hash to a value starting with a number (e.g. I have one CSS file in production whose hash is
93u2u5
). SincenormalizeIdentifier()
prefixes classes that start with a number with an_
. Because an_
is not a base36 character (ref counts in class names are serialized to base36) we never run into this ambiguous case. Since in a class name with a hash of93u2u5
, ref count of2
, we get_93u2u52
. We'll never generate another class name that ends with an underscore so@vanilla-extract
's string searching won't be confused.vanilla-extract/packages/css/src/identifier.ts
Lines 30 to 32 in 729f209
This was a very annoying issue to debug. It was happening in my production deploy CI job but wasn't happening on local developer machines or my test CI job (even when identifiers were set to short). I thought this was Linux related, then arm64 vs x86_64 related, and turns out it's based on how the file name is hashed.
Replacing
identifiers: "short"
withidentifiers: ({hash}) => hash.startsWith("_") ? `_${hash}` : hash
works around the issue by making sure all classes start with an underscore. Filing this issue so either this fix can be added to@vanilla-extract
itself or a more principled fix can be written up.Reproduction
Apologies for not providing a minimal reproduction. I created one locally with Vite but since this issue is based on how the absolute path file is hashed I figured it might be better to only include the essential part of the reproduction (the
bug-repro.css.ts
file above) and let maintainers iterate on their own reproduction based on the absolute file paths on their machine.System Info
Used Package Manager
npm
Logs
Here's the original error message I was seeing in CI. Clearly
&&&
is a valid selector:Validations
The text was updated successfully, but these errors were encountered: