CLI: Ignore watch events for files that don't match globs (#9215)

* Don’t re-add files in the CLI watcher that are covered by dynamic patterns

They don’t have the same problem. As long as the parent directory is watched their add/change events will fire correctly

* Ignore raw events for files that don’t match the content files

* fixup

* Update changelog
This commit is contained in:
Jordan Pittman 2022-08-31 12:59:56 -04:00 • committed by GitHub
parent edf47a012d
commit 8b1bf8006d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 35 additions and 4 deletions

View file

@ -21,7 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Sort tags before classes when `@applying` a selector with joined classes ([#9107](https://github.com/tailwindlabs/tailwindcss/pull/9107))
- Remove invalid `outline-hidden` utility ([#9147](https://github.com/tailwindlabs/tailwindcss/pull/9147))
- Honor the `hidden` attribute on elements in preflight ([#9174](https://github.com/tailwindlabs/tailwindcss/pull/9174))
- Don't stop watching atomically renamed files ([#9173](https://github.com/tailwindlabs/tailwindcss/pull/9173))
- Don't stop watching atomically renamed files ([#9173](https://github.com/tailwindlabs/tailwindcss/pull/9173), [#9215](https://github.com/tailwindlabs/tailwindcss/pull/9215))
- Re-use existing entries in the rule cache ([#9208](https://github.com/tailwindlabs/tailwindcss/pull/9208))
- Don't output duplicate utilities ([#9208](https://github.com/tailwindlabs/tailwindcss/pull/9208))
- Fix `fontFamily` config TypeScript types ([#9214](https://github.com/tailwindlabs/tailwindcss/pull/9214))

View file

@ -17,6 +17,7 @@ import getModuleDependencies from './lib/getModuleDependencies'
import log from './util/log'
import packageJson from '../package.json'
import normalizePath from 'normalize-path'
import micromatch from 'micromatch'
import { validateConfig } from './util/validateConfig.js'
let env = {
@ -837,6 +838,23 @@ async function build() {
}
let config = refreshConfig(configPath)
let contentPatterns = refreshContentPatterns(config)
/**
* @param {import('../types/config.js').RequiredConfig} config
* @return {{all: string[], dynamic: string[], static: string[]}}
**/
function refreshContentPatterns(config) {
let globs = extractFileGlobs(config)
let tasks = fastGlob.generateTasks(globs, { absolute: true })
let dynamicPatterns = tasks.filter((task) => task.dynamic).flatMap((task) => task.patterns)
let staticPatterns = tasks.filter((task) => !task.dynamic).flatMap((task) => task.patterns)
return {
all: [...staticPatterns, ...dynamicPatterns],
dynamic: dynamicPatterns,
}
}
if (input) {
contextDependencies.add(path.resolve(input))
@ -867,6 +885,7 @@ async function build() {
env.DEBUG && console.time('Resolve config')
context = null
config = refreshConfig(configPath)
contentPatterns = refreshContentPatterns(config)
env.DEBUG && console.timeEnd('Resolve config')
env.DEBUG && console.time('Watch new files')
@ -924,7 +943,14 @@ async function build() {
// Restore watching any files that are "removed"
// This can happen when a file is pseudo-atomically replaced (a copy is created, overwritten, the old one is unlinked, and the new one is renamed)
// TODO: An an optimization we should allow removal when the config changes
watcher.on('unlink', (file) => watcher.add(file))
watcher.on('unlink', (file) => {
file = normalizePath(file)
// Only re-add the file if it's not covered by a dynamic pattern
if (!micromatch.some([file], contentPatterns.dynamic)) {
watcher.add(file)
}
})
// Some applications such as Visual Studio (but not VS Code)
// will only fire a rename event for atomic writes and not a change event
@ -935,11 +961,16 @@ async function build() {
return
}
let watchedPath = path.resolve(meta.watchedPath)
let watchedPath = meta.watchedPath
// Watched path might be the file itself
// Or the directory it is in
filePath = watchedPath.endsWith(filePath) ? watchedPath : path.resolve(watchedPath, filePath)
filePath = watchedPath.endsWith(filePath) ? watchedPath : path.join(watchedPath, filePath)
// Skip this event since the files it is for does not match any of the registered content globs
if (!micromatch.some([filePath], contentPatterns.all)) {
return
}
// Skip since we've already queued a rebuild for this file that hasn't happened yet
if (pendingRebuilds.has(filePath)) {