From d3a7955ee3c29dd3fffb8c18b2ad3c57665a93f5 Mon Sep 17 00:00:00 2001
From: Philipp Spiess
`, 'project-a/tailwind.config.js': js` - export default { - content: ['../project-b/src/**/*.js'], - } + export default { content: ['../project-b/src/**/*.js'] } `, 'project-a/src/index.css': css` @import 'tailwindcss/theme' theme(reference); @@ -122,7 +125,7 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => { export default defineConfig({ css: ${transformer === 'postcss' ? '{}' : "{ transformer: 'lightningcss' }"}, build: { cssMinify: false }, - plugins: [tailwindcss()], + plugins: [tailwindcss({ scanner: '${scanner}' })], }) `, 'project-a/index.html': html` @@ -142,9 +145,7 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => { `, 'project-a/tailwind.config.js': js` - export default { - content: ['../project-b/src/**/*.js'], - } + export default { content: ['../project-b/src/**/*.js'] } `, 'project-a/src/index.css': css` @import 'tailwindcss/theme' theme(reference); @@ -162,9 +163,7 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => { }, }, async ({ root, spawn, fs, expect }) => { - let process = await spawn('pnpm vite dev', { - cwd: path.join(root, 'project-a'), - }) + let process = await spawn('pnpm vite dev', { cwd: path.join(root, 'project-a') }) await process.onStdout((m) => m.includes('ready in')) let url = '' @@ -174,17 +173,19 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => { return Boolean(url) }) - // Candidates are resolved lazily, so the first visit of index.html - // will only have candidates from this file. + // Candidates are resolved lazily in module-graph mode, so the first visit of index.html will + // only have candidates from this file. await retryAssertion(async () => { let styles = await fetchStyles(url, '/index.html') expect(styles).toContain(candidate`underline`) expect(styles).toContain(candidate`flex`) - expect(styles).not.toContain(candidate`font-bold`) + + if (scanner === 'module-graph') { + expect(styles).not.toContain(candidate`font-bold`) + } }) - // Going to about.html will extend the candidate list to include - // candidates from about.html. + // Going to about.html will extend the candidate list to include candidates from about.html. await retryAssertion(async () => { let styles = await fetchStyles(url, '/about.html') expect(styles).toContain(candidate`underline`) @@ -232,8 +233,8 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => { }) await retryAssertion(async () => { - // After updates to the CSS file, all previous candidates should still be in - // the generated CSS + // After updates to the CSS file, all previous candidates should still be in the generated + // stylesheet. await fs.write( 'project-a/src/index.css', css` @@ -283,10 +284,7 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => { import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'vite' - export default defineConfig({ - build: { cssMinify: false }, - plugins: [tailwindcss()], - }) + export default defineConfig({ build: { cssMinify: false }, plugins: [tailwindcss()] }) `, 'project-a/index.html': html`
@@ -297,9 +295,7 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => { `, 'project-a/tailwind.config.js': js` - export default { - content: ['../project-b/src/**/*.js'], - } + export default { content: ['../project-b/src/**/*.js'] } `, 'project-a/src/index.css': css` @import 'tailwindcss/theme' theme(reference); @@ -324,9 +320,7 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => { }, }, async ({ root, spawn, fs, expect }) => { - let process = await spawn('pnpm vite build --watch', { - cwd: path.join(root, 'project-a'), - }) + let process = await spawn('pnpm vite build --watch', { cwd: path.join(root, 'project-a') }) await process.onStdout((m) => m.includes('built in')) let filename = '' @@ -465,7 +459,7 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => { export default defineConfig({ css: ${transformer === 'postcss' ? '{}' : "{ transformer: 'lightningcss' }"}, build: { cssMinify: false }, - plugins: [tailwindcss()], + plugins: [tailwindcss({ scanner: '${scanner}' })], }) `, 'project-a/index.html': html` @@ -551,7 +545,7 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => { export default defineConfig({ css: ${transformer === 'postcss' ? '{}' : "{ transformer: 'lightningcss' }"}, build: { cssMinify: false }, - plugins: [tailwindcss()], + plugins: [tailwindcss({ scanner: '${scanner}' })], }) `, 'project-a/index.html': html` @@ -653,7 +647,7 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => { export default defineConfig({ css: ${transformer === 'postcss' ? '{}' : "{ transformer: 'lightningcss' }"}, build: { cssMinify: false }, - plugins: [tailwindcss()], + plugins: [tailwindcss({ scanner: '${scanner}' })], }) `, 'project-a/index.html': html` @@ -702,23 +696,15 @@ test( 'package.json': json` { "type": "module", - "dependencies": { - "@tailwindcss/vite": "workspace:^", - "tailwindcss": "workspace:^" - }, - "devDependencies": { - "vite": "^6" - } + "dependencies": { "@tailwindcss/vite": "workspace:^", "tailwindcss": "workspace:^" }, + "devDependencies": { "vite": "^6" } } `, 'vite.config.ts': ts` import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'vite' - export default defineConfig({ - build: { cssMinify: false }, - plugins: [tailwindcss()], - }) + export default defineConfig({ build: { cssMinify: false }, plugins: [tailwindcss()] }) `, 'index.html': html`
@@ -784,23 +770,15 @@ test( 'package.json': json` { "type": "module", - "dependencies": { - "@tailwindcss/vite": "workspace:^", - "tailwindcss": "workspace:^" - }, - "devDependencies": { - "vite": "^6" - } + "dependencies": { "@tailwindcss/vite": "workspace:^", "tailwindcss": "workspace:^" }, + "devDependencies": { "vite": "^6" } } `, 'vite.config.ts': ts` import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'vite' - export default defineConfig({ - build: { cssMinify: false }, - plugins: [tailwindcss()], - }) + export default defineConfig({ build: { cssMinify: false }, plugins: [tailwindcss()] }) `, 'index.html': html`
@@ -860,10 +838,7 @@ test( import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'vite' - export default defineConfig({ - build: { cssMinify: false }, - plugins: [tailwindcss()], - }) + export default defineConfig({ build: { cssMinify: false }, plugins: [tailwindcss()] }) `, 'index.html': html`
diff --git a/packages/@tailwindcss-vite/src/index.ts b/packages/@tailwindcss-vite/src/index.ts
index ce61fdf9b64c..bcad05a19f2c 100644
--- a/packages/@tailwindcss-vite/src/index.ts
+++ b/packages/@tailwindcss-vite/src/index.ts
@@ -13,7 +13,13 @@ const INLINE_STYLE_ID_RE = /[?&]index\=\d+\.css$/
const IGNORED_DEPENDENCIES = ['tailwind-merge']
-export default function tailwindcss(): Plugin[] {
+type ScannerMode = 'automatic' | 'module-graph' | 'file-system'
+
+export default function tailwindcss(
+ { scanner: scannerMode = 'automatic' }: { scanner: ScannerMode } = {
+ scanner: 'automatic',
+ },
+): Plugin[] {
let servers: ViteDevServer[] = []
let config: ResolvedConfig | null = null
@@ -59,13 +65,18 @@ export default function tailwindcss(): Plugin[] {
return new Root(
id,
() => moduleGraphCandidates,
- config!.base,
+ scannerMode,
+ config!.root,
customCssResolver,
customJsResolver,
)
})
function scanFile(id: string, content: string, extension: string) {
+ if (scannerMode === 'file-system') {
+ return
+ }
+
for (let dependency of IGNORED_DEPENDENCIES) {
// We validated that Vite IDs always use posix style path separators, even on Windows.
// In dev build, Vite precompiles dependencies
@@ -197,6 +208,11 @@ export default function tailwindcss(): Plugin[] {
config = _config
minify = config.build.cssMinify !== false
isSSR = config.build.ssr !== false && config.build.ssr !== undefined
+
+ if (shouldDisableModuleGraph(config) && scannerMode === 'automatic') {
+ console.warn('Detected an Astro.js build and opted-out of using the Vite module graph.')
+ scannerMode = 'file-system'
+ }
},
// Scan all non-CSS files for candidates
@@ -416,6 +432,7 @@ class Root {
constructor(
private id: string,
private getSharedCandidates: () => MapWelcome to React Router
+ }
+ `,
+ 'app/app.css': css`@import 'tailwindcss';`,
+ 'app/routes.ts': ts`
+ import { type RouteConfig, index } from '@react-router/dev/routes'
+ export default [index('routes/home.tsx')] satisfies RouteConfig
+ `,
+ 'app/root.tsx': ts`
+ import { Links, Meta, Outlet, Scripts, ScrollRestoration } from 'react-router'
+ import './app.css'
+ export function Layout({ children }: { children: React.ReactNode }) {
+ return (
+
+
+
+
+
+