Skip to content

Commit c5ab880

Browse files
authored
fix(cdk/schematics): support both application and browser builders (#27875)
In #27792 the schematics were updated to use the new default `application` builder instead of the `browser` builder. According to the CLI team we'll have to support both so these changes update our existing logic to account for both cases.
1 parent 2f958ac commit c5ab880

File tree

5 files changed

+106
-17
lines changed

5 files changed

+106
-17
lines changed

src/cdk/schematics/utils/project-index-file.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
*/
88

99
import {Path, workspaces} from '@angular-devkit/core';
10-
import {defaultTargetBuilders, getTargetsByBuilderName} from './project-targets';
10+
import {getProjectBuildTargets} from './project-targets';
1111

1212
/** Gets the path of the index file in the given project. */
1313
export function getProjectIndexFiles(project: workspaces.ProjectDefinition): Path[] {
14-
const paths = getTargetsByBuilderName(project, defaultTargetBuilders.build)
14+
const paths = getProjectBuildTargets(project)
1515
.filter(t => t.options?.['index'])
1616
.map(t => t.options!['index'] as Path);
1717

src/cdk/schematics/utils/project-main-file.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ import {getProjectTargetOptions} from './project-targets';
1313
/** Looks for the main TypeScript file in the given project and returns its path. */
1414
export function getProjectMainFile(project: workspaces.ProjectDefinition): Path {
1515
const buildOptions = getProjectTargetOptions(project, 'build');
16-
const mainPath = buildOptions['browser'] as Path | undefined;
16+
17+
// `browser` is for the `@angular-devkit/build-angular:application` builder while
18+
// `main` is for the `@angular-devkit/build-angular:browser` builder.
19+
const mainPath = (buildOptions['browser'] || buildOptions['main']) as Path | undefined;
1720

1821
if (!mainPath) {
1922
throw new SchematicsException(

src/cdk/schematics/utils/project-targets.ts

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,6 @@
99
import {JsonValue, workspaces} from '@angular-devkit/core';
1010
import {SchematicsException} from '@angular-devkit/schematics';
1111

12-
/** Object that maps a CLI target to its default builder name. */
13-
export const defaultTargetBuilders = {
14-
build: '@angular-devkit/build-angular:application',
15-
test: '@angular-devkit/build-angular:karma',
16-
};
17-
1812
/** Resolves the architect options for the build target of the given project. */
1913
export function getProjectTargetOptions(
2014
project: workspaces.ProjectDefinition,
@@ -31,12 +25,34 @@ export function getProjectTargetOptions(
3125
return options;
3226
}
3327

34-
/** Gets all targets from the given project that match the specified builder name. */
35-
export function getTargetsByBuilderName(
28+
/** Gets all of the default CLI-provided build targets in a project. */
29+
export function getProjectBuildTargets(
30+
project: workspaces.ProjectDefinition,
31+
): workspaces.TargetDefinition[] {
32+
return getTargetsByBuilderName(
33+
project,
34+
builder =>
35+
builder === '@angular-devkit/build-angular:application' ||
36+
builder === '@angular-devkit/build-angular:browser',
37+
);
38+
}
39+
40+
/** Gets all of the default CLI-provided testing targets in a project. */
41+
export function getProjectTestTargets(
42+
project: workspaces.ProjectDefinition,
43+
): workspaces.TargetDefinition[] {
44+
return getTargetsByBuilderName(
45+
project,
46+
builder => builder === '@angular-devkit/build-angular:karma',
47+
);
48+
}
49+
50+
/** Gets all targets from the given project that pass a predicate check. */
51+
function getTargetsByBuilderName(
3652
project: workspaces.ProjectDefinition,
37-
builderName: string,
53+
predicate: (name: string | undefined) => boolean,
3854
): workspaces.TargetDefinition[] {
3955
return Array.from(project.targets.keys())
40-
.filter(name => project.targets.get(name)?.builder === builderName)
56+
.filter(name => predicate(project.targets.get(name)?.builder))
4157
.map(name => project.targets.get(name)!);
4258
}

src/material/schematics/ng-add/index.spec.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,75 @@ describe('ng-add schematic', () => {
599599
expect(buffer.toString()).toContain('<body class="one two">');
600600
});
601601
});
602+
603+
describe('using browser builder', () => {
604+
beforeEach(() => {
605+
const config = {
606+
version: 1,
607+
projects: {
608+
material: {
609+
projectType: 'application',
610+
root: 'projects/material',
611+
sourceRoot: 'projects/material/src',
612+
prefix: 'app',
613+
architect: {
614+
build: {
615+
builder: '@angular-devkit/build-angular:browser',
616+
options: {
617+
outputPath: 'dist/material',
618+
index: 'projects/material/src/index.html',
619+
main: 'projects/material/src/main.ts',
620+
styles: ['projects/material/src/styles.css'],
621+
},
622+
},
623+
test: {
624+
builder: '@angular-devkit/build-angular:karma',
625+
options: {
626+
outputPath: 'dist/material',
627+
index: 'projects/material/src/index.html',
628+
browser: 'projects/material/src/main.ts',
629+
styles: ['projects/material/src/styles.css'],
630+
},
631+
},
632+
},
633+
},
634+
},
635+
};
636+
637+
appTree.overwrite('/angular.json', JSON.stringify(config, null, 2));
638+
});
639+
640+
it('should add a theme', async () => {
641+
const tree = await runner.runSchematic('ng-add-setup-project', baseOptions, appTree);
642+
const workspace = await getWorkspace(tree);
643+
const project = getProjectFromWorkspace(workspace, baseOptions.project);
644+
645+
expectProjectStyleFile(project, '@angular/material/prebuilt-themes/indigo-pink.css');
646+
});
647+
648+
it('should add material app styles', async () => {
649+
const tree = await runner.runSchematic('ng-add-setup-project', baseOptions, appTree);
650+
const workspace = await getWorkspace(tree);
651+
const project = getProjectFromWorkspace(workspace, baseOptions.project);
652+
653+
const defaultStylesPath = getProjectStyleFile(project)!;
654+
const htmlContent = tree.read(defaultStylesPath)!.toString();
655+
656+
expect(htmlContent).toContain('html, body { height: 100%; }');
657+
expect(htmlContent).toContain(
658+
'body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }',
659+
);
660+
});
661+
662+
it('should add the BrowserAnimationsModule to the project module', async () => {
663+
const tree = await runner.runSchematic('ng-add-setup-project', baseOptions, appTree);
664+
const fileContent = getFileContent(tree, '/projects/material/src/app/app.module.ts');
665+
666+
expect(fileContent)
667+
.withContext('Expected the project app module to import the "BrowserAnimationsModule".')
668+
.toContain('BrowserAnimationsModule');
669+
});
670+
});
602671
});
603672

604673
describe('ng-add schematic - library project', () => {

src/material/schematics/ng-add/theming/theming.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@ import {
1717
} from '@angular-devkit/schematics';
1818
import {
1919
addBodyClass,
20-
defaultTargetBuilders,
2120
getProjectFromWorkspace,
2221
getProjectStyleFile,
2322
getProjectTargetOptions,
2423
getProjectIndexFiles,
24+
getProjectTestTargets,
25+
getProjectBuildTargets,
2526
} from '@angular/cdk/schematics';
2627
import {InsertChange} from '@schematics/angular/utility/change';
2728
import {getWorkspace, updateWorkspace} from '@schematics/angular/utility/workspace';
@@ -177,9 +178,9 @@ function validateDefaultTargetBuilder(
177178
targetName: 'build' | 'test',
178179
logger: logging.LoggerApi,
179180
) {
180-
const defaultBuilder = defaultTargetBuilders[targetName];
181-
const targetConfig = project.targets?.get(targetName);
182-
const isDefaultBuilder = targetConfig?.['builder'] === defaultBuilder;
181+
const targets =
182+
targetName === 'test' ? getProjectTestTargets(project) : getProjectBuildTargets(project);
183+
const isDefaultBuilder = targets.length > 0;
183184

184185
// Because the build setup for the Angular CLI can be customized by developers, we can't know
185186
// where to put the theme file in the workspace configuration if custom builders are being

0 commit comments

Comments
 (0)