-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix Nuxt integration #14319
Fix Nuxt integration #14319
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import { expect } from 'vitest' | ||
import { candidate, css, fetchStyles, html, json, retryAssertion, test, ts } from '../utils' | ||
|
||
test( | ||
'dev mode', | ||
{ | ||
fs: { | ||
'package.json': json` | ||
{ | ||
"type": "module", | ||
"dependencies": { | ||
"@tailwindcss/vite": "workspace:^", | ||
"nuxt": "^3.13.1", | ||
"tailwindcss": "workspace:^", | ||
"vue": "latest" | ||
} | ||
} | ||
`, | ||
'nuxt.config.ts': ts` | ||
import tailwindcss from '@tailwindcss/vite' | ||
|
||
// https://nuxt.com/docs/api/configuration/nuxt-config | ||
export default defineNuxtConfig({ | ||
vite: { | ||
plugins: [tailwindcss()], | ||
}, | ||
|
||
css: ['~/assets/css/main.css'], | ||
devtools: { enabled: true }, | ||
compatibilityDate: '2024-08-30', | ||
}) | ||
`, | ||
'app.vue': html` | ||
<template> | ||
<div class="underline">Hello world!</div> | ||
</template> | ||
`, | ||
'assets/css/main.css': css`@import 'tailwindcss';`, | ||
}, | ||
}, | ||
async ({ fs, spawn, getFreePort }) => { | ||
let port = await getFreePort() | ||
await spawn(`pnpm nuxt dev --port ${port}`) | ||
|
||
await retryAssertion(async () => { | ||
let css = await fetchStyles(port) | ||
expect(css).toContain(candidate`underline`) | ||
}) | ||
|
||
await fs.write( | ||
'app.vue', | ||
html` | ||
<template> | ||
<div class="underline font-bold">Hello world!</div> | ||
</template> | ||
`, | ||
) | ||
await retryAssertion(async () => { | ||
let css = await fetchStyles(port) | ||
expect(css).toContain(candidate`underline`) | ||
expect(css).toContain(candidate`font-bold`) | ||
}) | ||
}, | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,7 +11,7 @@ import postcssImport from 'postcss-import' | |
import type { Plugin, ResolvedConfig, Rollup, Update, ViteDevServer } from 'vite' | ||
|
||
export default function tailwindcss(): Plugin[] { | ||
let server: ViteDevServer | null = null | ||
let servers: ViteDevServer[] = [] | ||
let config: ResolvedConfig | null = null | ||
|
||
let isSSR = false | ||
|
@@ -58,36 +58,35 @@ export default function tailwindcss(): Plugin[] { | |
} | ||
|
||
function invalidateAllRoots(isSSR: boolean) { | ||
// If we're building then we don't need to update anything | ||
if (!server) return | ||
|
||
let updates: Update[] = [] | ||
for (let id of roots.keys()) { | ||
let module = server.moduleGraph.getModuleById(id) | ||
if (!module) { | ||
// Note: Removing this during SSR is not safe and will produce | ||
// inconsistent results based on the timing of the removal and | ||
// the order / timing of transforms. | ||
if (!isSSR) { | ||
// It is safe to remove the item here since we're iterating on a copy | ||
// of the keys. | ||
roots.delete(id) | ||
for (let server of servers) { | ||
let updates: Update[] = [] | ||
for (let id of roots.keys()) { | ||
let module = server.moduleGraph.getModuleById(id) | ||
if (!module) { | ||
// Note: Removing this during SSR is not safe and will produce | ||
// inconsistent results based on the timing of the removal and | ||
// the order / timing of transforms. | ||
if (!isSSR) { | ||
// It is safe to remove the item here since we're iterating on a copy | ||
// of the keys. | ||
roots.delete(id) | ||
} | ||
continue | ||
} | ||
continue | ||
} | ||
|
||
roots.get(id).requiresRebuild = false | ||
server.moduleGraph.invalidateModule(module) | ||
updates.push({ | ||
type: `${module.type}-update`, | ||
path: module.url, | ||
acceptedPath: module.url, | ||
timestamp: Date.now(), | ||
}) | ||
} | ||
roots.get(id).requiresRebuild = false | ||
server.moduleGraph.invalidateModule(module) | ||
updates.push({ | ||
type: `${module.type}-update`, | ||
path: module.url, | ||
acceptedPath: module.url, | ||
timestamp: Date.now(), | ||
}) | ||
} | ||
|
||
if (updates.length > 0) { | ||
server.hot.send({ type: 'update', updates }) | ||
if (updates.length > 0) { | ||
server.hot.send({ type: 'update', updates }) | ||
} | ||
} | ||
} | ||
|
||
|
@@ -139,8 +138,8 @@ export default function tailwindcss(): Plugin[] { | |
name: '@tailwindcss/vite:scan', | ||
enforce: 'pre', | ||
|
||
configureServer(_server) { | ||
server = _server | ||
configureServer(server) { | ||
servers.push(server) | ||
}, | ||
|
||
async configResolved(_config) { | ||
|
@@ -169,7 +168,7 @@ export default function tailwindcss(): Plugin[] { | |
}, | ||
transform(src, id, options) { | ||
let extension = getExtension(id) | ||
if (extension === '' || extension === 'css') return | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is an optimization that makes sure vite |
||
if (isPotentialCssRootFile(id)) return | ||
scanFile(id, src, extension, options?.ssr ?? false) | ||
}, | ||
}, | ||
|
@@ -193,7 +192,7 @@ export default function tailwindcss(): Plugin[] { | |
// The reason why we can not rely on the invalidation here is that the | ||
// users would otherwise see a flicker in the styles as the CSS might | ||
// be loaded with an invalid set of candidates first. | ||
await server?.waitForRequestsIdle?.(id) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need to bump the minimum Vite version to the one where |
||
await Promise.all(servers.map((server) => server.waitForRequestsIdle(id))) | ||
} | ||
|
||
let generated = await root.generate(src, (file) => this.addWatchFile(file)) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not happy about this line but if we want to mention the improved Nuxt support we should mention the version number, otherwise people try it and it won't work 😢
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems fine to me tbh