diff --git a/packages/schematics/angular/migrations/migration-collection.json b/packages/schematics/angular/migrations/migration-collection.json index cb265c98c51b..afebb2c8fe04 100644 --- a/packages/schematics/angular/migrations/migration-collection.json +++ b/packages/schematics/angular/migrations/migration-collection.json @@ -9,6 +9,11 @@ "version": "16.0.0", "factory": "./update-16/replace-default-collection-option", "description": "Replace removed 'defaultCollection' option in workspace configuration with 'schematicCollections'." + }, + "update-server-builder-config": { + "version": "16.0.0", + "factory": "./update-16/update-server-builder-config", + "description": "Update the '@angular-devkit/build-angular:server' builder configuration to disable 'buildOptimizer' for non optimized builds." } } } diff --git a/packages/schematics/angular/migrations/update-16/update-server-builder-config.ts b/packages/schematics/angular/migrations/update-16/update-server-builder-config.ts new file mode 100644 index 000000000000..534a7f9930d9 --- /dev/null +++ b/packages/schematics/angular/migrations/update-16/update-server-builder-config.ts @@ -0,0 +1,30 @@ +/** + * @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 { Rule } from '@angular-devkit/schematics'; +import { allTargetOptions, updateWorkspace } from '../../utility/workspace'; +import { Builders } from '../../utility/workspace-models'; + +export default function (): Rule { + return updateWorkspace((workspace) => { + for (const project of workspace.projects.values()) { + for (const target of project.targets.values()) { + if (target.builder !== Builders.Server) { + continue; + } + + for (const [, options] of allTargetOptions(target)) { + // Set 'buildOptimizer' to match the 'optimization' option. + if (options.buildOptimizer === undefined && options.optimization !== undefined) { + options.buildOptimizer = !!options.optimization; + } + } + } + } + }); +} diff --git a/packages/schematics/angular/migrations/update-16/update-server-builder-config_spec.ts b/packages/schematics/angular/migrations/update-16/update-server-builder-config_spec.ts new file mode 100644 index 000000000000..fa8683c5b53b --- /dev/null +++ b/packages/schematics/angular/migrations/update-16/update-server-builder-config_spec.ts @@ -0,0 +1,91 @@ +/** + * @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 { JsonObject } from '@angular-devkit/core'; +import { EmptyTree } from '@angular-devkit/schematics'; +import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing'; +import { + BuilderTarget, + Builders, + ProjectType, + WorkspaceSchema, +} from '../../utility/workspace-models'; + +function getServerTarget(tree: UnitTestTree): BuilderTarget { + const target = (tree.readJson('/angular.json') as unknown as WorkspaceSchema).projects.app + .architect?.server; + + return target as unknown as BuilderTarget; +} + +function createWorkSpaceConfig(tree: UnitTestTree) { + const angularConfig: WorkspaceSchema = { + version: 1, + projects: { + app: { + root: '', + sourceRoot: 'src', + projectType: ProjectType.Application, + prefix: 'app', + architect: { + server: { + builder: Builders.Server, + options: { + main: './server.ts', + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } as any, + configurations: { + development: { + optimization: false, + }, + production: { + optimization: true, + }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } as any, + }, + }, + }, + }, + }; + + tree.create('/angular.json', JSON.stringify(angularConfig, undefined, 2)); +} + +const schematicName = 'update-server-builder-config'; + +describe(`Migration to update '@angular-devkit/build-angular:server' options. ${schematicName}`, () => { + const schematicRunner = new SchematicTestRunner( + 'migrations', + require.resolve('../migration-collection.json'), + ); + + let tree: UnitTestTree; + beforeEach(() => { + tree = new UnitTestTree(new EmptyTree()); + createWorkSpaceConfig(tree); + }); + + it(`should add 'buildOptimizer: false' to 'optimization' is 'false'`, async () => { + const newTree = await schematicRunner.runSchematic(schematicName, {}, tree); + const { configurations } = getServerTarget(newTree); + expect(configurations?.development.buildOptimizer).toBeFalse(); + }); + + it(`should not add 'buildOptimizer' option when to 'optimization' is not defined.`, async () => { + const newTree = await schematicRunner.runSchematic(schematicName, {}, tree); + const { options } = getServerTarget(newTree); + expect(options.buildOptimizer).toBeUndefined(); + }); + + it(`should add 'buildOptimizer: true' to 'optimization' is 'true'`, async () => { + const newTree = await schematicRunner.runSchematic(schematicName, {}, tree); + const { configurations } = getServerTarget(newTree); + expect(configurations?.production.buildOptimizer).toBeTrue(); + }); +});