diff --git a/integrations/vite/build-watch.test.ts b/integrations/vite/build-watch.test.ts index a1f6af970..10008f4b8 100644 --- a/integrations/vite/build-watch.test.ts +++ b/integrations/vite/build-watch.test.ts @@ -1,5 +1,5 @@ import path from 'node:path' -import { candidate, css, js, json, test } from '../utils' +import { candidate, css, html, js, json, test } from '../utils' test( 'build watch ignores a custom output directory', @@ -47,8 +47,12 @@ test( document.body.innerHTML = '
Hello
' `, - 'resources/css/app.css': css` @import 'tailwindcss'; `, + 'resources/css/app.css': css` + @import 'tailwindcss'; + @source '../../assets/source.html'; + `, 'assets/app.js': js` console.log('previous build') `, + 'assets/source.html': html`
`, 'assets/styles.css': css` .previous-build { display: block; @@ -64,7 +68,7 @@ test( await process.onStdout((message) => message.includes('built in')) let output = path.join(root, 'assets/styles.css') - await fs.expectFileToContain(output, candidate`underline`) + await fs.expectFileToContain(output, [candidate`font-black`, candidate`underline`]) process.flush() let result = await Promise.race([ diff --git a/packages/@tailwindcss-vite/src/index.ts b/packages/@tailwindcss-vite/src/index.ts index c9b67d627..e84946978 100644 --- a/packages/@tailwindcss-vite/src/index.ts +++ b/packages/@tailwindcss-vite/src/index.ts @@ -339,6 +339,10 @@ class Root { // The lazily-initialized Tailwind scanner. private scanner?: Scanner + // A scanner for explicit `@source` paths that can opt back into paths which + // are excluded from automatic source detection. + private explicitScanner?: Scanner + // List of all candidates that were being returned by the root scanner during // the lifetime of the root. private candidates: Set = new Set() @@ -433,7 +437,7 @@ class Root { return [{ ...this.compiler.root, negated: false }] })().concat(this.compiler.sources) - if (this.buildOutputDirectory !== null) { + if (this.buildOutputDirectory !== null && this.compiler.root === null) { // Watching files emitted by Vite would trigger another build every time // the output is written. sources.push({ @@ -444,6 +448,10 @@ class Root { } this.scanner = new Scanner({ sources }) + this.explicitScanner = + this.compiler.sources.length > 0 + ? new Scanner({ sources: this.compiler.sources }) + : undefined DEBUG && I.end('Setup scanner') } else { for (let buildDependency of this.buildDependencies.keys()) { @@ -469,47 +477,55 @@ class Root { // setup a new scanner and compiler every time we request the CSS file // (regardless whether it actually changed or not). DEBUG && I.start('Scan for candidates') - for (let candidate of this.scanner.scan()) { - this.candidates.add(candidate) + for (let scanner of [this.scanner, this.explicitScanner]) { + if (!scanner) continue + + for (let candidate of scanner.scan()) { + this.candidates.add(candidate) + } } DEBUG && I.end('Scan for candidates') } if (this.compiler.features & Features.Utilities) { DEBUG && I.start('Register dependency messages') - // Watch individual files found via custom `@source` paths - for (let file of this.scanner.files) { - addWatchFile(file) - } + for (let scanner of [this.scanner, this.explicitScanner]) { + if (!scanner) continue - // Watch globs found via custom `@source` paths - for (let glob of this.scanner.globs) { - if (glob.pattern[0] === '!') continue - - let relative = path.relative(this.base, glob.base) - if (relative[0] !== '.') { - relative = './' + relative + // Watch individual files found via custom `@source` paths + for (let file of scanner.files) { + addWatchFile(file) } - // Ensure relative is a posix style path since we will merge it with the - // glob. - relative = normalizePath(relative) - addWatchFile(path.posix.join(relative, glob.pattern)) + // Watch globs found via custom `@source` paths + for (let glob of scanner.globs) { + if (glob.pattern[0] === '!') continue - let root = this.compiler.root + let relative = path.relative(this.base, glob.base) + if (relative[0] !== '.') { + relative = './' + relative + } + // Ensure relative is a posix style path since we will merge it with the + // glob. + relative = normalizePath(relative) - if (root !== 'none' && root !== null) { - let basePath = normalizePath(path.resolve(root.base, root.pattern)) + addWatchFile(path.posix.join(relative, glob.pattern)) - let isDir = await fs.stat(basePath).then( - (stats) => stats.isDirectory(), - () => false, - ) + let root = this.compiler.root - if (!isDir) { - throw new Error( - `The path given to \`source(…)\` must be a directory but got \`source(${basePath})\` instead.`, + if (root !== 'none' && root !== null) { + let basePath = normalizePath(path.resolve(root.base, root.pattern)) + + let isDir = await fs.stat(basePath).then( + (stats) => stats.isDirectory(), + () => false, ) + + if (!isDir) { + throw new Error( + `The path given to \`source(…)\` must be a directory but got \`source(${basePath})\` instead.`, + ) + } } } }