tailwindcss/integrations/vite/virtual-modules.test.ts
Philipp Spiess 59e003e6d1
Vite: Don't crash with virtual module dependencies (#16780)
Fixes #16732

If we can not get the mtime from a file, chances are that the resource
is a virtual module. This is perfectly legit and we can fall back to
what we did before the changes in `4.0.8` (which is to rebuild the root
every time a change contains a dependency like that).

## Test plan

Added a test to mimic the setup from the repor in #16732. Also ensured
the repro now passes:

<img width="1278" alt="Screenshot 2025-02-24 at 17 29 38"
src="https://github.com/user-attachments/assets/d111273d-579f-44c2-82f5-aa32d6a1879a"
/>

Note that importing virtual modules directly in CSS does not work as the
resolver we use does not resolve against the Vite runtime it seems. This
is unrelated to the regression added in `4.0.8` though and something to
look into in the future.
2025-02-25 11:29:58 +01:00

88 lines
2.3 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { candidate, css, fetchStyles, html, retryAssertion, test, ts, txt } from '../utils'
const WORKSPACE = {
'package.json': txt`
{
"type": "module",
"dependencies": {
"@tailwindcss/vite": "workspace:^",
"tailwindcss": "workspace:^"
},
"devDependencies": {
"vite": "^5.3.5"
}
}
`,
'vite.config.ts': ts`
import tailwindcss from '@tailwindcss/vite'
import { defineConfig } from 'vite'
import { fileURLToPath } from 'node:url'
export default defineConfig({
build: { cssMinify: false },
plugins: [tailwindcss(), virtualModule()],
})
function virtualModule() {
const virtualModuleId = 'virtual:my-module.css'
const resolvedVirtualModuleId = '' + virtualModuleId
return {
name: 'my-plugin',
resolveId(id) {
if (id === virtualModuleId) {
return resolvedVirtualModuleId
}
},
load(id) {
if (id === resolvedVirtualModuleId) {
return 'export default {}'
}
},
}
}
`,
'index.html': html`
<head>
<link rel="stylesheet" href="./src/index.css" />
<script type="module" src="./src/index.js"></script>
</head>
<body>
<div class="underline">Hello, world!</div>
</body>
`,
'src/index.js': ts`import 'virtual:my-module.css'`,
'src/index.css': css`@import 'tailwindcss';`,
}
test(
'does not crash when importing a virtual module ending in .css in production builds',
{ fs: WORKSPACE },
async ({ fs, exec, expect }) => {
await exec('pnpm vite build')
let files = await fs.glob('dist/**/*.css')
expect(files).toHaveLength(1)
let [filename] = files[0]
await fs.expectFileToContain(filename, [candidate`underline`])
},
)
test('loads virtual modules in dev mode', { fs: WORKSPACE }, async ({ spawn, expect }) => {
let process = await spawn('pnpm vite dev')
await process.onStdout((m) => m.includes('ready in'))
let url = ''
await process.onStdout((m) => {
let match = /Local:\s*(http.*)\//.exec(m)
if (match) url = match[1]
return Boolean(url)
})
await retryAssertion(async () => {
let styles = await fetchStyles(url, '/index.html')
expect(styles).toContain(candidate`underline`)
})
})