tailwindlabs / tailwindcss

A utility-first CSS framework for rapid UI development.
https://tailwindcss.com/
MIT License
81.85k stars 4.13k forks source link

[v4] Vite plugin breaks when setting `css.transformer` to `"lightningcss"` #14205

Open aaronadamsCA opened 4 weeks ago

aaronadamsCA commented 4 weeks ago

What version of Tailwind CSS are you using?

4.0.0-alpha.19

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

Vite 5.4.0

What version of Node.js are you using?

20.16.0

What browser are you using?

N/A

What operating system are you using?

Ubuntu 22.04

Reproduction URL

Let me know if you need this and how you'd like it. It works fine on Tailwind Play but fails in Vite.

Describe your issue

With a Vite config that specifies "lightningcss" as the CSS transformer:

import tailwindcss from "@tailwindcss/vite";
import react from "@vitejs/plugin-react";
import { defineConfig } from "vite";

export default defineConfig({
  css: {
    transformer: "lightningcss",
  },
  plugins: [react(), tailwindcss()],
});

The behaviour of the Vite plugin is undefined and buggy.

It crashes when using @apply with class names containing characters * or /:

@import "tailwindcss";

@utility foo {
  @apply text-3xl/tight;
}
12:44:49 PM [vite] Pre-transform error: Cannot apply unknown utility class: /
12:44:49 PM [vite] Internal server error: Cannot apply unknown utility class: /
  Plugin: @tailwindcss/vite:generate:serve
  File: /workspace/packages/ui/src/tailwind.css
      at onInvalidCandidate (file:///workspace/node_modules/.pnpm/tailwindcss@4.0.0-alpha.19/node_modules/tailwindcss/dist/lib.mjs:6:109810)
...

It pollutes the console with warnings:

Error running vite:css on Tailwind CSS output. Skipping.
Error running vite:css on Tailwind CSS output. Skipping.
Error running vite:css on Tailwind CSS output. Skipping.

And it seems to ignore @layer base classes.

You can work around the problem by removing the offending part of the Vite config.

philipp-spiess commented 4 weeks ago

Heya! I tried to reproduce this but both vite dev and vite build seems to work for me if I add this @utility rule:

Screenshot 2024-08-16 at 15 05 42

Do you mind sharing your Vite config? Maybe there's another preprocessor that rewrites the @apply rule.

aaronadamsCA commented 4 weeks ago

Thanks @philipp-spiess, that narrows down the problem. It's because I was configuring "lightningcss" as my transformer:

import tailwindcss from "@tailwindcss/vite";
import react from "@vitejs/plugin-react";
import { defineConfig } from "vite";

export default defineConfig({
  css: {
    transformer: "lightningcss",
  },
  plugins: [react(), tailwindcss()],
});

If I remove it, everything works as expected! No more mystery problems.

This was also breaking a few other features, like using @layer base to set global styles, and the console was littered with these warnings:

Error running vite:css on Tailwind CSS output. Skipping.
Error running vite:css on Tailwind CSS output. Skipping.
Error running vite:css on Tailwind CSS output. Skipping.
Error running vite:css on Tailwind CSS output. Skipping.

All of this is resolved by removing that (redundant?) part of the config.

I've updated the original bug report. Hopefully you can reproduce this and then decide how to fix it, even if it's just erroring out for now, since "completely broken with a clear error message" is a lot better than "mysteriously half-broken".

philipp-spiess commented 4 weeks ago

@aaronadamsCA Thank you so much! Yeah, this doesn't work right now šŸ˜ž We currently rely on the default postcss transformer for two reasons:

  1. It won't rewrite CSS rules like the @apply text-3xl/tight example you shared above.
  2. We rely on postcss for @import resolution and we're hooking into it by making sure relative imports (e.g. @plugin "./src/foo.ts") are rewritten correctly when imports are flattened.

I agree, though, that this is something that should work much better than it does right now. I'll brainstorm some ideas and will get back to you.

philipp-spiess commented 4 weeks ago

@aaronadamsCA I'll continue to look into it but wanted to give a quick update since we just talked about this. Our current thinking is that tailwindcss currently already runs lightningcss for you so technically we're a superset of lightningcss and it would be better for us to either replace lightningcss in that case or hook into it more instead of having to run the same computation twice.

For the very short term, this unfortunately means that we won't have a good solution for this and the current alpha releases of @tailwindcss/vite won't be working with css.transformer set to lightningcss. I'll do some more digging next week though.

aaronadamsCA commented 4 weeks ago

Sounds good @philipp-spiess! Maybe you could just throw an error if the Vite config is invalid.

In the meantime, hopefully anybody who runs into any of the same problems can now find this issue report!

philipp-spiess commented 1 week ago

Reopening this. It's fixed now for the majority of cases (so normal CSS files going through Vite) but plugins that use the preprocessCSS() pipeline (e.g. Astro when writing CSS inside <style> blocks) still have this issue as there is no way for us to hook into it before the processing (yet).

corneliusio commented 1 week ago

Not sure if this should be noted here or in a new issue, but there is currently also an issue with setting css.transformer: 'lightningcss' when trying to use @custom-media

lightningcss can handle custom media queries, however Tailwind will throw an error Custom media query --XXXXX is not defined

philipp-spiess commented 1 week ago

@corneliusio Which version of Tailwind CSS and the Tailwind Vite plugin are you on? I was just trying this out with the Tailwind CSS Alpha 23 releases and the following Vite config:

import tailwindcss from '@tailwindcss/vite'
import { defineConfig } from 'vite'

export default defineConfig({
  css: {
    transformer: 'lightningcss',
    lightningcss: {
      drafts: {
        customMedia: true,
      },
    },
  },
  plugins: [tailwindcss()],
})

And custom-media queries seem to be correctly transpiled.

corneliusio commented 1 week ago

Ah, I'm glad you posted your config. I had missed that I needed to add drafts: { customMedia: true }. Once I added that it handled the custom media at rules as expected.

However, one thing I did discover after making this update that may or may not be an issue that can be addressed is that lightningcss will throw an error if you attempt to use the Tailwind theme() as part of the @custom-media definition.

@custom-media --screen-sm (width >= theme(--breakpoint-sm));
@custom-media --screen-md (width >= theme(--breakpoint-md));
@custom-media --screen-lg (width >= theme(--breakpoint-lg));
@custom-media --screen-xl (width >= theme(--breakpoint-xl));
@custom-media --screen-2xl (width >= theme(--breakpoint-2xl));
error during build:
[vite:css] Unexpected token Function("theme")

Edit: Using @tailwindcss/vite@4.0.0-alpha.23 and tailwindcss@4.0.0-alpha.23

philipp-spiess commented 1 week ago

Oh gotcha yes we will need to replace theme inside @custom-media. We don't do that yet. Let me add a PR :)

philipp-spiess commented 1 week ago

@corneliusio Fixed in https://github.com/tailwindlabs/tailwindcss/pull/14358 :)

corneliusio commented 1 week ago

šŸ™ŒšŸ¼ Fantastic! Now I just need Bun to get this odd edge case resolve. šŸ™ƒ