Skip to content

Fix non-root dependency tracking in build watch mode - #64973

Open
John Favret (johnfav03) wants to merge 1 commit into
microsoft:mainfrom
johnfav03:fix/64424
Open

John Favret (johnfav03) wants to merge 1 commit into
microsoft:mainfrom
johnfav03:fix/64424

Conversation

@johnfav03

Copy link
Copy Markdown
Contributor

Fixes #64424

Build watch mode relied on configured roots and incremental build-info file tables to identify affected projects. Non-incremental builds lack that same file table, so changes to non-root imported files could be ignored even when a filesystem notification arrived.

Example: If we have "files": ["index.ts"] and index.ts imports ./other.js, editing other.ts should invalidate the project and cause a rebuild even when incremental and composite are disabled.

Copilot AI balanced review requested due to automatic review settings October 26, 2026 20:23
@github-project-automation github-project-automation Bot moved this to Not started in PR Backlog Oct 26, 2026
@typescript-automation typescript-automation Bot added Author: Team For Uncommitted Bug PR for untriaged, rejected, closed or missing bug labels Oct 26, 2026

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 changes require final human review because they are too complex or risky for automated approval.

No open issues 🎉

What changed in this PR

Fixes #64424 by tracking non-root dependencies independently of incremental file tables, so build watch mode can rebuild non-incremental projects when imported files change.

Changes:

  • Capture dependencies, resolution lookups, and symlink identities; persist dependency inventories in build info.
  • Use those inventories for event classification, watch registration, and freshness checks, with shared source-cache invalidation.
  • Add regression tests and update affected build-info baselines.

Validation commands were not run in this review environment.

File Description
tsc/​testdata/​baselines/​reference/​tsc/​declarationEmit/​reports-dts-generation-errors.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuildWatch/​programUpdates/​works-when-noUnusedParameters-changes-to-false.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuildWatch/​programUpdates/​works-correctly-when-project-with-extended-config-is-removed.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuildWatch/​programUpdates/​tsbuildinfo-has-error.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuildWatch/​noEmitOnError/​noEmitOnError.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuildWatch/​noEmitOnError/​noEmitOnError-with-declaration.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuildWatch/​noEmit/​syntax-errors.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuildWatch/​noEmit/​semantic-errors.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuildWatch/​noEmit/​dts-errors.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuildWatch/​noEmit/​dts-errors-without-dts-enabled.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuildWatch/​noEmit/​does-not-go-in-loop-when-watching-when-no-files-are-emitted.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuildWatch/​noEmit/​does-not-go-in-loop-when-watching-when-no-files-are-emitted-with-incremental.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuildWatch/​moduleResolution/​build-mode-watches-package-json-lookups-from-existing-buildinfo.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuildWatch/​moduleResolution/​build-mode-watches-missing-package-json-lookups.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuildWatch/​extends/​configDir-template.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​transitiveReferences/​builds-correctly.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​solution/​does-not-have-empty-files-diagnostic-when-files-is-empty-and-references-are-provided.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​sample/​tsbuildinfo-has-error.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​sample/​builds-correctly-when-project-is-not-composite-or-doesnt-have-any-references.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​roots/​when-two-root-files-are-consecutive.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​resolveJsonModule/​without-outDir.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​resolveJsonModule/​without-outDir-non-composite.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​resolveJsonModule/​sourcemap.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​resolveJsonModule/​sourcemap-non-composite.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​resolveJsonModule/​include-only.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​resolveJsonModule/​include-only-without-outDir.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​resolveJsonModule/​include-only-without-outDir-non-composite.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​resolveJsonModule/​include-only-with-json-without-rootDir-but-outside-configDirectory.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​resolveJsonModule/​include-only-with-json-without-rootDir-but-outside-configDirectory-non-composite.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​resolveJsonModule/​include-only-with-json-not-in-rootDir.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​resolveJsonModule/​include-only-with-json-not-in-rootDir-non-composite.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​resolveJsonModule/​include-only-non-composite.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​resolveJsonModule/​include-of-json-along-with-other-include.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​resolveJsonModule/​include-of-json-along-with-other-include-non-composite.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​resolveJsonModule/​include-of-json-along-with-other-include-and-file-name-matches-ts-file.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​resolveJsonModule/​include-of-json-along-with-other-include-and-file-name-matches-ts-file-non-composite.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​resolveJsonModule/​include-and-files.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​resolveJsonModule/​include-and-files-non-composite.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​resolveJsonModule/​importing-json-module-from-project-reference.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​resolveJsonModule/​files-containing-json-file.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​resolveJsonModule/​files-containing-json-file-non-composite.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​projectReferenceWithRootDirInParent/​reports-no-error-when-tsbuildinfo-differ.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​projectReferenceWithRootDirInParent/​reports-error-for-same-tsbuildinfo-file.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​projectReferenceWithRootDirInParent/​reports-error-for-same-tsbuildinfo-file-without-incremental.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​projectReferenceWithRootDirInParent/​reports-error-for-same-tsbuildinfo-file-without-incremental-with-tsc.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​projectReferenceWithRootDirInParent/​reports-error-for-same-tsbuildinfo-file-because-no-rootDir-in-the-base.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​programUpdates/​tsbuildinfo-has-fewer-fileInfos-than-fileNames.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​outputPaths/​when-rootDir-is-specified.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​outputPaths/​when-rootDir-is-specified-but-not-all-files-belong-to-rootDir.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​outputPaths/​when-rootDir-is-specified-but-not-all-files-belong-to-rootDir-and-is-composite.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​outputPaths/​when-rootDir-is-not-specified.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​outputPaths/​when-rootDir-is-not-specified-and-is-composite.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​noEmitOnError/​syntax-errors.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​noEmitOnError/​syntax-errors-with-declaration.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​noEmitOnError/​semantic-errors.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​noEmitOnError/​semantic-errors-with-declaration.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​noEmitOnError/​dts-errors.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​noEmitOnError/​dts-errors-with-declaration.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​noEmit/​syntax-errors.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​noEmit/​semantic-errors.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​noEmit/​dts-errors.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​noEmit/​dts-errors-without-dts-enabled.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​noEmit/​dts-errors-with-declaration-enable-changes.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​moduleResolution/​when-resolution-is-not-shared.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​moduleResolution/​shared-resolution-should-not-report-error.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​moduleResolution/​resolves-specifier-in-output-declaration-file-from-referenced-project-correctly.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​moduleResolution/​resolves-specifier-in-output-declaration-file-from-referenced-project-correctly-with-preserveSymlinks.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​moduleResolution/​resolution-from-d.ts-of-referenced-project.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​moduleResolution/​impliedNodeFormat-differs-between-projects-for-shared-file.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​fileDelete/​deleted-file-without-composite.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​extends/​resolves-the-symlink-path.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​extends/​configDir-template.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​declarationEmit/​when-ts-file-is-referenced-through-triple-slash-from-another-project.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​declarationEmit/​when-declaration-file-is-referenced-through-triple-slash-but-uses-no-references.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​declarationEmit/​reports-dts-generation-errors.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​declarationEmit/​reports-dts-generation-errors-with-incremental.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​contentMapperOptionDiagnostics/​rebuild-to-report-mapper-option-diagnostics.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​contentMapperIdentity/​content-mapper-identity-change-forces-rebuild.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​configFileErrors/​when-tsconfig-extends-the-missing-file.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​commandLine/​included-tsconfig-json-can-be-imported-as-json-input.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​commandLine/​emitDeclarationOnly-on-commandline-with-declaration.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​commandLine/​emitDeclarationOnly-false-on-commandline-with-declaration.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​tsbuild/​clean/​tsx-with-dts-emit.js Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​fourslash/​state/​findAllRefsSolutionWithDisableReferencedProjectLoadReferencingDefaultProjectDirectly.baseline Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​fourslash/​state/​findAllRefsSolutionReferencingDefaultProjectDirectly.baseline Updated as part of this pull request.
tsc/​testdata/​baselines/​reference/​fourslash/​state/​findAllRefsProjectWithOwnFilesReferencingFileFromReferencedProject.baseline Updated as part of this pull request.
tsc/​internal/​execute/​tsctests/​readablebuildinfo.go Updated as part of this pull request.
tsc/​internal/​execute/​incremental/​snapshottobuildinfo.go Updated as part of this pull request.
tsc/​internal/​execute/​incremental/​buildInfo.go Updated as part of this pull request.
tsc/​internal/​execute/​incremental/​buildinfo_path_test.go Updated as part of this pull request.
tsc/​internal/​execute/​build/​watchDependencies_test.go Updated as part of this pull request.
tsc/​internal/​execute/​build/​host.go Updated as part of this pull request.
tsc/​internal/​execute/​build/​compilerHost.go Updated as part of this pull request.

Review effort: Balanced

@jakebailey

Copy link
Copy Markdown
Member

I had copilot review this and it found this test case with bad behavior:

func TestBuildWatchDependencyDirectoryReplacement(t *testing.T) {
	t.Parallel()
	for _, incremental := range []bool{false, true} {
		t.Run(fmt.Sprintf("incremental=%v", incremental), func(t *testing.T) {
			t.Parallel()
			const pkg = dependencyProject + "node_modules/widget"
			const manifest = `{"name":"widget","types":"index.d.ts"}`
			const output = dependencyProject + "out/index.d.ts"

			files := FileMap{
				dependencyProject + "tsconfig.json": fmt.Sprintf(`{
					"compilerOptions": {
						"outDir": "out",
						"declaration": true,
						"incremental": %v,
						"module": "nodenext",
						"target": "es2022",
						"types": [],
						"libReplacement": false
					},
					"include": ["**/*.ts"]
				}`, incremental),
				dependencyProject + "index.ts": `import { value } from "widget"; export const result = value;`,
				pkg + "/package.json":          manifest,
				pkg + "/index.d.ts":            `export const value: 1;`,
			}
			sys, watcher := startDependencyWatch(
				t, files,
				[]string{"--build", "--watch", "--verbose", "--pretty", "false"},
				false, "",
			)
			checkDependencyOutput(t, sys, output, "result: 1;")

			sys.removeNoError(pkg + "/index.d.ts")
			sys.removeNoError(pkg + "/package.json")
			sys.removeNoError(pkg)
			sys.writeFileNoError(pkg+"/package.json", manifest)
			sys.writeFileNoError(pkg+"/index.d.ts", `export const value: 2;`)

			sys.mockWatchBackend.SendEvents([]fswatch.Event{
				{Kind: fswatch.EventUpdate, Path: pkg},
			})
			watcher.DoCycle()

			checkDependencyOutput(t, sys, output, "result: 2;")
			checkDependencySuccess(t, sys)
		})
	}
}

Both incremental variants leave the output at result: 1;. Removing the task.watchDependencies != nil early return in orchestrator.go makes both pass. Directory delete/recreate events can coalesce into an update without individual child-file notifications.

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.

tsc -b --watch doesn't rebuild when an imported file changes, unless incremental is on

3 participants