From c462d9cb90377342980384c6bccb3ddfef533282 Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Tue, 30 May 2023 15:03:21 -0400 Subject: [PATCH] fix(@angular-devkit/build-angular): preemptively remove AOT metadata in esbuild builder The Angular compiler generates two types of metadata calls when it generates AOT code. This metadata is not used in fully AOT compiled applications and can contain direct references to components, services, etc. that may affect the output chunk layout of the application. While this currently has not lead to any problems, it could in the future and the Webpack bundler already performs a transform that preemptively removes these calls. To remain consistent, the esbuild-based build system will now also perform this transform. This also updates the autoprefixer behavior tests to check the actual runtime style text instead of the style text within the metadata calls. --- .../browser-esbuild/angular/aot-compilation.ts | 13 +++++++++---- .../behavior/stylesheet_autoprefixer_spec.ts | 17 +++++++---------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/packages/angular_devkit/build_angular/src/builders/browser-esbuild/angular/aot-compilation.ts b/packages/angular_devkit/build_angular/src/builders/browser-esbuild/angular/aot-compilation.ts index 84a59e40a7b9..72c452dd1947 100644 --- a/packages/angular_devkit/build_angular/src/builders/browser-esbuild/angular/aot-compilation.ts +++ b/packages/angular_devkit/build_angular/src/builders/browser-esbuild/angular/aot-compilation.ts @@ -19,7 +19,10 @@ import { // Temporary deep import for transformer support // TODO: Move these to a private exports location or move the implementation into this package. -const { mergeTransformers, replaceBootstrap } = require('@ngtools/webpack/src/ivy/transformation'); +const { + mergeTransformers, + createAotTransformers, +} = require('@ngtools/webpack/src/ivy/transformation'); class AngularCompilationState { constructor( @@ -191,9 +194,11 @@ export class AotCompilation extends AngularCompilation { angularCompiler.incrementalCompilation.recordSuccessfulEmit(sourceFile); emittedFiles.set(sourceFile, { filename: sourceFile.fileName, contents }); }; - const transformers = mergeTransformers(angularCompiler.prepareEmit().transformers, { - before: [replaceBootstrap(() => typeScriptProgram.getProgram().getTypeChecker())], - }); + const transformers = mergeTransformers( + angularCompiler.prepareEmit().transformers, + // The default behavior is to replace JIT bootstraping and remove AOT metadata calls + createAotTransformers(typeScriptProgram, {}), + ); // TypeScript will loop until there are no more affected files in the program while ( diff --git a/packages/angular_devkit/build_angular/src/builders/browser-esbuild/tests/behavior/stylesheet_autoprefixer_spec.ts b/packages/angular_devkit/build_angular/src/builders/browser-esbuild/tests/behavior/stylesheet_autoprefixer_spec.ts index bf08b78bd19b..84aa4039d406 100644 --- a/packages/angular_devkit/build_angular/src/builders/browser-esbuild/tests/behavior/stylesheet_autoprefixer_spec.ts +++ b/packages/angular_devkit/build_angular/src/builders/browser-esbuild/tests/behavior/stylesheet_autoprefixer_spec.ts @@ -106,12 +106,10 @@ describeBuilder(buildEsbuildBrowser, BROWSER_BUILDER_INFO, (harness) => { harness .expectFile('dist/main.js') - .content.toMatch( - /section\s*{\\n\s*-webkit-hyphens:\s*none;\\n\s*hyphens:\s*none;\\n\s*}/, - ); + .content.toMatch(/{\\n\s*-webkit-hyphens:\s*none;\\n\s*hyphens:\s*none;\\n\s*}/); harness .expectFile('dist/main.js') - .content.toMatch(/div\s*{\\n\s*-webkit-hyphens:\s*none;\\n\s*hyphens:\s*none;\\n\s*}/); + .content.toMatch(/{\\n\s*-webkit-hyphens:\s*none;\\n\s*hyphens:\s*none;\\n\s*}/); }); it(`should not add prefixes if not required by browsers in external component styles [${ext}]`, async () => { @@ -137,10 +135,8 @@ describeBuilder(buildEsbuildBrowser, BROWSER_BUILDER_INFO, (harness) => { const { result } = await harness.executeOnce(); expect(result?.success).toBeTrue(); - harness - .expectFile('dist/main.js') - .content.toMatch(/section\s*{\\n\s*hyphens:\s*none;\\n\s*}/); - harness.expectFile('dist/main.js').content.toMatch(/div\s*{\\n\s*hyphens:\s*none;\\n\s*}/); + harness.expectFile('dist/main.js').content.toMatch(/{\\n\s*hyphens:\s*none;\\n\s*}/); + harness.expectFile('dist/main.js').content.toMatch(/{\\n\s*hyphens:\s*none;\\n\s*}/); }); } @@ -169,7 +165,8 @@ describeBuilder(buildEsbuildBrowser, BROWSER_BUILDER_INFO, (harness) => { harness .expectFile('dist/main.js') - .content.toMatch(/div\s*{\\n\s*-webkit-hyphens:\s*none;\\n\s*hyphens:\s*none;\\n\s*}/); + // div[_ngcontent-%COMP%] {\n -webkit-hyphens: none;\n hyphens: none;\n}\n + .content.toMatch(/{\\n\s*-webkit-hyphens:\s*none;\\n\s*hyphens:\s*none;\\n\s*}/); }); it('should not add prefixes if not required by browsers in inline component styles', async () => { @@ -193,7 +190,7 @@ describeBuilder(buildEsbuildBrowser, BROWSER_BUILDER_INFO, (harness) => { const { result } = await harness.executeOnce(); expect(result?.success).toBeTrue(); - harness.expectFile('dist/main.js').content.toMatch(/div\s*{\\n\s*hyphens:\s*none;\\n\s*}/); + harness.expectFile('dist/main.js').content.toMatch(/{\\n\s*hyphens:\s*none;\\n\s*}/); }); }); });