From 75bd83a4be35ccf349f381fdb88051f1cde8fb8b Mon Sep 17 00:00:00 2001 From: Alan Agius Date: Wed, 6 Dec 2023 16:34:08 +0000 Subject: [PATCH] feat(@angular-devkit/build-angular): move `browser-sync` as optional dependency `browser-sync` is now an optional dependency of `@angular-devkit/build-angular`. This package is only needed when using the legacy `@angular-devkit/build-angular:ssr-dev-server` builder. Closes #26349 --- .../angular_devkit/build_angular/package.json | 5 +- .../src/builders/ssr-dev-server/index.ts | 13 ++- .../migrations/migration-collection.json | 5 + .../update-17/add-browser-sync-dependency.ts | 39 ++++++++ .../add-browser-sync-dependency_spec.ts | 94 +++++++++++++++++++ packages/schematics/angular/ssr/index.ts | 18 +++- .../utility/latest-versions/package.json | 1 + 7 files changed, 169 insertions(+), 6 deletions(-) create mode 100644 packages/schematics/angular/migrations/update-17/add-browser-sync-dependency.ts create mode 100644 packages/schematics/angular/migrations/update-17/add-browser-sync-dependency_spec.ts diff --git a/packages/angular_devkit/build_angular/package.json b/packages/angular_devkit/build_angular/package.json index 7df5adc0d516..b9564f3c0198 100644 --- a/packages/angular_devkit/build_angular/package.json +++ b/packages/angular_devkit/build_angular/package.json @@ -27,7 +27,6 @@ "babel-loader": "9.1.3", "babel-plugin-istanbul": "6.1.1", "browserslist": "^4.21.5", - "browser-sync": "2.29.3", "chokidar": "3.5.3", "copy-webpack-plugin": "11.0.0", "critters": "0.0.20", @@ -80,6 +79,7 @@ "@angular/localize": "^17.0.0 || ^17.1.0-next.0", "@angular/platform-server": "^17.0.0 || ^17.1.0-next.0", "@angular/service-worker": "^17.0.0 || ^17.1.0-next.0", + "browser-sync": "^2.29.3", "jest": "^29.5.0", "jest-environment-jsdom": "^29.5.0", "karma": "^6.3.0", @@ -98,6 +98,9 @@ "@angular/service-worker": { "optional": true }, + "browser-sync": { + "optional": true + }, "jest": { "optional": true }, diff --git a/packages/angular_devkit/build_angular/src/builders/ssr-dev-server/index.ts b/packages/angular_devkit/build_angular/src/builders/ssr-dev-server/index.ts index 895b6137f666..231317d03a6b 100644 --- a/packages/angular_devkit/build_angular/src/builders/ssr-dev-server/index.ts +++ b/packages/angular_devkit/build_angular/src/builders/ssr-dev-server/index.ts @@ -80,7 +80,18 @@ export function execute( verbose: options.verbose, } as json.JsonObject); - const bsInstance = require('browser-sync').create(); + let browserSync: typeof import('browser-sync'); + try { + browserSync = require('browser-sync'); + } catch { + return of({ + success: false, + error: + '"browser-sync" is not installed, most likely you need to run `npm install browser-sync --save-dev` in your project.', + }); + } + + const bsInstance = browserSync.create(); context.logger.error(tags.stripIndents` **************************************************************************************** diff --git a/packages/schematics/angular/migrations/migration-collection.json b/packages/schematics/angular/migrations/migration-collection.json index ffb06e47eec3..ee9835fbe30e 100644 --- a/packages/schematics/angular/migrations/migration-collection.json +++ b/packages/schematics/angular/migrations/migration-collection.json @@ -15,6 +15,11 @@ "factory": "./update-17/update-workspace-config", "description": "Replace deprecated options in 'angular.json'." }, + "add-browser-sync-dependency": { + "version": "17.1.0", + "factory": "./update-17/add-browser-sync-dependency", + "description": "Add 'browser-sync' as dev dependency when '@angular-devkit/build-angular:ssr-dev-server' is used, as it is no longer a direct dependency of '@angular-devkit/build-angular'." + }, "use-application-builder": { "version": "18.0.0", "factory": "./update-17/use-application-builder", diff --git a/packages/schematics/angular/migrations/update-17/add-browser-sync-dependency.ts b/packages/schematics/angular/migrations/update-17/add-browser-sync-dependency.ts new file mode 100644 index 000000000000..754f1a809c77 --- /dev/null +++ b/packages/schematics/angular/migrations/update-17/add-browser-sync-dependency.ts @@ -0,0 +1,39 @@ +/** + * @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 { DependencyType, addDependency } from '../../utility'; +import { getPackageJsonDependency } from '../../utility/dependencies'; +import { latestVersions } from '../../utility/latest-versions'; +import { getWorkspace } from '../../utility/workspace'; +import { Builders, ProjectType } from '../../utility/workspace-models'; + +const BROWSER_SYNC_VERSION = latestVersions['browser-sync']; + +export default function (): Rule { + return async (tree) => { + if (getPackageJsonDependency(tree, 'browser-sync')?.version === BROWSER_SYNC_VERSION) { + return; + } + + const workspace = await getWorkspace(tree); + for (const project of workspace.projects.values()) { + if (project.extensions.projectType !== ProjectType.Application) { + continue; + } + + for (const target of project.targets.values()) { + if (target.builder === Builders.SsrDevServer) { + return addDependency('browser-sync', BROWSER_SYNC_VERSION, { + type: DependencyType.Dev, + }); + } + } + } + }; +} diff --git a/packages/schematics/angular/migrations/update-17/add-browser-sync-dependency_spec.ts b/packages/schematics/angular/migrations/update-17/add-browser-sync-dependency_spec.ts new file mode 100644 index 000000000000..b627a162c63f --- /dev/null +++ b/packages/schematics/angular/migrations/update-17/add-browser-sync-dependency_spec.ts @@ -0,0 +1,94 @@ +/** + * @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 { EmptyTree } from '@angular-devkit/schematics'; +import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing'; +import { latestVersions } from '../../utility/latest-versions'; +import { Builders, ProjectType } from '../../utility/workspace-models'; + +describe(`Migration to add 'browser-sync' as a dev dependency`, () => { + const schematicName = 'add-browser-sync-dependency'; + const schematicRunner = new SchematicTestRunner( + 'migrations', + require.resolve('../migration-collection.json'), + ); + + let tree: UnitTestTree; + beforeEach(() => { + tree = new UnitTestTree(new EmptyTree()); + tree.create( + '/package.json', + JSON.stringify( + { + devDependencies: {}, + }, + undefined, + 2, + ), + ); + }); + + it(`should add 'browser-sync' as devDependencies when '@angular-devkit/build-angular:ssr-dev-server' is used`, async () => { + tree.create( + '/angular.json', + JSON.stringify( + { + version: 1, + projects: { + app: { + root: '', + projectType: ProjectType.Application, + prefix: 'app', + architect: { + 'serve-ssr': { + builder: Builders.SsrDevServer, + options: {}, + }, + }, + }, + }, + }, + undefined, + 2, + ), + ); + + const newTree = await schematicRunner.runSchematic(schematicName, {}, tree); + const { devDependencies } = JSON.parse(newTree.readContent('/package.json')); + expect(devDependencies['browser-sync']).toBe(latestVersions['browser-sync']); + }); + + it(`should not add 'browser-sync' as devDependencies when '@angular-devkit/build-angular:ssr-dev-server' is not used`, async () => { + tree.create( + '/angular.json', + JSON.stringify( + { + version: 1, + projects: { + app: { + root: '', + projectType: ProjectType.Application, + prefix: 'app', + architect: { + 'serve-ssr': { + builder: Builders.Browser, + options: {}, + }, + }, + }, + }, + }, + undefined, + 2, + ), + ); + const newTree = await schematicRunner.runSchematic(schematicName, {}, tree); + const { devDependencies } = JSON.parse(newTree.readContent('/package.json')); + expect(devDependencies['browser-sync']).toBeUndefined(); + }); +}); diff --git a/packages/schematics/angular/ssr/index.ts b/packages/schematics/angular/ssr/index.ts index 790eec187efa..8c0436685e2c 100644 --- a/packages/schematics/angular/ssr/index.ts +++ b/packages/schematics/angular/ssr/index.ts @@ -212,8 +212,8 @@ function updateWebpackBuilderServerTsConfigRule(options: SSROptions): Rule { }; } -function addDependencies(): Rule { - return chain([ +function addDependencies(isUsingApplicationBuilder: boolean): Rule { + const rules: Rule[] = [ addDependency('@angular/ssr', latestVersions.AngularSSR, { type: DependencyType.Default, }), @@ -223,7 +223,17 @@ function addDependencies(): Rule { addDependency('@types/express', latestVersions['@types/express'], { type: DependencyType.Dev, }), - ]); + ]; + + if (!isUsingApplicationBuilder) { + rules.push( + addDependency('browser-sync', latestVersions['browser-sync'], { + type: DependencyType.Dev, + }), + ); + } + + return chain(rules); } function addServerFile(options: ServerOptions, isStandalone: boolean): Rule { @@ -288,7 +298,7 @@ export default function (options: SSROptions): Rule { ]), addServerFile(options, isStandalone), addScriptsRule(options, isUsingApplicationBuilder), - addDependencies(), + addDependencies(isUsingApplicationBuilder), ]); }; } diff --git a/packages/schematics/angular/utility/latest-versions/package.json b/packages/schematics/angular/utility/latest-versions/package.json index 13f2afde2c3c..5fc5b7e4bd05 100644 --- a/packages/schematics/angular/utility/latest-versions/package.json +++ b/packages/schematics/angular/utility/latest-versions/package.json @@ -6,6 +6,7 @@ "@types/express": "^4.17.17", "@types/jasmine": "~5.1.0", "@types/node": "^18.18.0", + "browser-sync": "^2.29.3", "express": "^4.18.2", "jasmine-core": "~5.1.0", "jasmine-spec-reporter": "~7.0.0",