mirror of
https://github.com/hanzoai/tailwindcss.git
synced 2026-09-24 17:03:14 +00:00
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.
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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 (
|
||||
<QwikCityProvider>
|
||||
<head></head>
|
||||
<body>
|
||||
<RouterOutlet />
|
||||
</body>
|
||||
</QwikCityProvider>
|
||||
)
|
||||
})
|
||||
`,
|
||||
'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(<Root />, opts)
|
||||
}
|
||||
`,
|
||||
'src/routes/index.tsx': ts`
|
||||
import { component$ } from '@builder.io/qwik'
|
||||
|
||||
export default component$(() => {
|
||||
return <h1 class="underline">Hello World!</h1>
|
||||
})
|
||||
`,
|
||||
},
|
||||
},
|
||||
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 <h1 class="underline flex">Hello World!</h1>
|
||||
})
|
||||
`,
|
||||
)
|
||||
|
||||
let css = await fetchStyles(url)
|
||||
expect(css).toContain(candidate`underline`)
|
||||
expect(css).toContain(candidate`flex`)
|
||||
})
|
||||
},
|
||||
)
|
||||
@@ -184,7 +184,15 @@ class Root {
|
||||
_addWatchFile: (file: string) => void,
|
||||
I: Instrumentation,
|
||||
): Promise<string | false> {
|
||||
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)) {
|
||||
|
||||
Reference in New Issue
Block a user