Command
build
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
No response
Description
Symptom: After a one-shot ng build (no --watch) completes successfully, the Node process does not exit. process._getActiveHandles() shows a ChildProcess for the esbuild service
all services stopped
handles: [ 'WriteStream', 'WriteStream', 'ReadStream', 'ChildProcess' ]
requests: []
child: {
pid: 52715,
file: '/my/machine/<project>/node_modules/.pnpm/@esbuild+linux-x64@0.27.3/node_modules/@esbuild/linux-x64/bin/esbuild',
args: [
'/my/machine/<project>/node_modules/.pnpm/@esbuild+linux-x64@0.27.3/node_modules/@esbuild/linux-x64/bin/esbuild',
'--service=0.27.3',
'--ping'
]
}
The root cause lays in @angular/build/src/builders/application/build-action.js — runEsBuildBuildAction:
- For watch:false, BundlerContext.incremental is false, so the build path uses one-shot esbuild.build() and never creates an esbuild.context().
- ExecutionResult.dispose() → BundlerContext.dispose() only awaits this.#esbuildContext?.dispose(), which is undefined in this path. So nothing tears down esbuild's long-lived
service child.
- The builder never calls esbuild.stop() anywhere.
- The plugin teardown registered via build.onDispose(...) in compiler-plugin.js (javascriptTransformer.close(), cacheStore?.close(), compilation.close?.()) is fire-and-forget
(void ...) and scheduled by esbuild via setTimeout(cb, 0), so it can race with the function returning.
The issue is not apparent in regular builds since the process is exited after the build loop marks done: true but builders that decorate over the Angular builder inherit the leakage.
Minimal Reproduction
Here's how we use the internal builder programatically: https://github.com/native-federation/angular-adapter/blob/8bd8b58b7db8ae3cac5818c2d643077a8b3161ce/packages/angular/src/builders/build/builder.ts#L95
Exception or Error
Your Environment
> ng version
_ _ ____ _ ___
/ \ _ __ __ _ _ _| | __ _ _ __ / ___| | |_ _|
/ △ \ | '_ \ / _` | | | | |/ _` | '__| | | | | | |
/ ___ \| | | | (_| | |_| | | (_| | | | |___| |___ | |
/_/ \_\_| |_|\__, |\__,_|_|\__,_|_| \____|_____|___|
|___/
Angular CLI : 21.2.10
Angular : 21.2.12
Node.js : 24.11.1
Package Manager : pnpm 10.33.0
Operating System : linux x64
┌───────────────────────────────┬───────────────────┬───────────────────┐
│ Package │ Installed Version │ Requested Version │
├───────────────────────────────┼───────────────────┼───────────────────┤
│ @angular-devkit/build-angular │ 21.2.10 │ ^21.2.10 │
│ @angular/build │ 21.2.10 │ ^21.2.10 │
│ @angular/cli │ 21.2.10 │ ^21.2.10 │
│ @angular/common │ 21.2.12 │ ^21.2.0 │
│ @angular/compiler │ 21.2.12 │ ^21.2.0 │
│ @angular/compiler-cli │ 21.2.12 │ ^21.2.0 │
│ @angular/core │ 21.2.12 │ ^21.2.0 │
│ @angular/forms │ 21.2.12 │ ^21.2.0 │
│ @angular/platform-browser │ 21.2.12 │ ^21.2.0 │
│ @angular/router │ 21.2.12 │ ^21.2.0 │
│ rxjs │ 7.8.2 │ ~7.8.0 │
│ typescript │ 5.9.3 │ ~5.9.2 │
│ vitest │ 4.1.5 │ ^4.0.8 │
└───────────────────────────────┴───────────────────┴───────────────────┘
Anything else relevant?
This is only happening when the buildAction is called programatically
Command
build
Is this a regression?
The previous version in which this bug was not present was
No response
Description
Symptom: After a one-shot ng build (no --watch) completes successfully, the Node process does not exit. process._getActiveHandles() shows a ChildProcess for the esbuild service
all services stopped handles: [ 'WriteStream', 'WriteStream', 'ReadStream', 'ChildProcess' ] requests: [] child: { pid: 52715, file: '/my/machine/<project>/node_modules/.pnpm/@esbuild+linux-x64@0.27.3/node_modules/@esbuild/linux-x64/bin/esbuild', args: [ '/my/machine/<project>/node_modules/.pnpm/@esbuild+linux-x64@0.27.3/node_modules/@esbuild/linux-x64/bin/esbuild', '--service=0.27.3', '--ping' ] }The root cause lays in @angular/build/src/builders/application/build-action.js — runEsBuildBuildAction:
service child.
(void ...) and scheduled by esbuild via setTimeout(cb, 0), so it can race with the function returning.
The issue is not apparent in regular builds since the process is exited after the build loop marks done: true but builders that decorate over the Angular builder inherit the leakage.
Minimal Reproduction
Here's how we use the internal builder programatically: https://github.com/native-federation/angular-adapter/blob/8bd8b58b7db8ae3cac5818c2d643077a8b3161ce/packages/angular/src/builders/build/builder.ts#L95
Exception or Error
Your Environment
> ng version _ _ ____ _ ___ / \ _ __ __ _ _ _| | __ _ _ __ / ___| | |_ _| / △ \ | '_ \ / _` | | | | |/ _` | '__| | | | | | | / ___ \| | | | (_| | |_| | | (_| | | | |___| |___ | | /_/ \_\_| |_|\__, |\__,_|_|\__,_|_| \____|_____|___| |___/ Angular CLI : 21.2.10 Angular : 21.2.12 Node.js : 24.11.1 Package Manager : pnpm 10.33.0 Operating System : linux x64 ┌───────────────────────────────┬───────────────────┬───────────────────┐ │ Package │ Installed Version │ Requested Version │ ├───────────────────────────────┼───────────────────┼───────────────────┤ │ @angular-devkit/build-angular │ 21.2.10 │ ^21.2.10 │ │ @angular/build │ 21.2.10 │ ^21.2.10 │ │ @angular/cli │ 21.2.10 │ ^21.2.10 │ │ @angular/common │ 21.2.12 │ ^21.2.0 │ │ @angular/compiler │ 21.2.12 │ ^21.2.0 │ │ @angular/compiler-cli │ 21.2.12 │ ^21.2.0 │ │ @angular/core │ 21.2.12 │ ^21.2.0 │ │ @angular/forms │ 21.2.12 │ ^21.2.0 │ │ @angular/platform-browser │ 21.2.12 │ ^21.2.0 │ │ @angular/router │ 21.2.12 │ ^21.2.0 │ │ rxjs │ 7.8.2 │ ~7.8.0 │ │ typescript │ 5.9.3 │ ~5.9.2 │ │ vitest │ 4.1.5 │ ^4.0.8 │ └───────────────────────────────┴───────────────────┴───────────────────┘Anything else relevant?
This is only happening when the buildAction is called programatically