You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Yes, this behavior used to work in the previous version
The previous version in which this bug was not present was
22.1.8
Description
(AI generated)
After updating @angular/build / @angular/cli from 22.1.8 to 22.2.0, ng test in watch mode (@angular/build:unit-test, Vitest runner) no longer starts running tests after the initial build when the build target has "preserveSymlinks": true. The output stops at:
With NG_TEST_LOG=1, VitestExecutor never logs Executing test run — the first build result is not handed to the executor. We stopped the process after more than 4 minutes of waiting. ng test --watch=false is unaffected (the full suite finishes in ~3 min including the build).
Setting "preserveSymlinks": false in the test build configuration makes Vitest start ~2 s after the build completes. Downgrading Vitest (5.0.1 → 4.1.11) makes no difference, so it is not Vitest-related.
Cause (from reading @angular/build 22.2.0 sources):
In src/builders/application/build-action.js, watch mode now calls setupWatcher() from src/utils/watcher.js before emitting the first build result:
createWatcher() uses chokidar instead of @parcel/watcher whenever followSymlinks (= preserveSymlinks) is true.
createChokidarWatcher() calls chokidar.watch(rootDir, …) on the entire workspace root (cwd: workspaceRoot), regardless of NG_BUILD_WATCH_ROOT.
The **/node_modules/** ignore pattern is only added when shouldWatchRoot && !preserveSymlinks, so with preserveSymlinks: true chokidar also walks all of node_modules (≈106 000 files in our workspace).
In 22.1.8, build-action.js used tools/esbuild/watcher.js and only watched the files/directories from result.watchFiles (plus the project root only if NG_BUILD_WATCH_ROOT was set), with no wait for an initial scan, so startup was instant.
preserveSymlinks: true is a common setting for workspaces that npm link local libraries, so this effectively makes watch mode unusable for them.
Since ng serve and ng build --watch go through the same runEsBuildBuildAction / setupWatcher path, they are affected as well, see comment below.
Possible fixes:
Keep watching only watchFiles (and the root only with NG_BUILD_WATCH_ROOT), as in 22.1.8, for the chokidar path; or
ignore node_modules under the workspace root in the chokidar path as well — explicitly added watch files outside the root (e.g. npm link targets) would still be watched; or
don't block the first build result on chokidar's ready when the initial scan is large.
npx @angular/cli@22.2.0 new repro --defaults --test-runner=vitest
In angular.json, add "preserveSymlinks": true to projects.repro.architect.build.options.
Run ng test (watch mode; ng test --watch in a non-TTY shell).
Observe: output stops after "Watch mode enabled. Watching for file changes..." for about 2 minutes before Vitest starts.
Measured on Windows 11, fresh project (≈18 000 files in node_modules), time from "Watch mode enabled" to the Vitest test summary:
preserveSymlinks
Time to test summary
Vitest run duration
not set (default)
6 s
5.3 s
true
123 s
7.0 s
The delay scales with the number of files under the workspace root. In a large application workspace (≈106 000 files in node_modules) tests had still not started after more than 4 minutes, when we stopped the process. ng test --watch=false is not affected.
Exception or Error
No error — the process hangs silently after:
Watch mode enabled. Watching for file changes...
The unit-test builder reads preserveSymlinks from the build target options (unit-test/options.js), so this only affects tests; ng serve / ng build keep preserveSymlinks: true for npm link.
Command
Is this a regression?
The previous version in which this bug was not present was
22.1.8
Description
(AI generated)
After updating
@angular/build/@angular/clifrom 22.1.8 to 22.2.0,ng testin watch mode (@angular/build:unit-test, Vitest runner) no longer starts running tests after the initial build when the build target has"preserveSymlinks": true. The output stops at:With
NG_TEST_LOG=1,VitestExecutornever logsExecuting test run— the first build result is not handed to the executor. We stopped the process after more than 4 minutes of waiting.ng test --watch=falseis unaffected (the full suite finishes in ~3 min including the build).Setting
"preserveSymlinks": falsein the test build configuration makes Vitest start ~2 s after the build completes. Downgrading Vitest (5.0.1 → 4.1.11) makes no difference, so it is not Vitest-related.Cause (from reading
@angular/build22.2.0 sources):In
src/builders/application/build-action.js, watch mode now callssetupWatcher()fromsrc/utils/watcher.jsbefore emitting the first build result:createWatcher()uses chokidar instead of@parcel/watcherwheneverfollowSymlinks(=preserveSymlinks) is true.createChokidarWatcher()callschokidar.watch(rootDir, …)on the entire workspace root (cwd: workspaceRoot), regardless ofNG_BUILD_WATCH_ROOT.**/node_modules/**ignore pattern is only added whenshouldWatchRoot && !preserveSymlinks, so withpreserveSymlinks: truechokidar also walks all ofnode_modules(≈106 000 files in our workspace).await once(watcher, 'ready')(added in fix(@angular/build): ensure chokidar watcher is ready before returning #34122), i.e. it blocks until that full initial scan has completed — withfollowSymlinks: trueon Windows.In 22.1.8,
build-action.jsusedtools/esbuild/watcher.jsand only watched the files/directories fromresult.watchFiles(plus the project root only ifNG_BUILD_WATCH_ROOTwas set), with no wait for an initial scan, so startup was instant.preserveSymlinks: trueis a common setting for workspaces thatnpm linklocal libraries, so this effectively makes watch mode unusable for them.Since
ng serveandng build --watchgo through the samerunEsBuildBuildAction/setupWatcherpath, they are affected as well, see comment below.Possible fixes:
watchFiles(and the root only withNG_BUILD_WATCH_ROOT), as in 22.1.8, for the chokidar path; ornode_modulesunder the workspace root in the chokidar path as well — explicitly added watch files outside the root (e.g.npm linktargets) would still be watched; orreadywhen the initial scan is large.Minimal Reproduction
Verified by me (human): https://github.com/reifi/angular-preserve-symlinks-watch-repro
Reproducible with a freshly generated project:
npx @angular/cli@22.2.0 new repro --defaults --test-runner=vitestangular.json, add"preserveSymlinks": truetoprojects.repro.architect.build.options.ng test(watch mode;ng test --watchin a non-TTY shell).Measured on Windows 11, fresh project (≈18 000 files in
node_modules), time from "Watch mode enabled" to the Vitest test summary:preserveSymlinkstrueThe delay scales with the number of files under the workspace root. In a large application workspace (≈106 000 files in
node_modules) tests had still not started after more than 4 minutes, when we stopped the process.ng test --watch=falseis not affected.Exception or Error
Your Environment
Anything else relevant?
Workaround: override
"preserveSymlinks": falsein the build configuration referenced by the unit-testbuildTarget, e.g.The unit-test builder reads
preserveSymlinksfrom the build target options (unit-test/options.js), so this only affects tests;ng serve/ng buildkeeppreserveSymlinks: truefornpm link.