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 #26349
  • Loading branch information
alan-agius4 authored and clydin committed Dec 6, 2023
1 parent 10588c2 commit 364a16b
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 6 deletions.
5 changes: 4 additions & 1 deletion packages/angular_devkit/build_angular/package.json
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
Expand Up @@ -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`
****************************************************************************************
Expand Down
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
@@ -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,
});
}
}
}
};
}
@@ -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();
});
});
18 changes: 14 additions & 4 deletions packages/schematics/angular/ssr/index.ts
Expand Up @@ -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,
}),
Expand All @@ -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 {
Expand Down Expand Up @@ -288,7 +298,7 @@ export default function (options: SSROptions): Rule {
]),
addServerFile(options, isStandalone),
addScriptsRule(options, isUsingApplicationBuilder),
addDependencies(),
addDependencies(isUsingApplicationBuilder),
]);
};
}
Expand Up @@ -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",
Expand Down

0 comments on commit 364a16b

Please sign in to comment.