G
YouTube TikTok Games
Skip to content

Prevent emitted files from retriggering native watch builds - #65475

Open
Jake Bailey (jakebailey) wants to merge 1 commit into
microsoft:mainfrom
jakebailey:compiler-fixes/wildcard-watch-filtering
Open

Jake Bailey (jakebailey) wants to merge 1 commit into
microsoft:mainfrom
jakebailey:compiler-fixes/wildcard-watch-filtering

Conversation

@jakebailey

Copy link
Copy Markdown
Member

Caught this in an audit.

Fixes #64037 (which I did not realize before making this fix)

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Watch mode can miss valid new inputs due to inconsistent extension casing and suppression of files never emitted, while regression tests do not cover same-directory output loops.

3 open issues
What changed in this PR

Updates the native compiler’s single-project watch mode to prevent emitted files from triggering repeated builds, addressing #64037.

Changes:

  • Filters file events using tracked dependencies, supported extensions, and predicted output paths.
  • Tracks dependency directories so directory deletions invalidate the build.
  • Adds tests for output filtering, new source discovery, and directory events.
File Description
tsc/​internal/​execute/​watcher.go Adds output-aware event filtering and dependency-directory tracking.
tsc/​internal/​execute/​tsctests/​watch_shallow_test.go Tests ignored file events and relevant source and directory changes.

Review effort: Balanced

Comment thread tsc/internal/execute/watcher.go Resolved
Comment thread tsc/internal/execute/watcher.go Resolved

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The append-only emittedFiles set retains stale output paths, causing watch mode to miss recreated independent declarations; entries need lifecycle-aware cleanup and regression coverage.

1 open issue
3 resolved since last review

Review effort: Balanced

Comment thread tsc/internal/execute/watcher.go Resolved

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Directory-replacement updates can retain stale source contents and resolutions, while excluded-directory and restored-output events can still trigger unnecessary watch rebuilds.

No open issues 🎉

3 previously missed issues

In code that hasn't changed since last review

High severity Force full rebuild when tracked dependency directories are replaced

tsc/​internal/​execute/​watcher.go:324

A directory replacement can be coalesced into EventUpdate, so this delete-only guard leaves program reuse enabled. If the root filenames stay unchanged and another source is edited in the same batch, the single-file fast path can retain stale contents and resolutions from the replaced directory. Invalidate cached descendants and force a full rebuild for updates to directories containing tracked dependencies; add a regression covering that mixed event batch.

Medium severity Filter excluded output-directory events from watch cycles

tsc/​internal/​execute/​watcher.go:418

The macOS repro in #64037 still passes this filter: with include: ["**/*"], exclude: ["build"], and tsBuildInfoFile: "./build/tsconfig.tsbuildinfo", the backend delivers updates for both /repro/build and the build-info file. Although the file event is now removed, the directory event survives solely because it is under the recursive watch, so DoCycle still reports a change and rebuilds after emission. Please filter excluded output-directory events too, while preserving directories containing genuine dependencies or discoverable inputs, and add a regression test delivering this pair of events.

Medium severity Track outputs restored from build info to avoid spurious rebuilds

tsc/​internal/​execute/​watcher.go:709

Outputs restored from build info are never registered here if incremental emission skips their writes. For example, prebuild a composite project that emits declarations alongside its sources, then start --watch without changing the inputs: the existing .d.ts files remain active outputs, but emittedFiles starts empty and this callback is not invoked for them. An event for one of those declarations therefore passes filterRelevantChanges as a new wildcard input and triggers an unnecessary rebuild. Initialize output tracking from confirmed restored emission state as well as successful writes, and add a prebuild/restart regression case; do not blanket-register potential outputs that were never emitted.

1 resolved since last review

Review effort: Balanced

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Human assessment is needed to evaluate a watcher edge case where a coalesced directory-to-file update can leave removed sources in the program.

No open issues 🎉

Review effort: Balanced

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The added tests inject mocked events, leaving native directory-event coalescing—especially kqueue child-directory updates—without the OS-level validation needed to rule out emitted-file rebuild loops.

No open issues 🎉

Review effort: Balanced

@jakebailey
Jake Bailey (jakebailey) force-pushed the compiler-fixes/wildcard-watch-filtering branch from 5843fae to d2d8a1f Compare November 14, 2026 03:13
Recursive wildcard roots describe directories, not arbitrary event
paths. Treating every descendant as a directory lets emitted outputs
and unrelated files retrigger compilation indefinitely.

Filter events using dependencies, supported extensions, exclusions,
and confirmed outputs. Keep output records aligned with their active
producers, including outputs restored when incremental watch restarts.

Preserve discovery of new inputs and invalidate cached dependencies
when directories are replaced, including coalesced directory-to-file
changes beneath package boundaries.
@jakebailey
Jake Bailey (jakebailey) force-pushed the compiler-fixes/wildcard-watch-filtering branch from d2d8a1f to cea79fb Compare November 14, 2026 07:13

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Author: Team For Uncommitted Bug PR for untriaged, rejected, closed or missing bug

Projects

Status: Not started

Development

Successfully merging this pull request may close these issues.

npx tsc -w is triggering itself after each build

3 participants