Hacktoberfest 2026:維護者為十月標記出來的 issue,仍然開放、適合新手。 瀏覽 Hacktoberfest issue

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)

未關閉
#34,162 1 則留言 1 個 reaction 已指派 0 人 在 GitHub 檢視

還沒有人認領這個 Issue。

評估

難度
4/5
預估耗時
3-5 天
新手友好度
58/100
Issue 類型
缺陷
描述清晰度
基本清楚
活躍度
活躍
技術堆疊
angular, typescript

研究方向

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.

由索引模型根據 Issue 內容生成。

描述

area: @angular/build gemini-triaged severity5: regression
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:

  1. createWatcher() uses chokidar instead of @parcel/watcher whenever followSymlinks (= preserveSymlinks) is true.
  2. createChokidarWatcher() calls chokidar.watch(rootDir, …) on the entire workspace root (cwd: workspaceRoot), regardless of NG_BUILD_WATCH_ROOT.
  3. 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).
  4. It then does await once(watcher, 'ready') (added in #34122), i.e. it blocks until that full initial scan has completed — with followSymlinks: true on 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 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.
Minimal Reproduction

Verified by me (human): https://github.com/reifi/angular-preserve-symlinks-watch-repro

Reproducible with a freshly generated project:

  1. npx @angular/[email protected] new repro --defaults --test-runner=vitest
  2. In angular.json, add "preserveSymlinks": true to projects.repro.architect.build.options.
  3. Run ng test (watch mode; ng test --watch in a non-TTY shell).
  4. 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.

主要語言
TypeScript
星號
27k
分支
11.8k
平均合併
17 小時 47 分鐘
30 天內合併 PR
181

貢獻指南

開啟貢獻指南

從這裡開始

  1. 先讀完整個 Issue,再讀專案的貢獻指南。
  2. 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
  3. Fork 儲存庫,在一個分支上完成修改。
  4. 送出 Pull Request,並在描述裡引用這個 Issue 編號。

angular/angular-cli 的其他 Issue

查看 angular/angular-cli 的全部 Issue

相似的 Issue

更多 TypeScript Issue

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。