Skip to content

Commit 364a16b

Browse files
alan-agius4clydin
authored andcommitted
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
1 parent 10588c2 commit 364a16b

File tree

7 files changed

+169
-6
lines changed

7 files changed

+169
-6
lines changed

packages/angular_devkit/build_angular/package.json

+4-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
"babel-loader": "9.1.3",
2828
"babel-plugin-istanbul": "6.1.1",
2929
"browserslist": "^4.21.5",
30-
"browser-sync": "2.29.3",
3130
"chokidar": "3.5.3",
3231
"copy-webpack-plugin": "11.0.0",
3332
"critters": "0.0.20",
@@ -80,6 +79,7 @@
8079
"@angular/localize": "^17.0.0 || ^17.1.0-next.0",
8180
"@angular/platform-server": "^17.0.0 || ^17.1.0-next.0",
8281
"@angular/service-worker": "^17.0.0 || ^17.1.0-next.0",
82+
"browser-sync": "^2.29.3",
8383
"jest": "^29.5.0",
8484
"jest-environment-jsdom": "^29.5.0",
8585
"karma": "^6.3.0",
@@ -98,6 +98,9 @@
9898
"@angular/service-worker": {
9999
"optional": true
100100
},
101+
"browser-sync": {
102+
"optional": true
103+
},
101104
"jest": {
102105
"optional": true
103106
},

packages/angular_devkit/build_angular/src/builders/ssr-dev-server/index.ts

+12-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,18 @@ export function execute(
8080
verbose: options.verbose,
8181
} as json.JsonObject);
8282

83-
const bsInstance = require('browser-sync').create();
83+
let browserSync: typeof import('browser-sync');
84+
try {
85+
browserSync = require('browser-sync');
86+
} catch {
87+
return of({
88+
success: false,
89+
error:
90+
'"browser-sync" is not installed, most likely you need to run `npm install browser-sync --save-dev` in your project.',
91+
});
92+
}
93+
94+
const bsInstance = browserSync.create();
8495

8596
context.logger.error(tags.stripIndents`
8697
****************************************************************************************

packages/schematics/angular/migrations/migration-collection.json

+5
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@
1515
"factory": "./update-17/update-workspace-config",
1616
"description": "Replace deprecated options in 'angular.json'."
1717
},
18+
"add-browser-sync-dependency": {
19+
"version": "17.1.0",
20+
"factory": "./update-17/add-browser-sync-dependency",
21+
"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'."
22+
},
1823
"use-application-builder": {
1924
"version": "18.0.0",
2025
"factory": "./update-17/use-application-builder",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import { Rule } from '@angular-devkit/schematics';
10+
import { DependencyType, addDependency } from '../../utility';
11+
import { getPackageJsonDependency } from '../../utility/dependencies';
12+
import { latestVersions } from '../../utility/latest-versions';
13+
import { getWorkspace } from '../../utility/workspace';
14+
import { Builders, ProjectType } from '../../utility/workspace-models';
15+
16+
const BROWSER_SYNC_VERSION = latestVersions['browser-sync'];
17+
18+
export default function (): Rule {
19+
return async (tree) => {
20+
if (getPackageJsonDependency(tree, 'browser-sync')?.version === BROWSER_SYNC_VERSION) {
21+
return;
22+
}
23+
24+
const workspace = await getWorkspace(tree);
25+
for (const project of workspace.projects.values()) {
26+
if (project.extensions.projectType !== ProjectType.Application) {
27+
continue;
28+
}
29+
30+
for (const target of project.targets.values()) {
31+
if (target.builder === Builders.SsrDevServer) {
32+
return addDependency('browser-sync', BROWSER_SYNC_VERSION, {
33+
type: DependencyType.Dev,
34+
});
35+
}
36+
}
37+
}
38+
};
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import { EmptyTree } from '@angular-devkit/schematics';
10+
import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing';
11+
import { latestVersions } from '../../utility/latest-versions';
12+
import { Builders, ProjectType } from '../../utility/workspace-models';
13+
14+
describe(`Migration to add 'browser-sync' as a dev dependency`, () => {
15+
const schematicName = 'add-browser-sync-dependency';
16+
const schematicRunner = new SchematicTestRunner(
17+
'migrations',
18+
require.resolve('../migration-collection.json'),
19+
);
20+
21+
let tree: UnitTestTree;
22+
beforeEach(() => {
23+
tree = new UnitTestTree(new EmptyTree());
24+
tree.create(
25+
'/package.json',
26+
JSON.stringify(
27+
{
28+
devDependencies: {},
29+
},
30+
undefined,
31+
2,
32+
),
33+
);
34+
});
35+
36+
it(`should add 'browser-sync' as devDependencies when '@angular-devkit/build-angular:ssr-dev-server' is used`, async () => {
37+
tree.create(
38+
'/angular.json',
39+
JSON.stringify(
40+
{
41+
version: 1,
42+
projects: {
43+
app: {
44+
root: '',
45+
projectType: ProjectType.Application,
46+
prefix: 'app',
47+
architect: {
48+
'serve-ssr': {
49+
builder: Builders.SsrDevServer,
50+
options: {},
51+
},
52+
},
53+
},
54+
},
55+
},
56+
undefined,
57+
2,
58+
),
59+
);
60+
61+
const newTree = await schematicRunner.runSchematic(schematicName, {}, tree);
62+
const { devDependencies } = JSON.parse(newTree.readContent('/package.json'));
63+
expect(devDependencies['browser-sync']).toBe(latestVersions['browser-sync']);
64+
});
65+
66+
it(`should not add 'browser-sync' as devDependencies when '@angular-devkit/build-angular:ssr-dev-server' is not used`, async () => {
67+
tree.create(
68+
'/angular.json',
69+
JSON.stringify(
70+
{
71+
version: 1,
72+
projects: {
73+
app: {
74+
root: '',
75+
projectType: ProjectType.Application,
76+
prefix: 'app',
77+
architect: {
78+
'serve-ssr': {
79+
builder: Builders.Browser,
80+
options: {},
81+
},
82+
},
83+
},
84+
},
85+
},
86+
undefined,
87+
2,
88+
),
89+
);
90+
const newTree = await schematicRunner.runSchematic(schematicName, {}, tree);
91+
const { devDependencies } = JSON.parse(newTree.readContent('/package.json'));
92+
expect(devDependencies['browser-sync']).toBeUndefined();
93+
});
94+
});

packages/schematics/angular/ssr/index.ts

+14-4
Original file line numberDiff line numberDiff line change
@@ -212,8 +212,8 @@ function updateWebpackBuilderServerTsConfigRule(options: SSROptions): Rule {
212212
};
213213
}
214214

215-
function addDependencies(): Rule {
216-
return chain([
215+
function addDependencies(isUsingApplicationBuilder: boolean): Rule {
216+
const rules: Rule[] = [
217217
addDependency('@angular/ssr', latestVersions.AngularSSR, {
218218
type: DependencyType.Default,
219219
}),
@@ -223,7 +223,17 @@ function addDependencies(): Rule {
223223
addDependency('@types/express', latestVersions['@types/express'], {
224224
type: DependencyType.Dev,
225225
}),
226-
]);
226+
];
227+
228+
if (!isUsingApplicationBuilder) {
229+
rules.push(
230+
addDependency('browser-sync', latestVersions['browser-sync'], {
231+
type: DependencyType.Dev,
232+
}),
233+
);
234+
}
235+
236+
return chain(rules);
227237
}
228238

229239
function addServerFile(options: ServerOptions, isStandalone: boolean): Rule {
@@ -288,7 +298,7 @@ export default function (options: SSROptions): Rule {
288298
]),
289299
addServerFile(options, isStandalone),
290300
addScriptsRule(options, isUsingApplicationBuilder),
291-
addDependencies(),
301+
addDependencies(isUsingApplicationBuilder),
292302
]);
293303
};
294304
}

packages/schematics/angular/utility/latest-versions/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"@types/express": "^4.17.17",
77
"@types/jasmine": "~5.1.0",
88
"@types/node": "^18.18.0",
9+
"browser-sync": "^2.29.3",
910
"express": "^4.18.2",
1011
"jasmine-core": "~5.1.0",
1112
"jasmine-spec-reporter": "~7.0.0",

0 commit comments

Comments
 (0)