Closed Newbie012 closed 1 month ago
After debugging the extension, I've figured out the source of the issue. It starts with this line:
It seems like .matchAll
freezes when I only hover on a class. This is because the extension takes only a portion of the file (which makes sense) and only then it tries to match against the predefined regex. In my case, I use tailwind-variants which suggests a regex that doesn't play nicely with incomplete code.
I was able to make a very minimal reproduction:
const text = `tv({
base: "disabled:pointer-events-none disabled:opacity-50",
compoundVariants: [
`
const regex = new RegExp("tv\\((([^()]*|\\([^()]*\\))*)\\)", "dg");
const matches = text.matchAll(regex);
// this will freeze the main thread.
matches.next()
While the regex issue is more related to tailwind-variants than tailwindcss itself, I still believe that something should be done in order to prevent high CPU usage.
This is a huge problem that needs fixing
The regex is prone to catastrophic backtracking. The only fix is to actually write a different regex.
I looked into this months ago: https://github.com/tailwindlabs/tailwindcss-intellisense/pull/897#issuecomment-1892792615
In JS there is no way to "cancel" a regex once it's started searching. If you sample the process it'll actually be stuck inside V8 itself (the JS engine that powers Node).
Node does have worker threads so that might be a way to keep the main thread responsive (and maybe terminate a thread that's stuck) but I actually have no idea if that would work. I'll have to look into it.
Going to close in favor of #963 given that it's the same problem
@thecrypticace I ran some tests and while I was unable to .terminate
a worker, I could stop it by calling process.exit
, but I didn't want to kill the main process, so I created a "middleware" worker.
In a nutshell: Main Thread -> Timeout Worker -> Regex Worker
The timeout worker is responsible for forwarding the messages between the regex worker and the main process, while adding a "kill switch" if the regex worker fails to respond in a given time.
I am able to .terminate()
a worker that's stuck in v8. Works fine from the main thread. The problem is more about creating a worker pool and making sure requests are appropriately distributed to non-busy workers, failed requests can be replayed, etc…
What version of Tailwind CSS are you using?
3.4.3
What build tool (or framework if it abstracts the build tool) are you using?
postcss 8.4.38
What version of Node.js are you using?
v20.10.0
What browser are you using?
N/A
What operating system are you using?
macOS
Reproduction URL
https://github.com/Newbie012/bug-tailwindcss-cpu
Describe your issue
I have a file with a lot of tailwind classes. Whenever I open it, the tailwind (vscode) extension freezes. You can see in the screenshot 2 processes (it opens a new one without closing the previous process every time I restart vscode) that points to the vscode extension.
Steps to Reproduce
pnpm install
component.ts
Please let me know if I missed any details so I can share it.
Thanks!