Skip to content

Commit b766949

Browse files
committed
add source(…) improvements to @tailwindcss/vite
1 parent 35268fe commit b766949

File tree

1 file changed

+74
-10
lines changed

1 file changed

+74
-10
lines changed

packages/@tailwindcss-vite/src/index.ts

+74-10
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { compile, env, normalizePath } from '@tailwindcss/node'
22
import { clearRequireCache } from '@tailwindcss/node/require-cache'
33
import { Scanner } from '@tailwindcss/oxide'
44
import { Features, transform } from 'lightningcss'
5+
import fs from 'node:fs/promises'
56
import path from 'path'
67
import type { Plugin, ResolvedConfig, Rollup, Update, ViteDevServer } from 'vite'
78

@@ -35,7 +36,7 @@ export default function tailwindcss(): Plugin[] {
3536
// Note: To improve performance, we do not remove candidates from this set.
3637
// This means a longer-ongoing dev mode session might contain candidates that
3738
// are no longer referenced in code.
38-
let moduleGraphCandidates = new Set<string>()
39+
let moduleGraphCandidates = new DefaultMap<string, Set<string>>(() => new Set<string>())
3940
let moduleGraphScanner = new Scanner({})
4041

4142
let roots: DefaultMap<string, Root> = new DefaultMap(
@@ -46,7 +47,7 @@ export default function tailwindcss(): Plugin[] {
4647
let updated = false
4748
for (let candidate of moduleGraphScanner.scanFiles([{ content, extension }])) {
4849
updated = true
49-
moduleGraphCandidates.add(candidate)
50+
moduleGraphCandidates.get(id).add(candidate)
5051
}
5152

5253
if (updated) {
@@ -343,14 +344,16 @@ class Root {
343344
// the lifetime of the root.
344345
private candidates: Set<string> = new Set<string>()
345346

346-
// List of all file dependencies that were captured while generating the root.
347-
// These are retained so we can clear the require cache when we rebuild the
348-
// root.
347+
// List of all dependencies captured while generating the root. These are
348+
// retained so we can clear the require cache when we rebuild the root.
349349
private dependencies = new Set<string>()
350350

351+
// The resolved path given to `source(…)`. When not given this is `null`.
352+
private basePath: string | null = null
353+
351354
constructor(
352355
private id: string,
353-
private getSharedCandidates: () => Set<string>,
356+
private getSharedCandidates: () => Map<string, Set<string>>,
354357
private base: string,
355358
) {}
356359

@@ -379,9 +382,22 @@ class Root {
379382
})
380383
env.DEBUG && console.timeEnd('[@tailwindcss/vite] Setup compiler')
381384

382-
this.scanner = new Scanner({
383-
sources: this.compiler.globs,
384-
})
385+
let sources = (() => {
386+
// Disable auto source detection
387+
if (this.compiler.root === 'none') {
388+
return []
389+
}
390+
391+
// No root specified, use the module graph
392+
if (this.compiler.root === null) {
393+
return []
394+
}
395+
396+
// Use the specified root
397+
return [this.compiler.root]
398+
})().concat(this.compiler.globs)
399+
400+
this.scanner = new Scanner({ sources })
385401
}
386402

387403
// This should not be here, but right now the Vite plugin is setup where we
@@ -411,14 +427,62 @@ class Root {
411427
relative = normalizePath(relative)
412428

413429
addWatchFile(path.posix.join(relative, glob.pattern))
430+
431+
let root = this.compiler.root
432+
433+
if (root !== 'none' && root !== null) {
434+
let basePath = path.posix.resolve(root.base, root.pattern)
435+
436+
let isDir = await fs.stat(basePath).then(
437+
(stats) => stats.isDirectory(),
438+
() => false,
439+
)
440+
441+
if (!isDir) {
442+
throw new Error(
443+
`The path given to \`source(…)\` must be a directory but got \`source(${basePath})\` instead.`,
444+
)
445+
}
446+
447+
this.basePath = basePath
448+
} else if (root === null) {
449+
this.basePath = null
450+
}
414451
}
415452

416453
this.requiresRebuild = true
417454

418455
env.DEBUG && console.time('[@tailwindcss/vite] Build CSS')
419-
let result = this.compiler.build([...this.getSharedCandidates(), ...this.candidates])
456+
let result = this.compiler.build([...this.sharedCandidates(), ...this.candidates])
420457
env.DEBUG && console.timeEnd('[@tailwindcss/vite] Build CSS')
421458

422459
return result
423460
}
461+
462+
private sharedCandidates(): Set<string> {
463+
if (!this.compiler) return new Set()
464+
if (this.compiler.root === 'none') return new Set()
465+
466+
let shouldIncludeCandidatesFrom = (id: string) => {
467+
if (this.basePath === null) return true
468+
469+
// This a virtual module that's not on the file system
470+
// TODO: What should we do here?
471+
if (!id.startsWith('/')) return true
472+
473+
return id.startsWith(this.basePath)
474+
}
475+
476+
let shared = new Set<string>()
477+
478+
for (let [id, candidates] of this.getSharedCandidates()) {
479+
if (!shouldIncludeCandidatesFrom(id)) continue
480+
481+
for (let candidate of candidates) {
482+
shared.add(candidate)
483+
}
484+
}
485+
486+
return shared
487+
}
424488
}

0 commit comments

Comments
 (0)