From 259ec72d521b3a660c54ec33aaf8bf7c838281e7 Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Thu, 29 Feb 2024 11:21:00 -0500 Subject: [PATCH] fix(@angular-devkit/build-angular): avoid marking component styles as media with no output media directory The logic to detect media output files was previously predicated on the presence of a media subdirectory being defined. Prior to the ability to customize output path subcomponents there was a guaranteed media subdirectory. However, now that customization is possible, there is the potential for media files to not have a distinct subdirectory in the output. To facilitate output media detection in this scenario a file extension based method is now employed. This avoids a dependence on output directory structure. (cherry picked from commit 7a1a44305cd73aa99290b4e2a234f8e7b5d0adb8) --- .../tests/options/output-path_spec.ts | 57 ++++++++++++++++++- .../src/tools/esbuild/bundler-context.ts | 5 +- 2 files changed, 56 insertions(+), 6 deletions(-) diff --git a/packages/angular_devkit/build_angular/src/builders/application/tests/options/output-path_spec.ts b/packages/angular_devkit/build_angular/src/builders/application/tests/options/output-path_spec.ts index 7b2706ba2ba4..580aa2e6e6c1 100644 --- a/packages/angular_devkit/build_angular/src/builders/application/tests/options/output-path_spec.ts +++ b/packages/angular_devkit/build_angular/src/builders/application/tests/options/output-path_spec.ts @@ -11,8 +11,11 @@ import { APPLICATION_BUILDER_INFO, BASE_OPTIONS, describeBuilder } from '../setu describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => { beforeEach(async () => { - // Add a media file + // Add a global stylesheet media file await harness.writeFile('src/styles.css', `h1 { background: url('./spectrum.png')}`); + // Add a component stylesheet media file + await harness.writeFile('src/app/abc.svg', ''); + await harness.writeFile('src/app/app.component.css', `h2 { background: url('./abc.svg')}`); // Enable SSR await harness.modifyFile('src/tsconfig.app.json', (content) => { @@ -23,10 +26,9 @@ describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => { return JSON.stringify(tsConfig); }); - // Application code is not needed in this test + // Application server code is not needed in this test await harness.writeFile('src/main.server.ts', `console.log('Hello!');`); await harness.writeFile('src/server.ts', `console.log('Hello!');`); - await harness.writeFile('src/main.ts', `console.log('Hello!');`); }); describe('Option: "outputPath"', () => { @@ -56,6 +58,7 @@ describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => { expect(result?.success).toBeTrue(); harness.expectFile('dist/browser/media/spectrum.png').toExist(); + harness.expectFile('dist/browser/media/abc.svg').toExist(); }); it(`should emit server bundles in 'server' directory`, async () => { @@ -96,6 +99,50 @@ describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => { expect(result?.success).toBeTrue(); harness.expectFile('dist/browser/resource/spectrum.png').toExist(); + harness.expectFile('dist/browser/resource/abc.svg').toExist(); + }); + + it(`should emit server bundles in 'server' directory`, async () => { + const { result } = await harness.executeOnce(); + expect(result?.success).toBeTrue(); + + harness.expectFile('dist/server/server.mjs').toExist(); + }); + }); + + describe(`'media' is set to ''`, () => { + beforeEach(() => { + harness.useTarget('build', { + ...BASE_OPTIONS, + polyfills: [], + styles: ['src/styles.css'], + server: 'src/main.server.ts', + outputPath: { + base: 'dist', + media: '', + }, + ssr: { + entry: 'src/server.ts', + }, + }); + }); + + it(`should emit browser bundles in 'browser' directory`, async () => { + const { result } = await harness.executeOnce(); + expect(result?.success).toBeTrue(); + + harness.expectFile('dist/browser/main.js').toExist(); + }); + + it(`should emit media files in 'browser' directory`, async () => { + const { result } = await harness.executeOnce(); + expect(result?.success).toBeTrue(); + + harness.expectFile('dist/browser/spectrum.png').toExist(); + harness.expectFile('dist/browser/abc.svg').toExist(); + + // Component CSS should not be considered media + harness.expectFile('dist/browser/app.component.css').toNotExist(); }); it(`should emit server bundles in 'server' directory`, async () => { @@ -135,6 +182,7 @@ describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => { expect(result?.success).toBeTrue(); harness.expectFile('dist/browser/media/spectrum.png').toExist(); + harness.expectFile('dist/browser/media/abc.svg').toExist(); }); it(`should emit server bundles in 'node-server' directory`, async () => { @@ -174,6 +222,7 @@ describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => { expect(result?.success).toBeTrue(); harness.expectFile('dist/public/media/spectrum.png').toExist(); + harness.expectFile('dist/public/media/abc.svg').toExist(); }); it(`should emit server bundles in 'server' directory`, async () => { @@ -220,6 +269,7 @@ describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => { expect(result?.success).toBeTrue(); harness.expectFile('dist/media/spectrum.png').toExist(); + harness.expectFile('dist/media/abc.svg').toExist(); }); it(`should error when ssr is enabled`, async () => { @@ -273,6 +323,7 @@ describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => { expect(result?.success).toBeTrue(); harness.expectFile('dist/browser/media/spectrum.png').toExist(); + harness.expectFile('dist/browser/media/abc.svg').toExist(); }); it(`should emit server bundles in '' directory`, async () => { diff --git a/packages/angular_devkit/build_angular/src/tools/esbuild/bundler-context.ts b/packages/angular_devkit/build_angular/src/tools/esbuild/bundler-context.ts index 387aed470139..dd25e85d0c43 100644 --- a/packages/angular_devkit/build_angular/src/tools/esbuild/bundler-context.ts +++ b/packages/angular_devkit/build_angular/src/tools/esbuild/bundler-context.ts @@ -352,11 +352,10 @@ export class BundlerContext { assert(this.#esbuildOptions, 'esbuild options cannot be undefined.'); - const { assetNames = '' } = this.#esbuildOptions; - const mediaDirname = dirname(assetNames); const outputFiles = result.outputFiles.map((file) => { let fileType: BuildOutputFileType; - if (dirname(file.path) === mediaDirname) { + // All files that are not JS, CSS, WASM, or sourcemaps for them are considered media + if (!/\.([cm]?js|css|wasm)(\.map)?$/i.test(file.path)) { fileType = BuildOutputFileType.Media; } else { fileType = this.#platformIsServer