Open marvinhagemeister opened 3 months ago
EDIT: Updated the numbers gathered from the repro code. I accidentally left in the ones from another project which didn't make it match up with the screenshots. Apologies for that I didn't notice that error when filing the issue.
I tried to replace hash()
with JSON.stringify()
in a real project (Rspack + postcss-loader + tailwindcss) and this makes tailwindcss several times faster:
hash()
3.12sJSON.stringify()
0.41sI found that the performance of hash()
depends on how the user uses the tailwindcss
postcss plugin. Tailwindcss only caches hash()
internally for some situations:
If the user calls the plugin via tailwindcss()
and does not pass in any parameters, tailwindcss will cache based on the path of tailwind.config.ts
to avoid repeated hash()
calls.
If the user calls the plugin via tailwindcss(configObject)
, tailwindcss will not cache this, causing each module to trigger hash()
once, resulting in build performance degradation.
See: https://github.com/tailwindlabs/tailwindcss/blob/3.4/src/lib/setupTrackingContext.js#L31-L71
What version of Tailwind CSS are you using?
v3.4.10
What build tool (or framework if it abstracts the build tool) are you using?
postcss 8.4.41
What version of Node.js are you using?
v22.6.0 (also Deno 1.46.0-rc.3+dd8a9c5)
What browser are you using?
What operating system are you using?
macOS
Reproduction URL
https://github.com/marvinhagemeister/tw-config-hash-repro
Steps to reproduce:
npm i
node foo.mjs
-> observe time printed to consolenode_modules/tailwindcss/lib/util/hashConfig.js
and replace the contents of the hashing function withJSON.stringify(config)
node foo.mjs
again -> observe much faster timeDescribe your issue
I noticed that hashing the tailwind configuration takes up roughly a third of the time in my project. That seemed a bit much. It looks like the
object-hash
package isn't the fastest.https://github.com/tailwindlabs/tailwindcss/blob/f07dbff2a7f78fd75c53c6cfe01b58b6c0419f22/src/util/hashConfig.js#L3-L5
Given that the config is mostly json, switching to
JSON.stringify
would be much faster. If we do want to treat some values in a special way when the config isn't pure json, we could pass a custom replacer function toJSON.stringify
for those.Here is a quick diff:
Before 84ms:
After 6.33ms:
Whilst this is just a synthetic example repository, I can reproduce the same results in real world projects of mine.
It might not seem like much in the grander scheme of thing, but in my projects where I do tailwind processing during development this makes HMR updates feel a tiny bit snappier. There the time hashing the configuration easily takes up 30-35% of the total tailwind processing time. Would be nice if that could be reduced.