Skip to content

Commit c560d44

Browse files
committed
fix(@angular/build): allow a default application browser option
The application build system's `browser` option is now considered optional. If not present, the value will be an `main.ts` file within the configured project source root (`sourceRoot`). This change allows the removal of the `browser` option from any project that uses the default generated value.
1 parent cc99b06 commit c560d44

File tree

4 files changed

+57
-10
lines changed

4 files changed

+57
-10
lines changed

goldens/public-api/angular/build/index.api.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export type ApplicationBuilderOptions = {
2525
appShell?: boolean;
2626
assets?: AssetPattern[];
2727
baseHref?: string;
28-
browser: string;
28+
browser?: string;
2929
budgets?: Budget[];
3030
clearScreen?: boolean;
3131
conditions?: string[];

packages/angular/build/src/builders/application/options.ts

+12-8
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,12 @@ export async function normalizeOptions(
177177
i18nOptions.flatOutput = true;
178178
}
179179

180-
const entryPoints = normalizeEntryPoints(workspaceRoot, options.browser, options.entryPoints);
180+
const entryPoints = normalizeEntryPoints(
181+
workspaceRoot,
182+
projectSourceRoot,
183+
options.browser,
184+
options.entryPoints,
185+
);
181186
const tsconfig = path.join(workspaceRoot, options.tsConfig);
182187
const optimizationOptions = normalizeOptimization(options.optimization);
183188
const sourcemapOptions = normalizeSourceMaps(options.sourceMap ?? false);
@@ -545,26 +550,25 @@ async function getTailwindConfig(
545550
*/
546551
function normalizeEntryPoints(
547552
workspaceRoot: string,
553+
projectSourceRoot: string,
548554
browser: string | undefined,
549-
entryPoints: Set<string> | Map<string, string> = new Set(),
555+
entryPoints: Set<string> | Map<string, string> | undefined,
550556
): Record<string, string> {
551557
if (browser === '') {
552558
throw new Error('`browser` option cannot be an empty string.');
553559
}
554560

555561
// `browser` and `entryPoints` are mutually exclusive.
556-
if (browser && entryPoints.size > 0) {
562+
if (browser && entryPoints) {
557563
throw new Error('Only one of `browser` or `entryPoints` may be provided.');
558564
}
559-
if (!browser && entryPoints.size === 0) {
560-
// Schema should normally reject this case, but programmatic usages of the builder might make this mistake.
561-
throw new Error('Either `browser` or at least one `entryPoints` value must be provided.');
562-
}
563565

564-
// Schema types force `browser` to always be provided, but it may be omitted when the builder is invoked programmatically.
565566
if (browser) {
566567
// Use `browser` alone.
567568
return { 'main': path.join(workspaceRoot, browser) };
569+
} else if (!entryPoints) {
570+
// Default browser entry if no explicit entry points
571+
return { 'main': path.join(projectSourceRoot, 'main.ts') };
568572
} else if (entryPoints instanceof Map) {
569573
return Object.fromEntries(
570574
Array.from(entryPoints.entries(), ([name, entryPoint]) => {

packages/angular/build/src/builders/application/schema.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -616,7 +616,7 @@
616616
}
617617
},
618618
"additionalProperties": false,
619-
"required": ["browser", "tsConfig"],
619+
"required": ["tsConfig"],
620620
"definitions": {
621621
"assetPattern": {
622622
"oneOf": [

packages/angular/build/src/builders/application/tests/options/browser_spec.ts

+43
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,49 @@ describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => {
4242
harness.expectFile('dist/browser/main.js').content.toContain('console.log("main")');
4343
});
4444

45+
it('defaults to use `src/main.ts` if not present', async () => {
46+
harness.useTarget('build', {
47+
...BASE_OPTIONS,
48+
browser: undefined,
49+
});
50+
51+
const { result } = await harness.executeOnce();
52+
53+
expect(result?.success).toBe(true);
54+
55+
harness.expectFile('dist/browser/main.js').toExist();
56+
harness.expectFile('dist/browser/index.html').toExist();
57+
});
58+
59+
it('uses project source root in default if `browser` not present', async () => {
60+
harness.useProject('test', {
61+
root: '.',
62+
sourceRoot: 'source',
63+
cli: {
64+
cache: {
65+
enabled: false,
66+
},
67+
},
68+
});
69+
harness.useTarget('build', {
70+
...BASE_OPTIONS,
71+
browser: undefined,
72+
index: false,
73+
});
74+
75+
// Update app for a `source/main.ts` file based on the above changed `sourceRoot`
76+
await harness.writeFile('source/main.ts', `console.log('main');`);
77+
await harness.modifyFile('src/tsconfig.app.json', (content) =>
78+
content.replace('main.ts', '../source/main.ts'),
79+
);
80+
81+
const { result } = await harness.executeOnce();
82+
83+
expect(result?.success).toBe(true);
84+
85+
harness.expectFile('dist/browser/main.js').content.toContain('console.log("main")');
86+
});
87+
4588
it('fails and shows an error when file does not exist', async () => {
4689
harness.useTarget('build', {
4790
...BASE_OPTIONS,

0 commit comments

Comments
 (0)