@@ -203,9 +203,6 @@ export async function handle(args: Result<ReturnType<typeof options>>) {
203
203
204
204
// Scan the entire `base` directory for full rebuilds.
205
205
if ( rebuildStrategy === 'full' ) {
206
- // Clear all watchers
207
- cleanupWatchers ( )
208
-
209
206
// Read the new `input`.
210
207
let input = args [ '--input' ]
211
208
? args [ '--input' ] === '-'
@@ -226,7 +223,12 @@ export async function handle(args: Result<ReturnType<typeof options>>) {
226
223
env . DEBUG && console . timeEnd ( '[@tailwindcss/cli] Scan for candidates' )
227
224
228
225
// 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
230
232
231
233
// Re-compile the CSS
232
234
env . DEBUG && console . time ( '[@tailwindcss/cli] Build CSS' )
@@ -271,8 +273,10 @@ export async function handle(args: Result<ReturnType<typeof options>>) {
271
273
// disable this behavior with `--watch=always`.
272
274
if ( args [ '--watch' ] !== 'always' ) {
273
275
process . stdin . on ( 'end' , ( ) => {
274
- cleanupWatchers ( )
275
- process . exit ( 0 )
276
+ cleanupWatchers ( ) . then (
277
+ ( ) => process . exit ( 0 ) ,
278
+ ( ) => process . exit ( 1 ) ,
279
+ )
276
280
} )
277
281
}
278
282
@@ -307,6 +311,29 @@ function watchDirectories(scanner: Scanner) {
307
311
}
308
312
309
313
async 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
+
310
337
// Track all Parcel watchers for each glob.
311
338
//
312
339
// 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) {
322
349
// A changed file can be watched by multiple watchers, but we only want to
323
350
// handle the file once. We debounce the handle function with the collected
324
351
// 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 ( )
328
355
329
356
// Setup a new macrotask to handle the files in batch.
330
357
debounceQueue . queueMacrotask ( ( ) => {
@@ -365,17 +392,17 @@ async function createWatchers(dirs: string[], cb: (files: string[]) => void) {
365
392
)
366
393
367
394
// Handle the tracked files at some point in the future.
368
- enqueueCallback ( )
395
+ await enqueueCallback ( )
369
396
} )
370
397
371
398
// Ensure we cleanup the watcher when we're done.
372
399
watchers . add ( unsubscribe )
373
400
}
374
401
375
402
// Cleanup
376
- return ( ) => {
377
- watchers . dispose ( )
378
- debounceQueue . dispose ( )
403
+ return async ( ) => {
404
+ await watchers . dispose ( )
405
+ await debounceQueue . dispose ( )
379
406
}
380
407
}
381
408
0 commit comments