diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d7a1fcbeb31..b05c7f1cbaf2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Handle `'` syntax in ClojureScript when extracting classes ([#18888](https://github.com/tailwindlabs/tailwindcss/pull/18888)) - Handle `@variant` inside `@custom-variant` ([#18885](https://github.com/tailwindlabs/tailwindcss/pull/18885)) - Merge suggestions when using `@utility` ([#18900](https://github.com/tailwindlabs/tailwindcss/pull/18900)) +- Ensure that file system watchers created when using the CLI are always cleaned up ([#18905](https://github.com/tailwindlabs/tailwindcss/pull/18905)) ## [4.1.13] - 2025-09-03 diff --git a/packages/@tailwindcss-cli/src/commands/build/index.ts b/packages/@tailwindcss-cli/src/commands/build/index.ts index 206bf27fbca2..794b54ae3be6 100644 --- a/packages/@tailwindcss-cli/src/commands/build/index.ts +++ b/packages/@tailwindcss-cli/src/commands/build/index.ts @@ -239,9 +239,9 @@ export async function handle(args: Result>) { // Watch for changes if (args['--watch']) { - let cleanupWatchers = await createWatchers( - watchDirectories(scanner), - async function handle(files) { + let cleanupWatchers: (() => Promise)[] = [] + cleanupWatchers.push( + await createWatchers(watchDirectories(scanner), async function handle(files) { try { // If the only change happened to the output file, then we don't want to // trigger a rebuild because that will result in an infinite loop. @@ -304,15 +304,15 @@ export async function handle(args: Result>) { // Setup new watchers DEBUG && I.start('Setup new watchers') - let newCleanupWatchers = await createWatchers(watchDirectories(scanner), handle) + let newCleanupFunction = await createWatchers(watchDirectories(scanner), handle) DEBUG && I.end('Setup new watchers') // Clear old watchers DEBUG && I.start('Cleanup old watchers') - await cleanupWatchers() + await Promise.all(cleanupWatchers.splice(0).map((cleanup) => cleanup())) DEBUG && I.end('Cleanup old watchers') - cleanupWatchers = newCleanupWatchers + cleanupWatchers.push(newCleanupFunction) // Re-compile the CSS DEBUG && I.start('Build CSS') @@ -362,14 +362,14 @@ export async function handle(args: Result>) { eprintln(err.toString()) } } - }, + }), ) // Abort the watcher if `stdin` is closed to avoid zombie processes. You can // disable this behavior with `--watch=always`. if (args['--watch'] !== 'always') { process.stdin.on('end', () => { - cleanupWatchers().then( + Promise.all(cleanupWatchers.map((fn) => fn())).then( () => process.exit(0), () => process.exit(1), )