Skip to content

fix(builder): watch the files the federation build actually tracked - #96

Open
arifsisman wants to merge 1 commit into
native-federation:mainfrom
arifsisman:fix/watch-federation-tracked-sources
Open

fix(builder): watch the files the federation build actually tracked#96
arifsisman wants to merge 1 commit into
native-federation:mainfrom
arifsisman:fix/watch-federation-tracked-sources

Conversation

@arifsisman

Copy link
Copy Markdown

Fixes #94.

Problem

While the dev server runs, edits to shared-mapping libraries and exposed sources never reach the emitted federation bundles. The dev server keeps serving stale code until it is restarted; a hard browser reload does not help.

Root cause

syncNfFileWatcher decides what to watch from the bundler cache:

const files = [...bundlerCache.keys()].filter((k) => !k.includes('node_modules'));

bundlerCache is Angular's SourceFileCache. That class extends Map, but it does not keep tracked files in the outer Map — it keeps them in two separate properties:

class SourceFileCache extends Map {
  typeScriptFileCache = new Map();  // .ts paths
  referencedFiles;                   // templates/styles the compiler tracked

SourceFileCache.invalidate() itself consults referencedFiles via extraWatchFiles. So keys() reads the one container that stays empty.

Instrumented on a running dev server (Angular 22.0.8, Nx workspace, host + 3 remotes):

outerMap.size = 0    typeScriptFileCache.size = 197    referencedFiles.length = 3119

197 .ts files and 3119 referenced files (275 of them workspace sources) never enter the watcher. Nothing lands in the dirty buffer, SourceFileCache is never invalidated, and the rebuild reuses stale TS output.

There is a second gap on the same path: the rebuild loop is only woken for npm-linked dirs (if (isUnderLinkedDir(p)) notifyChange()). Shared mappings and exposes are externals for the app build, so Angular's own rebuild iterator never emits for them — the "ride the next Angular-driven rebuild" fallback never arrives.

Fix

  1. Feed syncNfFileWatcher a key view over typeScriptFileCache + referencedFiles. The outer keys() is still included, so cache implementations that do populate it keep working.
  2. Wake the rebuild loop for those tracked sources as well, not only for linked dirs.

Applied to both build/builder.ts and remote/builder.ts.

Verification

Measured on a real Nx + Angular 22.0.8 workspace (host + 3 remotes) by writing a marker into a source file while the dev server is running, then checking whether it reaches the emitted bundle:

case before after
shared-mapping .ts edit stale — bundle unchanged, marker absent marker present
exposed screen .html edit stale — rebuild runs, chunk never contains the marker marker present in the exposed chunk

The .html case is the variant described in the issue comment (triggered through exposes rather than sharedMappings). Both go through the same mapping-or-exposed context, so a single fix closes both.

Verification was also repeated with the built artifact dropped into the consuming workspace's node_modules, not only against source.

npm run typecheck, npm run lint (0 errors; warning count identical to the unmodified baseline) and vitest run (14 files / 100 tests) all pass.

Note on tests

The changed code lives inside the builder generators and is not unit-testable as-is without extracting a helper module. Happy to pull federationSourceFiles into its own file with a spec if you would prefer that shape.

syncNfFileWatcher derived its watch list from `bundlerCache.keys()`. That
cache is Angular's SourceFileCache, which extends Map but keeps tracked
files in `typeScriptFileCache` (.ts) and `referencedFiles` (templates and
styles) rather than in the outer Map. Instrumented on a running dev server:
outerMap.size 0, typeScriptFileCache.size 197, referencedFiles.length 3119.

Reading only `keys()` therefore watched nothing, so shared-mapping and
exposed sources never invalidated the cache and the dev server kept serving
stale bundles until restart.

Read the two properties that actually hold the tracked files, and wake the
rebuild loop for them too — they are externals for the app build, so
Angular's own rebuild iterator never emits for them.

Fixes native-federation#94.
@arifsisman
arifsisman force-pushed the fix/watch-federation-tracked-sources branch from d59d16a to c3cde70 Compare July 28, 2026 22:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[native-federation] Dev server serves stale shared-mapping bundles until restart (workspace lib edits never trigger federation rebuild)

1 participant