Skip to content

Commit

Permalink
feat(@angular-devkit/build-angular): move browser-sync as optional …
Browse files Browse the repository at this point in the history
…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 angular#26349
  • Loading branch information
alan-agius4 committed Dec 5, 2023
1 parent ffa2d07 commit efc8363
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 3 deletions.
5 changes: 4 additions & 1 deletion packages/angular_devkit/build_angular/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand All @@ -98,6 +98,9 @@
"@angular/service-worker": {
"optional": true
},
"browser-sync": {
"optional": true
},
"jest": {
"optional": true
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export type SSRDevServerBuilderOutput = BuilderOutput & {
export function execute(
options: SSRDevServerBuilderOptions,
context: BuilderContext,
): Observable<SSRDevServerBuilderOutput> {
): Observable<SSRDevServerBuilderOutput> | SSRDevServerBuilderOutput {
const browserTarget = targetFromTargetString(options.browserTarget);
const serverTarget = targetFromTargetString(options.serverTarget);
const getBaseUrl = (bs: BrowserSyncInstance) =>
Expand All @@ -76,7 +76,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 {
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`
****************************************************************************************
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* @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 { getWorkspace } from '../../utility/workspace';
import { Builders, ProjectType } from '../../utility/workspace-models';

const BROWSER_SYNC_VERSION = '^2.29.3';
const BROWSER_SYNC_NAME = 'browser-sync';

export default function (): Rule {
return async (tree) => {
if (getPackageJsonDependency(tree, BROWSER_SYNC_NAME)?.version === BROWSER_SYNC_VERSION) {
return;
}

const workspace = await getWorkspace(tree);
for (const [, project] of workspace.projects) {
if (project.extensions.projectType !== ProjectType.Application) {
// Only interested in application projects since these changes only effects application builders
continue;
}

for (const target of project.targets.values()) {
if (target.builder === Builders.SsrDevServer) {
return addDependency(BROWSER_SYNC_NAME, BROWSER_SYNC_NAME, { type: DependencyType.Dev });
}
}
}
};
}
Original file line number Diff line number Diff line change
@@ -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 { EmptyTree } from '@angular-devkit/schematics';
import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing';
import { Builders, ProjectType, WorkspaceSchema } 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: {
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('^2.29.3');
});

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: {
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();
});
});

0 comments on commit efc8363

Please sign in to comment.