From 9ca3a54503574674eb107d4d2b507be7ecd727ee Mon Sep 17 00:00:00 2001 From: Alan Agius Date: Mon, 4 Mar 2024 14:08:41 +0000 Subject: [PATCH] feat(@angular-devkit/build-angular): add `deployUrl` to application builder This commit adds the deployUrl option ot the application builder. Closes #26411 --- .../angular_devkit/build_angular/index.md | 3 +- .../src/builders/application/options.ts | 7 +- .../src/builders/application/schema.json | 4 + .../tests/options/deploy-url_spec.ts | 81 +++++++++++++++++++ .../src/builders/browser-esbuild/schema.json | 3 +- .../tests/options/deploy-url_spec.ts | 21 +++-- .../src/builders/browser/schema.json | 3 +- .../src/builders/server/schema.json | 3 +- .../update-17/use-application-builder.ts | 30 +------ 9 files changed, 101 insertions(+), 54 deletions(-) create mode 100644 packages/angular_devkit/build_angular/src/builders/application/tests/options/deploy-url_spec.ts diff --git a/goldens/public-api/angular_devkit/build_angular/index.md b/goldens/public-api/angular_devkit/build_angular/index.md index f69fe3eae25f..10f34699e967 100644 --- a/goldens/public-api/angular_devkit/build_angular/index.md +++ b/goldens/public-api/angular_devkit/build_angular/index.md @@ -36,6 +36,7 @@ export interface ApplicationBuilderOptions { [key: string]: string; }; deleteOutputPath?: boolean; + deployUrl?: string; externalDependencies?: string[]; extractLicenses?: boolean; fileReplacements?: FileReplacement_2[]; @@ -94,7 +95,6 @@ export interface BrowserBuilderOptions { commonChunk?: boolean; crossOrigin?: CrossOrigin; deleteOutputPath?: boolean; - // @deprecated deployUrl?: string; extractLicenses?: boolean; fileReplacements?: FileReplacement[]; @@ -351,7 +351,6 @@ export interface ServerBuilderOptions { assets?: AssetPattern_4[]; buildOptimizer?: boolean; deleteOutputPath?: boolean; - // @deprecated deployUrl?: string; externalDependencies?: string[]; extractLicenses?: boolean; diff --git a/packages/angular_devkit/build_angular/src/builders/application/options.ts b/packages/angular_devkit/build_angular/src/builders/application/options.ts index 8eb6861fe4f2..95d1f35d8631 100644 --- a/packages/angular_devkit/build_angular/src/builders/application/options.ts +++ b/packages/angular_devkit/build_angular/src/builders/application/options.ts @@ -65,11 +65,6 @@ interface InternalOptions { * This is only used by the development server which currently only supports a single locale per build. */ forceI18nFlatOutput?: boolean; - - /** - * Allows for usage of the deprecated `deployUrl` option with the compatibility builder `browser-esbuild`. - */ - deployUrl?: string; } /** Full set of options for `application` builder. */ @@ -345,7 +340,7 @@ export async function normalizeOptions( i18nOptions, namedChunks, budgets: budgets?.length ? budgets : undefined, - publicPath: deployUrl ? deployUrl : undefined, + publicPath: deployUrl, plugins: extensions?.codePlugins?.length ? extensions?.codePlugins : undefined, loaderExtensions, jsonLogs: useJSONBuildLogs, diff --git a/packages/angular_devkit/build_angular/src/builders/application/schema.json b/packages/angular_devkit/build_angular/src/builders/application/schema.json index e82ecf523ead..9266d7b45a7a 100644 --- a/packages/angular_devkit/build_angular/src/builders/application/schema.json +++ b/packages/angular_devkit/build_angular/src/builders/application/schema.json @@ -33,6 +33,10 @@ "type": "string", "description": "The full path for the TypeScript configuration file, relative to the current workspace." }, + "deployUrl": { + "type": "string", + "description": "Customize the base path for the URLs of resources in 'index.html' and component stylesheets. This option is only necessary for specific deployment scenarios, such as with Angular Elements or when utilizing different CDN locations." + }, "scripts": { "description": "Global scripts to be included in the build.", "type": "array", diff --git a/packages/angular_devkit/build_angular/src/builders/application/tests/options/deploy-url_spec.ts b/packages/angular_devkit/build_angular/src/builders/application/tests/options/deploy-url_spec.ts new file mode 100644 index 000000000000..5c864cd5b4b1 --- /dev/null +++ b/packages/angular_devkit/build_angular/src/builders/application/tests/options/deploy-url_spec.ts @@ -0,0 +1,81 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import { buildApplication } from '../../index'; +import { APPLICATION_BUILDER_INFO, BASE_OPTIONS, describeBuilder } from '../setup'; + +describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => { + describe('Option: "deployUrl"', () => { + beforeEach(async () => { + // Add a global stylesheet to test link elements + await harness.writeFile('src/styles.css', '/* Global styles */'); + + // Reduce the input index HTML to a single line to simplify comparing + await harness.writeFile( + 'src/index.html', + '', + ); + }); + + it('should update script src and link href attributes when option is set to relative URL', async () => { + harness.useTarget('build', { + ...BASE_OPTIONS, + styles: ['src/styles.css'], + deployUrl: 'deployUrl/', + }); + + const { result } = await harness.executeOnce(); + expect(result?.success).toBe(true); + harness + .expectFile('dist/browser/index.html') + .content.toEqual( + `` + + `` + + ``, + ); + }); + + it('should update script src and link href attributes when option is set to absolute URL', async () => { + harness.useTarget('build', { + ...BASE_OPTIONS, + styles: ['src/styles.css'], + deployUrl: 'https://example.com/some/path/', + }); + + const { result } = await harness.executeOnce(); + expect(result?.success).toBe(true); + harness + .expectFile('dist/browser/index.html') + .content.toEqual( + `` + + `` + + ``, + ); + }); + + it('should update resources component stylesheets to reference deployURL', async () => { + await harness.writeFile('src/app/test.svg', ''); + await harness.writeFile( + 'src/app/app.component.css', + `* { background-image: url('./test.svg'); }`, + ); + + harness.useTarget('build', { + ...BASE_OPTIONS, + deployUrl: 'https://example.com/some/path/', + }); + + const { result } = await harness.executeOnce(); + expect(result?.success).toBeTrue(); + + harness + .expectFile('dist/browser/main.js') + .content.toContain('background-image: url("https://example.com/some/path/media/test.svg")'); + }); + }); +}); diff --git a/packages/angular_devkit/build_angular/src/builders/browser-esbuild/schema.json b/packages/angular_devkit/build_angular/src/builders/browser-esbuild/schema.json index 20075928cd2a..97775773d09c 100644 --- a/packages/angular_devkit/build_angular/src/builders/browser-esbuild/schema.json +++ b/packages/angular_devkit/build_angular/src/builders/browser-esbuild/schema.json @@ -277,8 +277,7 @@ }, "deployUrl": { "type": "string", - "description": "URL where files will be deployed.", - "x-deprecated": "Use \"baseHref\" option, \"APP_BASE_HREF\" DI token or a combination of both instead. For more information, see https://angular.io/guide/deployment#the-deploy-url." + "description": "Customize the base path for the URLs of resources in 'index.html' and component stylesheets. This option is only necessary for specific deployment scenarios, such as with Angular Elements or when utilizing different CDN locations." }, "verbose": { "type": "boolean", diff --git a/packages/angular_devkit/build_angular/src/builders/browser-esbuild/tests/options/deploy-url_spec.ts b/packages/angular_devkit/build_angular/src/builders/browser-esbuild/tests/options/deploy-url_spec.ts index 0bb5c942adc3..c975d7111fe9 100644 --- a/packages/angular_devkit/build_angular/src/builders/browser-esbuild/tests/options/deploy-url_spec.ts +++ b/packages/angular_devkit/build_angular/src/builders/browser-esbuild/tests/options/deploy-url_spec.ts @@ -12,9 +12,6 @@ import { BASE_OPTIONS, BROWSER_BUILDER_INFO, describeBuilder } from '../setup'; describeBuilder(buildEsbuildBrowser, BROWSER_BUILDER_INFO, (harness) => { describe('Option: "deployUrl"', () => { beforeEach(async () => { - // Application code is not needed for asset tests - await harness.writeFile('src/main.ts', 'console.log("TEST");'); - // Add a global stylesheet to test link elements await harness.writeFile('src/styles.css', '/* Global styles */'); @@ -61,22 +58,24 @@ describeBuilder(buildEsbuildBrowser, BROWSER_BUILDER_INFO, (harness) => { ); }); - it('should update dynamic import statements when option is set', async () => { + it('should update resources component stylesheets to reference deployURL', async () => { + await harness.writeFile('src/app/test.svg', ''); + await harness.writeFile( + 'src/app/app.component.css', + `* { background-image: url('./test.svg'); }`, + ); + harness.useTarget('build', { ...BASE_OPTIONS, - styles: ['src/styles.css'], deployUrl: 'https://example.com/some/path/', - namedChunks: true, }); - await harness.writeFile('src/main.ts', 'console.log("TEST");\nimport("./a");\nexport {}'); - await harness.writeFile('src/a.ts', 'console.log("A");\nexport {}'); - const { result } = await harness.executeOnce(); - expect(result?.success).toBe(true); + expect(result?.success).toBeTrue(); + harness .expectFile('dist/main.js') - .content.toContain('import("https://example.com/some/path/a'); + .content.toContain('background-image: url("https://example.com/some/path/media/test.svg")'); }); }); }); diff --git a/packages/angular_devkit/build_angular/src/builders/browser/schema.json b/packages/angular_devkit/build_angular/src/builders/browser/schema.json index 263d121227c7..58ba4f089b11 100644 --- a/packages/angular_devkit/build_angular/src/builders/browser/schema.json +++ b/packages/angular_devkit/build_angular/src/builders/browser/schema.json @@ -270,8 +270,7 @@ }, "deployUrl": { "type": "string", - "description": "URL where files will be deployed.", - "x-deprecated": "Use \"baseHref\" option, \"APP_BASE_HREF\" DI token or a combination of both instead. For more information, see https://angular.io/guide/deployment#the-deploy-url." + "description": "Customize the base path for the URLs of resources in 'index.html' and component stylesheets. This option is only necessary for specific deployment scenarios, such as with Angular Elements or when utilizing different CDN locations." }, "verbose": { "type": "boolean", diff --git a/packages/angular_devkit/build_angular/src/builders/server/schema.json b/packages/angular_devkit/build_angular/src/builders/server/schema.json index 4ab03873d7d0..c5e538432849 100644 --- a/packages/angular_devkit/build_angular/src/builders/server/schema.json +++ b/packages/angular_devkit/build_angular/src/builders/server/schema.json @@ -121,8 +121,7 @@ }, "deployUrl": { "type": "string", - "description": "URL where files will be deployed.", - "x-deprecated": "Use \"baseHref\" browser builder option, \"APP_BASE_HREF\" DI token or a combination of both instead. For more information, see https://angular.io/guide/deployment#the-deploy-url." + "description": "Customize the base path for the URLs of resources in 'index.html' and component stylesheets. This option is only necessary for specific deployment scenarios, such as with Angular Elements or when utilizing different CDN locations." }, "vendorChunk": { "type": "boolean", diff --git a/packages/schematics/angular/migrations/update-17/use-application-builder.ts b/packages/schematics/angular/migrations/update-17/use-application-builder.ts index c24bdf86505b..e8c449198c36 100644 --- a/packages/schematics/angular/migrations/update-17/use-application-builder.ts +++ b/packages/schematics/angular/migrations/update-17/use-application-builder.ts @@ -7,13 +7,7 @@ */ import { workspaces } from '@angular-devkit/core'; -import { - Rule, - SchematicContext, - SchematicsException, - chain, - externalSchematic, -} from '@angular-devkit/schematics'; +import { Rule, SchematicsException, chain, externalSchematic } from '@angular-devkit/schematics'; import { dirname, join } from 'node:path/posix'; import { JSONFile } from '../../utility/json-file'; import { TreeWorkspaceHost, allTargetOptions, getWorkspace } from '../../utility/workspace'; @@ -52,11 +46,6 @@ export default function (): Rule { const hasServerTarget = project.targets.has('server'); for (const [, options] of allTargetOptions(buildTarget, false)) { - // Show warnings for using no longer supported options - if (usesNoLongerSupportedOptions(options, context, name)) { - continue; - } - if (options['index'] === '') { options['index'] = false; } @@ -102,7 +91,6 @@ export default function (): Rule { } // Delete removed options - delete options['deployUrl']; delete options['vendorChunk']; delete options['commonChunk']; delete options['resourcesOutputPath']; @@ -204,19 +192,3 @@ export default function (): Rule { return chain(rules); }; } - -function usesNoLongerSupportedOptions( - { deployUrl, resourcesOutputPath }: Record, - context: SchematicContext, - projectName: string, -): boolean { - let hasUsage = false; - if (typeof deployUrl === 'string') { - hasUsage = true; - context.logger.warn( - `Skipping migration for project "${projectName}". "deployUrl" option is not available in the application builder.`, - ); - } - - return hasUsage; -}