Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some Tailwind classes are not extracted from Pug templates in Vue when elements have attributes #17313

Closed
davidrunger opened this issue Mar 21, 2025 · 6 comments · Fixed by #17320
Assignees

Comments

@davidrunger
Copy link

What version of Tailwind CSS are you using?

v4.0.15 (the latest released version, at the time of writing)

What build tool (or framework if it abstracts the build tool) are you using?

Vite 6.2.2, Vue 3.5.13, Pug 3.0.3 (the latest released version of each, at the time of writing)

What version of Node.js are you using?

v22.14.0 (the latest LTS release, at the time of writing)

What browser are you using?

Firefox (though I don't think it's relevant)

What operating system are you using?

Linux (Debian / MX Linux) (though I don't think it's relevant)

Reproduction URL

I cannot provide a Tailwind Play URL, because this bug is particular to Pug templates, whereas Tailwind Play only supports plain HTML.

But here's a public GitHub repo with a minimal reproduction: https://github.com/davidrunger/tailwind-pug-attr-bug-demo

And here's that GitHub repo imported into CodeSandbox: https://codesandbox.io/p/github/davidrunger/tailwind-pug-attr-bug-demo/main?file=%2Fsrc%2FApp.vue%3A4%2C1

Describe your issue

CSS styles are sometimes not included for some Tailwind classes in Pug templates in my Vue project.

In the reproduction linked above, there is this Vue component:

<template lang="pug">
.text-sky-600.bg-neutral-900(title="A tooltip") This div has an HTML attribute.
</template>

Actual

When viewed in the browser, only the text-sky-600 class has any visible effect (making the text blue). The bg-neutral-900 class does not have any effect (when served either via the Vite hot-reloading dev server or when compiled and viewed via the Vite static production preview server).

Image

Expected

I expect that the bg-neutral-900 class in the Pug Vue template would cause Tailwind to include CSS that gives that text a dark background, which is what happens if we go back to tailwindcss and @tailwindcss/vite at v4.0.9 :

Image

Additional context:

I recently reported a similar bug for this environment (Vue templates using Pug) here: #17211. That was fixed by #17252, which was included in the Tailwind 4.0.15 release today. Although that issue was fixed, this different issue (where the presence of an HTML attribute seems to cause not all Tailwind classes to be extracted from the Pug Vue template) is present in 4.0.15.

Thank you for Tailwind and for taking a look at this bug!

@RobinMalfait
Copy link
Member

Hey!

This will be fixed by #17320, have you experienced other Pug related issues?

@davidrunger
Copy link
Author

This will be fixed by #17320

@RobinMalfait Thank you for another super quick fix!

have you experienced other Pug related issues?

Unfortunately, that's somewhat hard to say for sure, but I hope not.

My process is basically just:

  1. update my app to the latest version of Tailwind
  2. see if something is broken
  3. if something is broken, then find some specific issue and create a minimal reproduction
  4. @RobinMalfait fixes the reported bug 🦸‍♂️
  5. wait for release of a new Tailwind version
  6. repeat all of these steps until my app is hopefully eventually working

I realize that this is not a super tight feedback loop. For all of our sakes, I wish that there were some way to make the feedback loop tighter.

I mostly work with Ruby, where, when I encounter a bug in a gem, then I can open the source code of that Ruby gem in my text editor with bundle open the_gem_name. I can then modify the gem code myself to see if I can figure out something that fixes my bug, in which case I can submit a PR. Or, even if I don't fix the issue myself, then, after someone else fixes it, I can try out the fix on my machine before it is merged and released, by putting something like

gem 'the_gem_name', gitub: 'the-organization/the-repo', branch: 'the-bugfix-pr-branch-name'

in my app's Gemfile.

Then, I can either say regarding the bugfix PR either "Yes, I can confirm that this fixes all of my issues" or "This fixes X, but it doesn't fix Y".

Unfortunately, I don't think that there is a way to do something similar, where I could check your PR against my app (before the PR is merged and released) and verify that it has resolved all of the issues? If there is some way, then please let me know, and I could try to do it to verify that your latest PR resolves all of the Tailwind issues that my app is currently seeing.

We already seem close to a solution, though.

Here's the visual diff for my app's Percy screenshots after going from

Tailwind 4.0.9 to 4.0.{11,12,13,14}:

Image

Image

And here's the visual diff for my app's Percy screenshots after going from

Tailwind 4.0.9 to 4.0.15:

Image

Image

As you can see, we are getting much closer to success (no visual diffs), so I am optimistic that your latest PR will fix all of the remaining issues.

Each of those screenshots demonstrates I think just a single Tailwind class that was not extracted. In both cases, the relevant Pug code does have an HTML attribute or Vue directive in parentheses.

Here's the relevant code for the top screenshot diff: https://github.com/davidrunger/david_runger/blob/8ed638e000b095de3c0fd344770449c33730a4b0/app/javascript/home/components/HomeHero.vue#L6-L14

And here's the relevant code for the bottom screenshot diff: https://github.com/davidrunger/david_runger/blob/8ed638e000b095de3c0fd344770449c33730a4b0/app/javascript/groceries/components/Sidebar.vue#L39-L43

All this is to say that, as I mentioned before, I hope (and mostly suspect) that #17320 will fix all of the remaining Pug-Tailwind issues that I'm seeing, but, as I also say, unfortunately it's hard to be fully sure of that without being able to actually try out a new release.

@RobinMalfait
Copy link
Member

Alright cool, thanks for that information! It does look like it's just the classes followed by a (. I did check your two links and it looks everything seems to be extracted as expected now!

Image Image

So this should be fixed by #17320 and will be available in the next release.

@davidrunger
Copy link
Author

@RobinMalfait Great -- thank you very much for checking both of those larger Pug Vue templates and for sharing the screenshots showing that all Tailwind classes are successfully extracted.

I look forward to hopefully getting back on the latest Tailwind with the 4.0.16 release. :)

@RobinMalfait
Copy link
Member

Wanted to answer some of your questions as well:

I realize that this is not a super tight feedback loop. For all of our sakes, I wish that there were some way to make the feedback loop tighter.

The big issue we run into is that these templating languages have a lot of special syntax around classes. Whenever you use a literal string like class="…" everything is guaranteed to be working. But it's the special cases where you can do .foo.bar and then follow the classes by special characters that is the problem.

Internally classes are separated by "boundary" characters. That means that if you look at class="flex" that even though " and f in flex are literally touching, they are not part of the same class. So " and are considered boundary characters.

One issue you will run into with Pug is .. We can have . in our classes, e.g.: px-2.5 but this should be 1 class. However in Pug you can do .flex.items-center and these are definitely not part of the same class, so we pre-process Pug to remove the . characters there (in memory, not on disk!).

Another one is .flex(…), in Pug that's valid because ( is just the start of attributes (I believe?). But in normal Tailwind CSS classes ( is not a boundary character. Otherwise every function call like foo() in most programming languages would also be considered classes.

So we remove ( as well here.

Unfortunately, I don't think that there is a way to do something similar, where I could check your PR against my app (before the PR is merged and released) and verify that it has resolved all of the issues?
There is not really unless you manually build everything (and link all the correct versions together). However, once the PR is merged (which it is) then we always release an insiders version:

npm install tailwindcss@insiders (and any of the other packages) should fix that.

@davidrunger
Copy link
Author

@RobinMalfait I really appreciate you taking the time and effort to provide that very helpful additional context.

Your writeup makes it clear that parsing templating languages for Tailwind is a tricky challenge. I am grateful that y'all do it, so that we can use these templating languages with Tailwind. :) I use Pug in Vue and also Haml for my Rails views.

Your comment made me curious how Tailwind would be able to handle something like .px-2.5 in a Pug template, but I guess that it doesn't have to, since that's not valid Pug syntax:

Image

So, that class would have to be provided in a class="…" attribute, like this:

p.text-4xl.text-right(class="px-2.5")

(which Tailwind will be able to parse more straightforwardly, as you mentioned).

Similarly, there are some other Tailwind classes, such as text-blue-300! and text-[#aaa] that also cannot be written using the Pug dot notation for classes (because .text-blue-300! and .text-[#aaa] are Pug syntax errors), and which also must instead be provided via a class="…" attribute.

Trying to write something in Pug like p.bg-(--color-red-500) Full stack web developer also doesn't seem to work. It's not a Pug syntax error like .text-blue-300! and .text-[#aaa], but it causes a runtime exception of Uncaught DOMException: String contains an invalid character in my Vue app, I guess because --color-red-500 is not a valid HTML attribute name, and I think that Pug would treat it as an HTML attribute in that example. So, seemingly that also must be written instead like p(class="bg-(--color-red-500)") Full stack web developer, which Tailwind handles successfully. So, I guess that Tailwind doesn't have to worry about trying to parse such classes containing parentheses written using Pug class dot notation, either.

Another one is .flex(…), in Pug that's valid because ( is just the start of attributes (I believe?)

Right. ✅

There is not really unless you manually build everything (and link all the correct versions together).

Yeah, I guessed that I could theoretically do that, but it seemed like probably a lot more hassle than I really felt like investing, and I wasn't very confident that I'd be able to get this working with any amount of effort. 😅

However, once the PR is merged (which it is) then we always release an insiders version:

npm install tailwindcss@insiders (and any of the other packages) should fix that.

Very cool! I tried this, and I am happy to report that, using tailwindcss@0.0.0-insiders.5426baf and @tailwindcss/vite@0.0.0-insiders.5426baf, there are no more Percy visual diffs for my app's Percy screenshots. 🎉

Image

Thanks again for all of your work on these Pug/Haml/Slim issues (and on Tailwind in general)!

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 a pull request may close this issue.

2 participants