Skip to content

fix: sort CSS module exports for deterministic output hashes#9

Open
asurare wants to merge 1 commit into
mhsdesign:mainfrom
asurare:main
Open

fix: sort CSS module exports for deterministic output hashes#9
asurare wants to merge 1 commit into
mhsdesign:mainfrom
asurare:main

Conversation

@asurare

@asurare asurare commented Jun 23, 2026

Copy link
Copy Markdown

Problem

Object.entries(exports) iterates in the order the properties were inserted into the JS object. lightningcss is written in Rust; its internal HashMap (which backs the exports object it returns) uses a randomly-seeded hasher for DOS protection. The iteration order therefore differs between process invocations, even for identical input.

This means the generated JS:

export default { container: "abc-container", switchOption: "abc-switchOption" }

can become:

export default { switchOption: "abc-switchOption", container: "abc-container" }

on the next run — same class names, different property order. esbuild hashes the chunk content, so a reordered object is a different hash, causing every chunk that transitively imports the module to also get a new hash. In a real project (~150 esbuild chunks) every single JS chunk changed hash between consecutive builds with no source changes.

The fix applied here is to simply sort exports alphabetically before generating the object literal, with :

for (const [cssClassReadableName, cssClassExport] of Object.entries(exports).sort(([a], [b]) => a < b ? -1 : 1)) {

With this fix, running esbuild with splitting enabled produces bit-for-bit identical output.

@mhsdesign mhsdesign left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

thanks for this fix, didnt know anyone uses this lib actually as esbuild kinda has modules support now (just not perfect one)

Comment thread pnpm-lock.yaml

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

please do not include the lock update - indeed i should update the dependencies but currently in the nmp eco system i think its better to not trust anyone;)

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