🔎 Search Terms
tsc -b --watch, tsc --build --watch, imported file not rebuilt, incremental, tsbuildinfo
🕗 Version & Regression Information
- This is the behavior in every version I tried
I tried 6.0.3 and today's nightly (7.1.0-dev.20260924.1). In 7 it only happens without incremental or composite. In 6.0.3 it happens even with incremental.
⏯ Playground Link
No response
💻 Code
mkdir proj && cd proj
echo '{"compilerOptions":{"outDir":"out","module":"nodenext","target":"es2022"},"files":["index.ts"]}' > tsconfig.json
echo '{"type":"module"}' > package.json
echo 'import { s } from "./other.js"; export const x = s;' > index.ts
echo 'export const s = "AAA";' > other.ts
npx tsc -b --watch
# in another terminal, once the first build is done:
echo 'export const s = "BBB";' > other.ts
🙁 Actual behavior
Editing other.ts does nothing, and out/other.js still has "AAA". Editing index.ts does rebuild.
Here's what I got with the same project:
tsc -b --watch: no rebuild
tsc -b --watch with "incremental": true: rebuilds
tsc -b --watch with "composite": true: rebuilds
tsc --watch (no -b): rebuilds
Same thing if the imported file is outside include, like ../shared/s.ts.
🙂 Expected behavior
tsc -b --watch should rebuild when any file in the program changes, like it already does with incremental on, or like tsc --watch does.
Additional information about the issue
It looks like the build orchestrator only finds out about non-root files from the .tsbuildinfo, both when it checks events and when it picks directories to watch:
|
if !rootChanged { |
|
task.buildInfoEntryMu.Lock() |
|
bi := task.buildInfoEntry |
|
task.buildInfoEntryMu.Unlock() |
|
if bi != nil && bi.buildInfo != nil { |
|
buildInfoDir := tspath.GetDirectoryPath(string(bi.path)) |
|
for _, fileName := range bi.buildInfo.FileNames { |
|
fp := o.toPath(o.resolveBuildInfoFileName(fileName, buildInfoDir)) |
|
if roots.Has(fp) { |
|
continue |
|
} |
|
if _, changed := normalizedPaths[fp]; changed { |
|
task.resetStatus() |
|
needsUpdate.Store(true) |
|
break |
|
} |
|
} |
|
// Non-root dependency directories from buildinfo (e.g. node_modules .d.ts files). |
|
task.buildInfoEntryMu.Lock() |
|
bi := task.buildInfoEntry |
|
task.buildInfoEntryMu.Unlock() |
|
if bi != nil && bi.buildInfo != nil { |
|
buildInfoDir := tspath.GetDirectoryPath(string(bi.path)) |
|
roots := collections.NewSetFromItems(core.Map(task.resolved.FileNames(), o.toPath)...) |
|
for _, fileName := range bi.buildInfo.FileNames { |
|
absPath := o.host.FS().Realpath(o.resolveBuildInfoFileName(fileName, buildInfoDir)) |
|
fp := o.toPath(absPath) |
|
if roots.Has(fp) { |
|
continue |
|
} |
|
dir := tspath.GetDirectoryPath(absPath) |
|
if !desiredDirs.Covered(dir) && watchmanager.CanWatchDirectory(dir) { |
|
desiredDirs.Set(dir, false) |
|
} |
|
} |
Without incremental or composite there's no buildinfo. So the change event for other.ts does come in (its folder is watched), but nothing picks it up and it gets dropped.
6.0 had the same gap, since its tsc -b only watched parsed.fileNames. So it's not a regression, but it's a bit surprising that in 7 the answer depends on incremental.
This came up in #64366, where I was asked to open a separate issue.
(I used an AI assistant to help write this up.)
🔎 Search Terms
tsc -b --watch, tsc --build --watch, imported file not rebuilt, incremental, tsbuildinfo
🕗 Version & Regression Information
I tried 6.0.3 and today's nightly (7.1.0-dev.20260924.1). In 7 it only happens without
incrementalorcomposite. In 6.0.3 it happens even withincremental.⏯ Playground Link
No response
💻 Code
🙁 Actual behavior
Editing
other.tsdoes nothing, andout/other.jsstill has"AAA". Editingindex.tsdoes rebuild.Here's what I got with the same project:
tsc -b --watch: no rebuildtsc -b --watchwith"incremental": true: rebuildstsc -b --watchwith"composite": true: rebuildstsc --watch(no-b): rebuildsSame thing if the imported file is outside
include, like../shared/s.ts.🙂 Expected behavior
tsc -b --watchshould rebuild when any file in the program changes, like it already does withincrementalon, or liketsc --watchdoes.Additional information about the issue
It looks like the build orchestrator only finds out about non-root files from the
.tsbuildinfo, both when it checks events and when it picks directories to watch:TypeScript/tsc/internal/execute/build/orchestrator.go
Lines 430 to 446 in df1a31e
TypeScript/tsc/internal/execute/build/orchestrator.go
Lines 576 to 593 in df1a31e
Without
incrementalorcompositethere's no buildinfo. So the change event forother.tsdoes come in (its folder is watched), but nothing picks it up and it gets dropped.6.0 had the same gap, since its
tsc -bonly watchedparsed.fileNames. So it's not a regression, but it's a bit surprising that in 7 the answer depends onincremental.This came up in #64366, where I was asked to open a separate issue.
(I used an AI assistant to help write this up.)