perf(builder): watch bounded source-tree roots instead of one watcher per file - #115
Conversation
… per file Follow-up to native-federation#96. The widened watch list registered one fs watcher per tracked federation source — ~1,900 watchers on a real Nx workspace. Per-file watchers do not scale: macOS FSEvents replays and throttles under that many streams, and every platform pays a file descriptor per watcher. federationWatchPaths() collapses the tracked files into the few top-level workspace source trees that contain them (libs, apps, ...) and both builders watch those roots recursively instead. Because a directory watch surfaces every event under the root, relevance is now filtered where events arrive: only tracked federation sources, project-root files and linked-dir edits pass, and only when their mtime actually advanced (the native-federation#96 stale-event filter). Irrelevant events no longer reach the dirty buffer at all. Files outside the workspace, at the workspace root, or under dot dirs, node_modules and build outputs stay as single-file watches; nested candidates deduplicate to their parent tree. Covered by five new unit tests; validated on the same Nx + Angular 22 workspace as native-federation#96 (files=~1900 collapses to roots=2).
|
Note on the red Two advisories ( #116 fixes it via the existing |
|
Might be superseded by #112 |
|
I'd love to hear your feedback on how it performs: https://github.com/native-federation/angular-adapter/releases/tag/v22.1.0-RC1 |
|
Measured RC1 against this PR on the workspace this PR was written for. Short version: you're right, #112 supersedes it — the per-file watcher problem is solved in core, and I'm happy to close this. SetupNx + Angular 22 workspace, one host shell and three remotes, all four dev servers running concurrently (macOS). Two installs compared:
Counts come from instrumenting Watcher handles
* not measured, it is the per-file count each server would register on plain 22.0.6. The first group on RC1 (13–20 per server) is Behaviour on RC1
Conclusion1113 → 299 is the number that mattered, and core 4.4.0 delivers it without the adapter needing a relevance filter or a stale-event filter — both of which this PR carries and #112 correctly deletes. What this PR would add on top is 299 → 12, and on this machine that is noise: Rebasing it would mean re-applying only One install note, unrelated to the watcher work: RC1 declares |
Follow-up to #96.
Problem
The widened watch list from #96 registers one fs watcher per tracked federation source — ~1,900 watchers on the same real Nx workspace the original fix was measured on. Per-file watchers don't scale:
syncNfFileWatcherpass re-diffs the full file list.Change
federationWatchPaths(files, workspaceRoot)collapses the tracked files into the few top-level workspace source trees that contain them (libs,apps, ...), and both builders watch those roots recursively instead. On the measured workspace:files=~1900collapses toroots=2(logged at verbose level).Because a directory watch surfaces every event under its root, relevance moves to where events arrive:
createDebouncedChangeWatcher, so irrelevant events never enterpendingPaths.Safety rails: files outside the workspace, at the workspace root itself, or under dot dirs /
node_modules/ build outputs stay as single-file watches; nested candidates deduplicate to their parent tree.Verification
federationWatchPaths(collapse, out-of-workspace, excluded top-levels, root-level file, parent/child dedup);typecheck,lint(0 errors, warning count unchanged) andvitest(16 files / 116 tests) pass.