Skip to content

[SPIKE] smart ax with dynamic length and prefix family matching#1902

Draft
xtan-atlas wants to merge 3 commits into
masterfrom
xtan/smart-ax
Draft

[SPIKE] smart ax with dynamic length and prefix family matching#1902
xtan-atlas wants to merge 3 commits into
masterfrom
xtan/smart-ax

Conversation

@xtan-atlas

Copy link
Copy Markdown
Contributor

What is this change?

Make ax supports longer classes like _ggggggvvvv, and can detect group hash is gggggg.
Support overrides legacy short classnames: ax('_ggggvvvv', '_ggggttvvvv') => '_ggggttvvvv'

Why are we making this change?

The 4 char group hash is too short, cause class collision and drop styles silently.


PR checklist

Don't delete me!

I have...

  • [ x ] Updated or added applicable tests
  • Updated the documentation in website/
  • Added a changeset (if making any changes that affect Compiled's behaviour)

@changeset-bot

changeset-bot Bot commented May 29, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 0bdd9a7

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@netlify

netlify Bot commented May 29, 2026

Copy link
Copy Markdown

Deploy Preview for compiled-css-in-js canceled.

Name Link
🔨 Latest commit 0bdd9a7
🔍 Latest deploy log https://app.netlify.com/projects/compiled-css-in-js/deploys/6a19567a76f931000818f3b2

'_aaaaeeee',
],
[
'should treat non-standard shorter atomic-looking class names consistently with suffix parsing',

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was failing, because original test was accepting 8 char class. It works before due to it treat first 4 char as group, but after we change logic to slice(className.length - valueLength), the group hash for 8 char string would be first 3 char...

Comment thread packages/react/src/runtime/ax.ts Outdated
Comment on lines +52 to +56
for (const existingKey in map) {
if (key.startsWith(existingKey)) {
delete map[existingKey];
}
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit confused on what this does. So let's say we have two: ax(['_abcd1234', '_abcde2345']); (old and new hashes)

  • _abcd1234 runs, sets map = { '_abcd': '_abcd1234' };
  • _abcd1234 runs, deletes that map entry, sets map = { '_abcde': '_abcde2345' };

That makes sense, you want the second value with that hash…

But then let's invert it: ax(['_abcde1234', '_abcd2345']); don't you get map = { '_abcd': '_abcd1234', '_abcde': '_abcde2345' };?

Is that a problem?

Comment on lines +88 to +90
if (isAtomic) {
removePrefixFamilyEntries(key);
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a comment (maybe in above jsdoc) explaining this part is helpful, especially RE: my comment above as I think this might get more complex…

Comment on lines +103 to +105
'should allow a variable-length longer group to override its legacy prefix family',
['_aaaabbbb', '_aaaa12cccc'],
'_aaaa12cccc',

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure we have a flipped version of this test as well, or like all three in various orders, whatever seems sensible.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added more flipped tests

* ever needs to be disabled.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const setAtomicClassInGroupMapSimpleScan = (groupKey: string, className: string) => {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is much easier to understand but a bit slower when ax large amount of classes, like Editor styles...

* For runtime performance, the bucket is mutated in place using swap-and-pop
* so we avoid allocating a fresh array on every insert.
*/
const setAtomicClassInGroupMapBucketed = (groupKey: string, className: string) => {

@xtan-atlas xtan-atlas May 29, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is hard to understand, but more performant. But still slower than without legacy group hash support. It's like slower 20-40%. So backwards support do come with cost.

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.

2 participants