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.`,
+ )
+ }
}
}
}