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

[v4] Tailwind utilities layer absent in production build when vite.build.minify is used #15278

Open
vejja opened this issue Dec 2, 2024 · 8 comments
Assignees

Comments

@vejja
Copy link

vejja commented Dec 2, 2024

What version of Tailwind CSS are you using?

v4

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

Nuxt (Vite)

What version of Node.js are you using?

20

What browser are you using?

Chrome

What operating system are you using?

macOS

Reproduction URL

https://github.com/siyosu/nuxt-ui-v3
https://nuxt-ui-v3.vercel.app/

Describe your issue

The Tailwind utilities layer is absent in the reproduction.
Observe how the class space-y-4 is not applied between the email input and the login button.

Please see details in full issue as originally posted here : nuxt-modules/security#576

This is Nuxt Security team.
Our context is the Nuxt Framework, but the issue appears to be unrelated to Nuxt.
Our investigation found that the bug only appears when Vite is used with option { build: { minify: true } } as documented in Vite here : https://vite.dev/config/build-options#build-minify

As a temporary workaround, we are disabling Vite's build minification.
However we would like to be able to minify builds again. This breaks Tailwind for now.

@Hardel-DW
Copy link

I can confirm that I have the same problem with my Astro sites.

@RobinMalfait RobinMalfait self-assigned this Dec 12, 2024
@RobinMalfait
Copy link
Member

Hey!

Edit before even posting this: Alright, below this big blob is my initial thought process, but I figured out something else that explains it. So let's talk about that instead.

Looking at the generated CSS it looks like this CSS is generated:

.space-y-4 :where(>:not(:last-child)) { /* … */ }

The :where() pseudo-class does not support relative selectors (the > part). If this code is passed to Lightning CSS, then the following is being generated:

.space-y-4 :where() { /* … */ }

The reason it's empty is because that part of the :where() is not valid and removed.

In Tailwind CSS v4, we generate nested CSS by default, this means that we generate the following CSS:

.space-y-4 {
  :where(& > :not(:last-child)) {
    /* … */
  }
}

My assumption is that something else (outside of Tailwind CSS) is incorrectly flattening the CSS.

The reason I say this, is because if you were using the minify feature of @tailwindcss/vite (which we read from config.build.cssMinify) or @tailwindcss/postcss (which is enabled by default if you use NODE_ENV === 'production'), then we run Lightning CSS which produces the following CSS:

:where(.space-y-4 > :not(:last-child)) {
  /* … */
}

So the only 2 outputs Tailwind CSS generates are either the nested version, or the correct :where(.space-y-4 > :not(:last-child)) version.

Your workaround where you do not run any minify step makes me think that the minify process is minifying our nested CSS (incorrectly) and producing the wrong output. The CSS nesting spec has changed over the last couple of years so I would not be surprised if the minify tool is using an older implementation.

The big difference with Tailwind CSS v3 is that in v3 we didn't generate nested CSS which is probably why you didn't see that bug before.

Now, one thing you can try is to always enable the minification in @tailwindcss/vite or @tailwincss/postcss (whichever one you are using). Right now this configuration is hidden and I can't easily access it to test. But I wonder if you enable minification in our plugins (which in turn generates the flattened CSS), that the problem goes away. Note: this is definitely a workaround and should ideally be fixed upstream.

  • If you configure @tailwindcss/vite with config.build.cssMinify = true in your Vite config, then @tailwindcss/vite will produce a minified output.
  • If you configure @tailwindcss/postcss with build: { minify: true }, then the same will happen:
// postcss.config.ts — or equivalent file
export default {
  plugins: {
    '@tailwindcss/postcss': {
      optimize: { minify: true }
    }
  }
}

Original debugging thought process, but included for transparency:

This is a bit of a confusing one because you are using @import "tailwindcss"; but it's not listed in your package.json. This means that you are relying on transitive dependencies.

It also looks like both @tailwindcss/postcss and @tailwindcss/vite are installed. Are both used (at the same time)?

dependencies:
@nuxt/ui 3.0.0-alpha.9
├─┬ @tailwindcss/postcss 4.0.0-alpha.34
│ └── tailwindcss 4.0.0-alpha.34
├─┬ @tailwindcss/vite 4.0.0-alpha.34
│ └── tailwindcss 4.0.0-alpha.34
├─┬ tailwind-variants 0.3.0
│ └── tailwindcss 4.0.0-alpha.34 peer
└── tailwindcss 4.0.0-alpha.34

One thing that you can try, but I don't think will help because I don't think this is a Tailwind CSS issue, is that you bump all the versions to the latest @next. Which at the time of writing this should result in v4.0.0-beta.7.

If I override the packages locally, to be beta.7, then during the build I do see confusing errors printed as warnings for valid CSS:
image

I wonder if an error like this in your pipeline is causing strange behavior.


@Hardel-DW can you create a minimal reproduction repo and open a new issue? I'm not sure if it's the exact same issue you are seeing so I want to make sure that's the case.

@vejja
Copy link
Author

vejja commented Dec 13, 2024

Hey @RobinMalfait
Thank you so much for devoting so much time & energy to this.

I'm not part of the Nuxt UI team so pinging @benjamincanac here, probably he will understand what you've discovered

@benjamincanac
Copy link

Thanks for digging @RobinMalfait!

It's not up to the user to install tailwindcss but to @nuxt/ui as we rely on a specific version, for example we're not using beta.7 yet but beta.6 because we have a Nuxt Build Error: [@tailwindcss/vite:generate:build] Object not disposable error.

As for why there is both @tailwindcss/postcss and @tailwindcss/vite dependencies installed, this is to handle either vite or webpack: https://github.com/nuxt/ui/blob/v3/src/module.ts#L92-L97

I've had the lexical warnings on build since the beginning if I remember correctly 😬

Would a Nuxt minimal reproduction without @nuxt/ui help?

@RobinMalfait
Copy link
Member

@benjamincanac that might be helpful, but I can reproduce the issue by completely removing @import "tailwindcss";

If I take the reproduction from @vejja, then I can apply this diff:

diff --git a/assets/css/main.css b/assets/css/main.css
index 7c95c6f..97d0325 100644
--- a/assets/css/main.css
+++ b/assets/css/main.css
@@ -1,2 +1,7 @@
-@import "tailwindcss";
-@import "@nuxt/ui";
+.space-y-4 {
+  :where(& > :not(:last-child)) {
+    --tw-space-y-reverse: 0;
+    margin-block-start: calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));
+    margin-block-end: calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)));
+  }
+}

If I then look in the browser, this code results in the incorrectly flattened styles I mentioned in a previous comment:

<style nonce="AfI6hKB7S0E4F/P+Xku2Wr+1">
  .space-y-4 :where(>:not(:last-child)) {
    --tw-space-y-reverse: 0;
    margin-block-end:calc(var(--spacing)*4*(1 - var(--tw-space-y-reverse)));margin-block-start: calc(var(--spacing)*4*var(--tw-space-y-reverse))
  }
</style>

Going to figure out if I can reproduce this with Vite alone or not. If so, I'll create a minimal reproduction and open an issue on the Vite repo itself.

@RobinMalfait
Copy link
Member

Created a minimal reproduction using Vite only without any JavaScript frameworks, Nuxt, Nuxt UI or Tailwind CSS and opened an issue on the Vite repo: vitejs/vite#18974

Reproduction in case you are interested: https://github.com/RobinMalfait/vite-incorrect-css-flattening

Copy link

Thanks @RobinMalfait :) Just to be sure, the warning above you posted about lexical error isn't related?

I also sometimes have this one:
CleanShot 2024-12-16 at 14.25.52@2x.png

@RobinMalfait
Copy link
Member

This warning:
image

Is unrelated to the Vite bug I submitted, but the warning in itself is also wrong because it is valid CSS.

The image you just shared also seems unrelated, not sure what's up with that. The CSS on the line with the ^ is also valid CSS. But since the error is talking about "invalid JS syntax", so I think some of the analysis tools are producing false positives.

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

No branches or pull requests

4 participants