Skip to content

Commit 3557804

Browse files
committed
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 angular#26349
1 parent ffa2d07 commit 3557804

File tree

6 files changed

+155
-4
lines changed

6 files changed

+155
-4
lines changed

goldens/public-api/angular_devkit/build_angular/index.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ export function executeServerBuilder(options: ServerBuilderOptions, context: Bui
240240
}): Observable<ServerBuilderOutput>;
241241

242242
// @public (undocumented)
243-
export function executeSSRDevServerBuilder(options: SSRDevServerBuilderOptions, context: BuilderContext): Observable<SSRDevServerBuilderOutput>;
243+
export function executeSSRDevServerBuilder(options: SSRDevServerBuilderOptions, context: BuilderContext): Observable<SSRDevServerBuilderOutput> | SSRDevServerBuilderOutput;
244244

245245
// @public
246246
export type ExecutionTransformer<T> = (input: T) => T | Promise<T>;

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

+13-2
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ export type SSRDevServerBuilderOutput = BuilderOutput & {
5757
export function execute(
5858
options: SSRDevServerBuilderOptions,
5959
context: BuilderContext,
60-
): Observable<SSRDevServerBuilderOutput> {
60+
): Observable<SSRDevServerBuilderOutput> | SSRDevServerBuilderOutput {
6161
const browserTarget = targetFromTargetString(options.browserTarget);
6262
const serverTarget = targetFromTargetString(options.serverTarget);
6363
const getBaseUrl = (bs: BrowserSyncInstance) =>
@@ -76,7 +76,18 @@ export function execute(
7676
verbose: options.verbose,
7777
} as json.JsonObject);
7878

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

8192
context.logger.error(tags.stripIndents`
8293
****************************************************************************************

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 { getWorkspace } from '../../utility/workspace';
13+
import { Builders, ProjectType } from '../../utility/workspace-models';
14+
15+
const BROWSER_SYNC_VERSION = '^2.29.3';
16+
const BROWSER_SYNC_NAME = 'browser-sync';
17+
18+
export default function (): Rule {
19+
return async (tree) => {
20+
if (getPackageJsonDependency(tree, BROWSER_SYNC_NAME)?.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_NAME, BROWSER_SYNC_VERSION, {
33+
type: DependencyType.Dev,
34+
});
35+
}
36+
}
37+
}
38+
};
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
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 { Builders, ProjectType, WorkspaceSchema } from '../../utility/workspace-models';
12+
13+
describe(`Migration to add 'browser-sync' as a dev dependency`, () => {
14+
const schematicName = 'add-browser-sync-dependency';
15+
const schematicRunner = new SchematicTestRunner(
16+
'migrations',
17+
require.resolve('../migration-collection.json'),
18+
);
19+
20+
let tree: UnitTestTree;
21+
beforeEach(() => {
22+
tree = new UnitTestTree(new EmptyTree());
23+
tree.create(
24+
'/package.json',
25+
JSON.stringify(
26+
{
27+
devDependencies: {},
28+
},
29+
undefined,
30+
2,
31+
),
32+
);
33+
});
34+
35+
it(`should add 'browser-sync' as devDependencies when '@angular-devkit/build-angular:ssr-dev-server' is used`, async () => {
36+
tree.create(
37+
'/angular.json',
38+
JSON.stringify(
39+
{
40+
version: 1,
41+
projects: {
42+
app: {
43+
root: '',
44+
projectType: ProjectType.Application,
45+
prefix: 'app',
46+
architect: {
47+
'serve-ssr': {
48+
builder: Builders.SsrDevServer,
49+
options: {},
50+
},
51+
},
52+
},
53+
},
54+
},
55+
undefined,
56+
2,
57+
),
58+
);
59+
60+
const newTree = await schematicRunner.runSchematic(schematicName, {}, tree);
61+
const { devDependencies } = JSON.parse(newTree.readContent('/package.json'));
62+
expect(devDependencies['browser-sync']).toBe('^2.29.3');
63+
});
64+
65+
it(`should not add 'browser-sync' as devDependencies when '@angular-devkit/build-angular:ssr-dev-server' is not used`, async () => {
66+
tree.create(
67+
'/angular.json',
68+
JSON.stringify(
69+
{
70+
version: 1,
71+
projects: {
72+
app: {
73+
root: '',
74+
projectType: ProjectType.Application,
75+
prefix: 'app',
76+
architect: {
77+
'serve-ssr': {
78+
builder: Builders.Browser,
79+
options: {},
80+
},
81+
},
82+
},
83+
},
84+
},
85+
undefined,
86+
2,
87+
),
88+
);
89+
const newTree = await schematicRunner.runSchematic(schematicName, {}, tree);
90+
const { devDependencies } = JSON.parse(newTree.readContent('/package.json'));
91+
expect(devDependencies['browser-sync']).toBeUndefined();
92+
});
93+
});

0 commit comments

Comments
 (0)