Command
build
Is this a regression?
The previous version in which this bug was not present was
21.2.13
Description
ng build (no --watch) finishes successfully. It prints the build summary and "Output location," then the process never exits. A lingering esbuild --service=<version> --ping child stays alive next to the still-running ng build parent, and both have to be killed by hand.
This looks like a regression from #33267 (merged in 21.2.14), which switched one-shot builds from a plain esbuild.build() call to esbuild.context() + .rebuild(), the persistent-IPC path normally reserved for watch mode. That PR fixed a real leak (#33201), but seems to have opened a scheduling/teardown race for one-shot builds instead.
This was already filed as #33480 and closed for lack of a reproducible case. I put together a minimal repro from scratch to close that gap.
Minimal Reproduction
Repo: https://github.com/hskiba/ng-build-hang-repro
git clone https://github.com/hskiba/ng-build-hang-repro
cd ng-build-hang-repro
npm install
npx ng build
The build finishes, then hangs. ps aux | grep esbuild in another terminal shows the stuck service process.
Three commits show exactly what triggers it:
initial commit: untouched ng new output, builds and exits fine
Add minimal trigger...: adds one file with two trivial @Component classes, each with nothing but an inline styles: block. It's never imported or routed anywhere, only picked up via tsconfig.app.json's include: ["src/**/*.ts"]. Adding it alone causes the hang.
Document root cause...: full writeup
What I found bisecting it: the count of components with inline styles: blocks is what matters. Two hangs it, one doesn't. CSS content is irrelevant, a bare :host { display: block; } triggers it just as reliably as anything more elaborate. Host bindings, signals, file size, and third-party dependencies are all beside the point. Pinning to 21.2.13 with the identical source file builds and exits cleanly.
Exception or Error
Your Environment
Angular CLI : 21.2.18
Angular : 21.2.17
Node.js : 24.18.0
Package Manager : npm 11.16.0
Operating System : darwin arm64
@angular/build 21.2.18
@angular/cli 21.2.18
@angular/common 21.2.17
@angular/compiler 21.2.17
@angular/compiler-cli 21.2.17
@angular/core 21.2.17
@angular/forms 21.2.17
@angular/platform-browser 21.2.17
@angular/router 21.2.17
rxjs 7.8.2
typescript 5.9.3
vitest 4.1.9
Anything else relevant?
Reproduced on macOS (arm64) and was happening in our container builds for both arm64 and amd64.
Command
build
Is this a regression?
The previous version in which this bug was not present was
21.2.13
Description
ng build(no--watch) finishes successfully. It prints the build summary and "Output location," then the process never exits. A lingeringesbuild --service=<version> --pingchild stays alive next to the still-runningng buildparent, and both have to be killed by hand.This looks like a regression from #33267 (merged in 21.2.14), which switched one-shot builds from a plain
esbuild.build()call toesbuild.context()+.rebuild(), the persistent-IPC path normally reserved for watch mode. That PR fixed a real leak (#33201), but seems to have opened a scheduling/teardown race for one-shot builds instead.This was already filed as #33480 and closed for lack of a reproducible case. I put together a minimal repro from scratch to close that gap.
Minimal Reproduction
Repo: https://github.com/hskiba/ng-build-hang-repro
git clone https://github.com/hskiba/ng-build-hang-repro cd ng-build-hang-repro npm install npx ng buildThe build finishes, then hangs.
ps aux | grep esbuildin another terminal shows the stuck service process.Three commits show exactly what triggers it:
initial commit: untouchedng newoutput, builds and exits fineAdd minimal trigger...: adds one file with two trivial@Componentclasses, each with nothing but an inlinestyles:block. It's never imported or routed anywhere, only picked up viatsconfig.app.json'sinclude: ["src/**/*.ts"]. Adding it alone causes the hang.Document root cause...: full writeupWhat I found bisecting it: the count of components with inline
styles:blocks is what matters. Two hangs it, one doesn't. CSS content is irrelevant, a bare:host { display: block; }triggers it just as reliably as anything more elaborate. Host bindings, signals, file size, and third-party dependencies are all beside the point. Pinning to21.2.13with the identical source file builds and exits cleanly.Exception or Error
Your Environment
Anything else relevant?
Reproduced on macOS (arm64) and was happening in our container builds for both arm64 and amd64.