Skip to content

Commit 4bdf9e1

Browse files
committed
fix(@angular/build): added JavaScriptTransformer close to dispose method
This change allows for awaiting the disposed plugin and added the missing close method of the JavaScript transformer to the onDispose. When the plugin is run multiple times on different projects/bundles without proper closing it will result in a node heap corruption. This allows us to cleanup the build before we start a new one. Closes #31973
1 parent bf990dc commit 4bdf9e1

File tree

3 files changed

+32
-5
lines changed

3 files changed

+32
-5
lines changed

packages/angular/build/src/private.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ export function createCompilerPlugin(
5959
),
6060
);
6161
}
62+
export { getSharedCompilationStateCleanup } from './tools/esbuild/angular/compilation-state';
6263

6364
export type { AngularCompilation } from './tools/angular/compilation';
6465
export { DiagnosticModes } from './tools/angular/compilation';

packages/angular/build/src/tools/esbuild/angular/compilation-state.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export class SharedTSCompilationState {
1010
#pendingCompilation = true;
1111
#resolveCompilationReady: ((value: boolean) => void) | undefined;
1212
#compilationReadyPromise: Promise<boolean> | undefined;
13+
1314
#hasErrors = true;
1415

1516
get waitUntilReady(): Promise<boolean> {
@@ -24,6 +25,12 @@ export class SharedTSCompilationState {
2425
return this.#compilationReadyPromise;
2526
}
2627

28+
constructor() {
29+
compilationDisposedPromise ??= new Promise((resolve) => {
30+
disposeCompilation = resolve;
31+
});
32+
}
33+
2734
markAsReady(hasErrors: boolean): void {
2835
this.#hasErrors = hasErrors;
2936
this.#resolveCompilationReady?.(hasErrors);
@@ -37,7 +44,9 @@ export class SharedTSCompilationState {
3744

3845
dispose(): void {
3946
this.markAsReady(true);
47+
disposeCompilation?.();
4048
globalSharedCompilationState = undefined;
49+
compilationDisposedPromise = undefined;
4150
}
4251
}
4352

@@ -46,3 +55,17 @@ let globalSharedCompilationState: SharedTSCompilationState | undefined;
4655
export function getSharedCompilationState(): SharedTSCompilationState {
4756
return (globalSharedCompilationState ??= new SharedTSCompilationState());
4857
}
58+
59+
/**
60+
* ESbuild doesnt allow for awaiting the cleanup of plugins, therefore this
61+
* allows consumers of the compiler-plugin to await the disposal of the plugin
62+
* after ESbuild dispose function was called.
63+
*/
64+
let disposeCompilation: (() => void) | undefined;
65+
let compilationDisposedPromise: Promise<void> | undefined;
66+
67+
export function getSharedCompilationStateCleanup() {
68+
return (compilationDisposedPromise ??= new Promise((resolve) => {
69+
disposeCompilation = resolve;
70+
}));
71+
}

packages/angular/build/src/tools/esbuild/angular/compiler-plugin.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -588,11 +588,14 @@ export function createCompilerPlugin(
588588
logCumulativeDurations();
589589
});
590590

591-
build.onDispose(() => {
592-
sharedTSCompilationState?.dispose();
593-
void compilation.close?.();
594-
void cacheStore?.close();
595-
});
591+
build.onDispose(
592+
() =>
593+
void Promise.all(
594+
[compilation?.close?.(), cacheStore?.close(), javascriptTransformer.close()].filter(
595+
Boolean,
596+
),
597+
).then(() => sharedTSCompilationState?.dispose()),
598+
);
596599

597600
/**
598601
* Checks if the file has side-effects when `advancedOptimizations` is enabled.

0 commit comments

Comments
 (0)