Watch mode (`ng test`, `ng serve`) stalls after "Watch mode enabled" when `preserveSymlinks: true` — chokidar scans entire workspace incl. `node_modules` (regression in 22.2.0)
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Aptitud para principiantes
- 58/100
- Tipo de issue
- Error
- Claridad
- Bastante claro
- Estado de actividad
- Activo
- Stack tecnológico
- angular, typescript
- Área
- build-system, cli, testing-qa
Línea de trabajo
Start in src/builders/application/build-action.js and src/utils/watcher.js, tracing setupWatcher(), createWatcher(), and createChokidarWatcher() for preserveSymlinks: true. Use the linked reproduction or the listed npx and ng test commands on Windows, then verify that ng test, ng serve, and ng build --watch no longer wait on an unnecessarily broad initial scan before the first result.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Command
- test
- serve
Is this a regression?
- 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:
Application bundle generation complete. [52.899 seconds]
Watch mode enabled. Watching for file changes...
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/watcherwheneverfollowSymlinks(=preserveSymlinks) is true.createChokidarWatcher()callschokidar.watch(rootDir, …)on the entire workspace root (cwd: workspaceRoot), regardless ofNG_BUILD_WATCH_ROOT.- The
**/node_modules/**ignore pattern is only added whenshouldWatchRoot && !preserveSymlinks, so withpreserveSymlinks: truechokidar also walks all ofnode_modules(≈106 000 files in our workspace). - It then does
await once(watcher, 'ready')(added in #34122), i.e. it blocks until that full initial scan has completed — withfollowSymlinks: trueon Windows.
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 withNG_BUILD_WATCH_ROOT), as in 22.1.8, for the chokidar path; or - ignore
node_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; or - don't block the first build result on chokidar's
readywhen 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/[email protected] new repro --defaults --test-runner=vitest- In
angular.json, add"preserveSymlinks": truetoprojects.repro.architect.build.options. - Run
ng test(watch mode;ng test --watchin 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...
Your Environment
_ _ ____ _ ___
/ \ _ __ __ _ _ _| | __ _ _ __ / ___| | |_ _|
/ △ \ | '_ \ / _` | | | | |/ _` | '__| | | | | | |
/ ___ \| | | | (_| | |_| | | (_| | | | |___| |___ | |
/_/ \_\_| |_|\__, |\__,_|_|\__,_|_| \____|_____|___|
|___/
Angular CLI : 22.2.0
Angular : 22.2.0
Node.js : 26.8.2
Package Manager : npm 11.19.1
Operating System : win32 x64
┌─────────────────────────────────┬───────────────────┬───────────────────┐
│ Package │ Installed Version │ Requested Version │
├─────────────────────────────────┼───────────────────┼───────────────────┤
│ @angular/build │ 22.2.0 │ ^22.2.0 │
│ @angular/cdk │ 22.2.0 │ ^22.2.0 │
│ @angular/cli │ 22.2.0 │ ^22.2.0 │
│ @angular/common │ 22.2.0 │ ^22.2.0 │
│ @angular/compiler │ 22.2.0 │ ^22.2.0 │
│ @angular/compiler-cli │ 22.2.0 │ ^22.2.0 │
│ @angular/core │ 22.2.0 │ ^22.2.0 │
│ @angular/forms │ 22.2.0 │ ^22.2.0 │
│ @angular/google-maps │ 22.2.0 │ ^22.2.0 │
│ @angular/localize │ 22.2.0 │ ^22.2.0 │
│ @angular/material │ 22.2.0 │ ^22.2.0 │
│ @angular/material-luxon-adapter │ 22.2.0 │ ^22.2.0 │
│ @angular/platform-browser │ 22.2.0 │ ^22.2.0 │
│ @angular/router │ 22.2.0 │ ^22.2.0 │
│ @angular/upgrade │ 22.2.0 │ ^22.2.0 │
│ rxjs │ 7.8.2 │ ^7.8.2 │
│ typescript │ 6.0.3 │ ^6.0.3 │
│ vitest │ 5.0.1 │ ^5.0.1 │
│ zone.js │ 0.16.3 │ ^0.16.3 │
└─────────────────────────────────┴───────────────────┴───────────────────┘
Anything else relevant?
Workaround: override "preserveSymlinks": false in the build configuration referenced by the unit-test buildTarget, e.g.
"configurations": {
"test": {
"preserveSymlinks": false,
…
}
}
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.
- Lenguaje dominante
- TypeScript
- Estrellas
- 27k
- Forks
- 11.8k
- Merge medio
- 17 h 47 min
- PR fusionados (30 d)
- 181
Guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de angular/angular-cli
-
Can't use an array of hostnames in --allowedHosts cli parameter in @angular/build:dev-server Abiertoarea: @angular/build gemini-triaged
Dificultad 2/5 1-3 horas Aptitud para principiantes 74/100
angular/angular-cli#33955 ·
-
area: @angular/cli gemini-triaged
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
angular/angular-cli#33055 · 1 comentario · 3 reacciones ·
-
area: @angular/build gemini-triaged
Dificultad 3/5 1-2 días Aptitud para principiantes 68/100
angular/angular-cli#34166 · 1 comentario ·
-
Angular CLI can copy files from outside the workspace root through symlinked asset directories Abiertoarea: @angular/build gemini-triaged
Dificultad 4/5 3-5 días Aptitud para principiantes 52/100
angular/angular-cli#34164 ·
-
area: @angular/build gemini-triaged severity5: regression
Dificultad 4/5 3-5 días Aptitud para principiantes 75/100
angular/angular-cli#34163 ·
Todos los issues de angular/angular-cli
Issues similares
-
Dificultad 1/5 1-3 horas Aptitud para principiantes 88/100
motiondivision/motion#3849 ·
-
Add: S Play Event HD Abiertocheck:passed streams:add
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
-
Improvement for contact popover Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
-
LiteLLM proxy response_cost (x-litellm-response-cost) is never applied to ChatModelOutput.cost Abiertobug
Dificultad 2/5 1-3 horas Aptitud para principiantes 84/100
i-am-bee/beeai-framework#1697 · 1 reacción ·
-
Support bun dedupe Abiertoenhancement
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
antfu/node-modules-inspector#214 ·