@@ -203,9 +203,6 @@ export async function handle(args: Result<ReturnType<typeof options>>) {
203203
204204 // Scan the entire `base` directory for full rebuilds.
205205 if ( rebuildStrategy === 'full' ) {
206- // Clear all watchers
207- cleanupWatchers ( )
208-
209206 // Read the new `input`.
210207 let input = args [ '--input' ]
211208 ? args [ '--input' ] === '-'
@@ -226,7 +223,12 @@ export async function handle(args: Result<ReturnType<typeof options>>) {
226223 env . DEBUG && console . timeEnd ( '[@tailwindcss/cli] Scan for candidates' )
227224
228225 // Setup new watchers
229- cleanupWatchers = await createWatchers ( watchDirectories ( scanner ) , handle )
226+ let newCleanupWatchers = await createWatchers ( watchDirectories ( scanner ) , handle )
227+
228+ // Clear old watchers
229+ await cleanupWatchers ( )
230+
231+ cleanupWatchers = newCleanupWatchers
230232
231233 // Re-compile the CSS
232234 env . DEBUG && console . time ( '[@tailwindcss/cli] Build CSS' )
@@ -271,8 +273,10 @@ export async function handle(args: Result<ReturnType<typeof options>>) {
271273 // disable this behavior with `--watch=always`.
272274 if ( args [ '--watch' ] !== 'always' ) {
273275 process . stdin . on ( 'end' , ( ) => {
274- cleanupWatchers ( )
275- process . exit ( 0 )
276+ cleanupWatchers ( ) . then (
277+ ( ) => process . exit ( 0 ) ,
278+ ( ) => process . exit ( 1 ) ,
279+ )
276280 } )
277281 }
278282
@@ -307,6 +311,29 @@ function watchDirectories(scanner: Scanner) {
307311}
308312
309313async function createWatchers ( dirs : string [ ] , cb : ( files : string [ ] ) => void ) {
314+ // Remove any directories that are children of an already watched directory.
315+ // If we don't we may not get notified of certain filesystem events regardless
316+ // of whether or not they are for the directory that is duplicated.
317+
318+ // 1. Sort in asc by length
319+ dirs = dirs . sort ( ( a , z ) => a . length - z . length )
320+
321+ // 2. Remove any directories that are children of another directory
322+ let toRemove = [ ]
323+
324+ // /project-a 0
325+ // /project-a/src 1
326+
327+ for ( let i = 0 ; i < dirs . length ; ++ i ) {
328+ for ( let j = 0 ; j < i ; ++ j ) {
329+ if ( ! dirs [ i ] . startsWith ( `${ dirs [ j ] } /` ) ) continue
330+
331+ toRemove . push ( dirs [ i ] )
332+ }
333+ }
334+
335+ dirs = dirs . filter ( ( dir ) => ! toRemove . includes ( dir ) )
336+
310337 // Track all Parcel watchers for each glob.
311338 //
312339 // When we encounter a change in a CSS file, we need to setup new watchers and
@@ -322,9 +349,9 @@ async function createWatchers(dirs: string[], cb: (files: string[]) => void) {
322349 // A changed file can be watched by multiple watchers, but we only want to
323350 // handle the file once. We debounce the handle function with the collected
324351 // files to handle them in a single batch and to avoid multiple rebuilds.
325- function enqueueCallback ( ) {
326- // Dispose all existing macrotask .
327- debounceQueue . dispose ( )
352+ async function enqueueCallback ( ) {
353+ // Dispose all existing macrotasks .
354+ await debounceQueue . dispose ( )
328355
329356 // Setup a new macrotask to handle the files in batch.
330357 debounceQueue . queueMacrotask ( ( ) => {
@@ -365,17 +392,17 @@ async function createWatchers(dirs: string[], cb: (files: string[]) => void) {
365392 )
366393
367394 // Handle the tracked files at some point in the future.
368- enqueueCallback ( )
395+ await enqueueCallback ( )
369396 } )
370397
371398 // Ensure we cleanup the watcher when we're done.
372399 watchers . add ( unsubscribe )
373400 }
374401
375402 // Cleanup
376- return ( ) => {
377- watchers . dispose ( )
378- debounceQueue . dispose ( )
403+ return async ( ) => {
404+ await watchers . dispose ( )
405+ await debounceQueue . dispose ( )
379406 }
380407}
381408
0 commit comments