Skip to content

Commit 3f434a6

Browse files
Vite: Don't register the current CSS file as a dependency on itself (#17533)
Closes #17512 One of the changes of the Oxide API in 4.1 is that it now emits the input CSS file itself as a dependency. This was fine in most of our testing but it turns out that certain integrations (in this case a Qwik project) don't like this and will silently crash with no CSS file being added anymore. This PR fixes this by making sure we don't add the input file as a dependency on itself and also adds an integration test to ensure this won't regress again. ## Test plan - Tested with the repro provided in #17512 - Added a minimal integration test based on that reproduction that I also validated will _fail_, if the fix is reverted.
1 parent 4c99367 commit 3f434a6

File tree

3 files changed

+109
-1
lines changed

3 files changed

+109
-1
lines changed

Diff for: CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2020
- PostCSS: Ensure files containing `@tailwind utilities` are processed ([#17514](https://github.com/tailwindlabs/tailwindcss/pull/17514))
2121
- Ensure the `color-mix(…)` polyfill creates fallbacks even when using colors that cannot be statically analyzed ([#17513](https://github.com/tailwindlabs/tailwindcss/pull/17513))
2222
- Fix slow incremental builds with `@tailwindcss/vite` and `@tailwindcss/postscss` (especially on Windows) ([#17511](https://github.com/tailwindlabs/tailwindcss/pull/17511))
23+
- Vite: Fix an issue with Qwik setups ([#17533](https://github.com/tailwindlabs/tailwindcss/pull/17533))
2324

2425
## [4.1.1] - 2025-04-02
2526

Diff for: integrations/vite/qwik.test.ts

+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import { candidate, css, fetchStyles, json, retryAssertion, test, ts } from '../utils'
2+
3+
test(
4+
'dev mode',
5+
{
6+
fs: {
7+
'package.json': json`
8+
{
9+
"type": "module",
10+
"dependencies": {
11+
"@builder.io/qwik": "^1",
12+
"@builder.io/qwik-city": "^1",
13+
"vite": "^5",
14+
"@tailwindcss/vite": "workspace:^",
15+
"tailwindcss": "workspace:^"
16+
}
17+
}
18+
`,
19+
'vite.config.ts': ts`
20+
import { defineConfig } from 'vite'
21+
import { qwikVite } from '@builder.io/qwik/optimizer'
22+
import { qwikCity } from '@builder.io/qwik-city/vite'
23+
import tailwindcss from '@tailwindcss/vite'
24+
25+
export default defineConfig(() => {
26+
return {
27+
plugins: [tailwindcss(), qwikCity(), qwikVite()],
28+
}
29+
})
30+
`,
31+
'src/root.tsx': ts`
32+
import { component$ } from '@builder.io/qwik'
33+
import { QwikCityProvider, RouterOutlet } from '@builder.io/qwik-city'
34+
35+
import './global.css'
36+
37+
export default component$(() => {
38+
return (
39+
<QwikCityProvider>
40+
<head></head>
41+
<body>
42+
<RouterOutlet />
43+
</body>
44+
</QwikCityProvider>
45+
)
46+
})
47+
`,
48+
'src/global.css': css`@import 'tailwindcss/utilities.css';`,
49+
'src/entry.ssr.tsx': ts`
50+
import { renderToStream, type RenderToStreamOptions } from '@builder.io/qwik/server'
51+
import Root from './root'
52+
53+
export default function (opts: RenderToStreamOptions) {
54+
return renderToStream(<Root />, opts)
55+
}
56+
`,
57+
'src/routes/index.tsx': ts`
58+
import { component$ } from '@builder.io/qwik'
59+
60+
export default component$(() => {
61+
return <h1 class="underline">Hello World!</h1>
62+
})
63+
`,
64+
},
65+
},
66+
async ({ fs, spawn, expect }) => {
67+
let process = await spawn('pnpm vite --mode ssr')
68+
await process.onStdout((m) => m.includes('ready in'))
69+
70+
let url = ''
71+
await process.onStdout((m) => {
72+
console.log(m)
73+
let match = /Local:\s*(http.*)\//.exec(m)
74+
if (match) url = match[1]
75+
return Boolean(url)
76+
})
77+
78+
await retryAssertion(async () => {
79+
let css = await fetchStyles(url)
80+
expect(css).toContain(candidate`underline`)
81+
})
82+
83+
await retryAssertion(async () => {
84+
await fs.write(
85+
'src/routes/index.tsx',
86+
ts`
87+
import { component$ } from '@builder.io/qwik'
88+
89+
export default component$(() => {
90+
return <h1 class="underline flex">Hello World!</h1>
91+
})
92+
`,
93+
)
94+
95+
let css = await fetchStyles(url)
96+
expect(css).toContain(candidate`underline`)
97+
expect(css).toContain(candidate`flex`)
98+
})
99+
},
100+
)

Diff for: packages/@tailwindcss-vite/src/index.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,15 @@ class Root {
184184
_addWatchFile: (file: string) => void,
185185
I: Instrumentation,
186186
): Promise<string | false> {
187+
let inputPath = idToPath(this.id)
188+
187189
function addWatchFile(file: string) {
190+
// Don't watch the input file since it's already a dependency anc causes
191+
// issues with some setups (e.g. Qwik).
192+
if (file === inputPath) {
193+
return
194+
}
195+
188196
// Scanning `.svg` file containing a `#` or `?` in the path will
189197
// crash Vite. We work around this for now by ignoring updates to them.
190198
//
@@ -196,7 +204,6 @@ class Root {
196204
}
197205

198206
let requiresBuildPromise = this.requiresBuild()
199-
let inputPath = idToPath(this.id)
200207
let inputBase = path.dirname(path.resolve(inputPath))
201208

202209
if (!this.compiler || !this.scanner || (await requiresBuildPromise)) {

0 commit comments

Comments
 (0)