diff --git a/CHANGELOG.md b/CHANGELOG.md index ae525cc8c69b..b53d74ef35fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - PostCSS: Ensure files containing `@tailwind utilities` are processed ([#17514](https://github.com/tailwindlabs/tailwindcss/pull/17514)) - Ensure the `color-mix(…)` polyfill creates fallbacks even when using colors that cannot be statically analyzed ([#17513](https://github.com/tailwindlabs/tailwindcss/pull/17513)) - Fix slow incremental builds with `@tailwindcss/vite` and `@tailwindcss/postscss` (especially on Windows) ([#17511](https://github.com/tailwindlabs/tailwindcss/pull/17511)) +- Vite: Fix an issue with Qwik setups ([#17533](https://github.com/tailwindlabs/tailwindcss/pull/17533)) ## [4.1.1] - 2025-04-02 diff --git a/integrations/vite/qwik.test.ts b/integrations/vite/qwik.test.ts new file mode 100644 index 000000000000..42db6563aa7a --- /dev/null +++ b/integrations/vite/qwik.test.ts @@ -0,0 +1,100 @@ +import { candidate, css, fetchStyles, json, retryAssertion, test, ts } from '../utils' + +test( + 'dev mode', + { + fs: { + 'package.json': json` + { + "type": "module", + "dependencies": { + "@builder.io/qwik": "^1", + "@builder.io/qwik-city": "^1", + "vite": "^5", + "@tailwindcss/vite": "workspace:^", + "tailwindcss": "workspace:^" + } + } + `, + 'vite.config.ts': ts` + import { defineConfig } from 'vite' + import { qwikVite } from '@builder.io/qwik/optimizer' + import { qwikCity } from '@builder.io/qwik-city/vite' + import tailwindcss from '@tailwindcss/vite' + + export default defineConfig(() => { + return { + plugins: [tailwindcss(), qwikCity(), qwikVite()], + } + }) + `, + 'src/root.tsx': ts` + import { component$ } from '@builder.io/qwik' + import { QwikCityProvider, RouterOutlet } from '@builder.io/qwik-city' + + import './global.css' + + export default component$(() => { + return ( + + + + + + + ) + }) + `, + 'src/global.css': css`@import 'tailwindcss/utilities.css';`, + 'src/entry.ssr.tsx': ts` + import { renderToStream, type RenderToStreamOptions } from '@builder.io/qwik/server' + import Root from './root' + + export default function (opts: RenderToStreamOptions) { + return renderToStream(, opts) + } + `, + 'src/routes/index.tsx': ts` + import { component$ } from '@builder.io/qwik' + + export default component$(() => { + return

Hello World!

+ }) + `, + }, + }, + async ({ fs, spawn, expect }) => { + let process = await spawn('pnpm vite --mode ssr') + await process.onStdout((m) => m.includes('ready in')) + + let url = '' + await process.onStdout((m) => { + console.log(m) + let match = /Local:\s*(http.*)\//.exec(m) + if (match) url = match[1] + return Boolean(url) + }) + + await retryAssertion(async () => { + let css = await fetchStyles(url) + expect(css).toContain(candidate`underline`) + }) + + await retryAssertion(async () => { + await fs.write( + 'src/routes/index.tsx', + ts` + import { component$ } from '@builder.io/qwik' + + export default component$(() => { + return

Hello World!

+ }) + `, + ) + + let css = await fetchStyles(url) + expect(css).toContain(candidate`underline`) + expect(css).toContain(candidate`flex`) + }) + }, +) diff --git a/packages/@tailwindcss-vite/src/index.ts b/packages/@tailwindcss-vite/src/index.ts index b47201b247a6..a484583a3ec3 100644 --- a/packages/@tailwindcss-vite/src/index.ts +++ b/packages/@tailwindcss-vite/src/index.ts @@ -184,7 +184,15 @@ class Root { _addWatchFile: (file: string) => void, I: Instrumentation, ): Promise { + let inputPath = idToPath(this.id) + function addWatchFile(file: string) { + // Don't watch the input file since it's already a dependency anc causes + // issues with some setups (e.g. Qwik). + if (file === inputPath) { + return + } + // Scanning `.svg` file containing a `#` or `?` in the path will // crash Vite. We work around this for now by ignoring updates to them. // @@ -196,7 +204,6 @@ class Root { } let requiresBuildPromise = this.requiresBuild() - let inputPath = idToPath(this.id) let inputBase = path.dirname(path.resolve(inputPath)) if (!this.compiler || !this.scanner || (await requiresBuildPromise)) {