Skip to content

Commit c592ec5

Browse files
committed
feat(@angular-devkit/build-angular): amend polyfills option in all builders to support an array of module specifiers
This is the ground work to be able to remove the `polyfills.ts` file which today is primarily used to add `zone.js`. Usage examples: ```js polyfills: ['zone.js'], polyfills: ['zone.js', 'zone.js/testing', 'src/polyfills.ts'], ```
1 parent f393b09 commit c592ec5

File tree

10 files changed

+114
-23
lines changed

10 files changed

+114
-23
lines changed

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ export interface BrowserBuilderOptions {
5353
outputHashing?: OutputHashing;
5454
outputPath: string;
5555
poll?: number;
56-
polyfills?: string;
56+
polyfills?: Polyfills;
5757
preserveSymlinks?: boolean;
5858
progress?: boolean;
5959
resourcesOutputPath?: string;
@@ -180,7 +180,7 @@ export interface KarmaBuilderOptions {
180180
karmaConfig: string;
181181
main: string;
182182
poll?: number;
183-
polyfills?: string;
183+
polyfills?: Polyfills_2;
184184
preserveSymlinks?: boolean;
185185
progress?: boolean;
186186
reporters?: string[];

packages/angular_devkit/build_angular/src/builders/browser-esbuild/options.ts

+14-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import { BuilderContext } from '@angular-devkit/architect';
1010
import * as path from 'path';
1111
import { normalizeAssetPatterns, normalizeOptimization, normalizeSourceMaps } from '../../utils';
12+
import { normalizePolyfills } from '../../utils/normalize-polyfills';
1213
import { Schema as BrowserBuilderOptions, OutputHashing } from '../browser/schema';
1314

1415
/**
@@ -33,10 +34,21 @@ export async function normalizeOptions(
3334
workspaceRoot,
3435
(projectMetadata.sourceRoot as string | undefined) ?? 'src',
3536
);
36-
3737
// Normalize options
3838
const mainEntryPoint = path.join(workspaceRoot, options.main);
39-
const polyfillsEntryPoint = options.polyfills && path.join(workspaceRoot, options.polyfills);
39+
40+
// Currently esbuild do not support multiple files per entry-point
41+
const [polyfillsEntryPoint, ...remainingPolyfills] = normalizePolyfills(
42+
options.polyfills,
43+
workspaceRoot,
44+
);
45+
46+
if (remainingPolyfills.length) {
47+
context.logger.warn(
48+
`The 'polyfills' option currently does not support multiple entries by this experimental builder. The first entry will be used.`,
49+
);
50+
}
51+
4052
const tsconfig = path.join(workspaceRoot, options.tsConfig);
4153
const outputPath = path.join(workspaceRoot, options.outputPath);
4254
const optimizationOptions = normalizeOptimization(options.optimization);

packages/angular_devkit/build_angular/src/builders/browser-esbuild/schema.json

+16-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,22 @@
1717
"description": "The full path for the main entry point to the app, relative to the current workspace."
1818
},
1919
"polyfills": {
20-
"type": "string",
21-
"description": "The full path for the polyfills file, relative to the current workspace."
20+
"description": "Polyfills to be included in the build.",
21+
"oneOf": [
22+
{
23+
"type": "array",
24+
"description": "A list of polyfills to include in the build. Can be a full path for a file, relative to the current workspace or module specifier. Example: 'zone.js'.",
25+
"items": {
26+
"type": "string",
27+
"uniqueItems": true
28+
},
29+
"default": []
30+
},
31+
{
32+
"type": "string",
33+
"description": "The full path for the polyfills file, relative to the current workspace or a module specifier. Example: 'zone.js'."
34+
}
35+
]
2236
},
2337
"tsConfig": {
2438
"type": "string",

packages/angular_devkit/build_angular/src/builders/browser/schema.json

+16-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,22 @@
1717
"description": "The full path for the main entry point to the app, relative to the current workspace."
1818
},
1919
"polyfills": {
20-
"type": "string",
21-
"description": "The full path for the polyfills file, relative to the current workspace."
20+
"description": "Polyfills to be included in the build.",
21+
"oneOf": [
22+
{
23+
"type": "array",
24+
"description": "A list of polyfills to include in the build. Can be a full path for a file, relative to the current workspace or module specifier. Example: 'zone.js'.",
25+
"items": {
26+
"type": "string",
27+
"uniqueItems": true
28+
},
29+
"default": []
30+
},
31+
{
32+
"type": "string",
33+
"description": "The full path for the polyfills file, relative to the current workspace or a module specifier. Example: 'zone.js'."
34+
}
35+
]
2236
},
2337
"tsConfig": {
2438
"type": "string",

packages/angular_devkit/build_angular/src/builders/browser/tests/options/polyfills_spec.ts

+11
Original file line numberDiff line numberDiff line change
@@ -54,5 +54,16 @@ describeBuilder(buildWebpackBrowser, BROWSER_BUILDER_INFO, (harness) => {
5454

5555
harness.expectFile('dist/polyfills.js').toNotExist();
5656
});
57+
58+
it('resolves module specifiers in array', async () => {
59+
harness.useTarget('build', {
60+
...BASE_OPTIONS,
61+
polyfills: ['zone.js', 'zone.js/testing'],
62+
});
63+
64+
const { result } = await harness.executeOnce();
65+
expect(result?.success).toBeTrue();
66+
harness.expectFile('dist/polyfills.js').toExist();
67+
});
5768
});
5869
});

packages/angular_devkit/build_angular/src/builders/karma/schema.json

+16-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,22 @@
1717
"description": "The name of the Karma configuration file."
1818
},
1919
"polyfills": {
20-
"type": "string",
21-
"description": "The name of the polyfills file."
20+
"description": "Polyfills to be included in the build.",
21+
"oneOf": [
22+
{
23+
"type": "array",
24+
"description": "A list of polyfills to include in the build. Can be a full path for a file, relative to the current workspace or module specifier. Example: 'zone.js'.",
25+
"items": {
26+
"type": "string",
27+
"uniqueItems": true
28+
},
29+
"default": []
30+
},
31+
{
32+
"type": "string",
33+
"description": "The full path for the polyfills file, relative to the current workspace or a module specifier. Example: 'zone.js'."
34+
}
35+
]
2236
},
2337
"assets": {
2438
"type": "array",

packages/angular_devkit/build_angular/src/utils/build-options.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export interface BuildOptions {
5858
statsJson: boolean;
5959
hmr?: boolean;
6060
main: string;
61-
polyfills?: string;
61+
polyfills: string[];
6262
budgets: Budget[];
6363
assets: AssetPatternClass[];
6464
scripts: ScriptElement[];

packages/angular_devkit/build_angular/src/utils/normalize-builder-schema.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
normalizeFileReplacements,
2121
} from './normalize-file-replacements';
2222
import { NormalizedOptimizationOptions, normalizeOptimization } from './normalize-optimization';
23+
import { normalizePolyfills } from './normalize-polyfills';
2324
import { normalizeSourceMaps } from './normalize-source-maps';
2425
import { getSupportedBrowsers } from './supported-browsers';
2526

@@ -32,6 +33,7 @@ export type NormalizedBrowserBuilderSchema = BrowserBuilderSchema &
3233
assets: AssetPatternClass[];
3334
fileReplacements: NormalizedFileReplacement[];
3435
optimization: NormalizedOptimizationOptions;
36+
polyfills: string[];
3537
};
3638

3739
export function normalizeBrowserSchema(
@@ -42,8 +44,6 @@ export function normalizeBrowserSchema(
4244
metadata: json.JsonObject,
4345
logger: logging.LoggerApi,
4446
): NormalizedBrowserBuilderSchema {
45-
const normalizedSourceMapOptions = normalizeSourceMaps(options.sourceMap || false);
46-
4747
return {
4848
...options,
4949
cache: normalizeCacheOptions(metadata, workspaceRoot),
@@ -55,7 +55,8 @@ export function normalizeBrowserSchema(
5555
),
5656
fileReplacements: normalizeFileReplacements(options.fileReplacements || [], workspaceRoot),
5757
optimization: normalizeOptimization(options.optimization),
58-
sourceMap: normalizedSourceMapOptions,
58+
sourceMap: normalizeSourceMaps(options.sourceMap || false),
59+
polyfills: normalizePolyfills(options.polyfills, workspaceRoot),
5960
preserveSymlinks:
6061
options.preserveSymlinks === undefined
6162
? process.execArgv.includes('--preserve-symlinks')
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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 { existsSync } from 'fs';
10+
import { resolve } from 'path';
11+
12+
export function normalizePolyfills(
13+
polyfills: string[] | string | undefined,
14+
root: string,
15+
): string[] {
16+
if (!polyfills) {
17+
return [];
18+
}
19+
20+
const polyfillsList = Array.isArray(polyfills) ? polyfills : [polyfills];
21+
22+
return polyfillsList.map((p) => {
23+
const resolvedPath = resolve(root, p);
24+
25+
// If file doesn't exist, let the bundle resolve it using node module resolution.
26+
return existsSync(resolvedPath) ? resolvedPath : p;
27+
});
28+
}

packages/angular_devkit/build_angular/src/webpack/configs/common.ts

+6-9
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ export async function getCommonConfig(wco: WebpackConfigOptions): Promise<Config
7777
const isPlatformServer = buildOptions.platform === 'server';
7878
const extraPlugins: { apply(compiler: Compiler): void }[] = [];
7979
const extraRules: RuleSetRule[] = [];
80-
const entryPoints: { [key: string]: [string, ...string[]] } = {};
80+
const entryPoints: Configuration['entry'] = {};
8181

8282
// Load ESM `@angular/compiler-cli` using the TypeScript dynamic import workaround.
8383
// Once TypeScript provides support for keeping the dynamic import this workaround can be
@@ -105,14 +105,11 @@ export async function getCommonConfig(wco: WebpackConfigOptions): Promise<Config
105105
extraPlugins.push(new ContextReplacementPlugin(/@?hapi|express[\\/]/));
106106
}
107107

108-
if (!isPlatformServer) {
109-
if (buildOptions.polyfills) {
110-
const projectPolyfills = path.resolve(root, buildOptions.polyfills);
111-
if (entryPoints['polyfills']) {
112-
entryPoints['polyfills'].push(projectPolyfills);
113-
} else {
114-
entryPoints['polyfills'] = [projectPolyfills];
115-
}
108+
if (buildOptions.polyfills.length) {
109+
if (Array.isArray(entryPoints['polyfills'])) {
110+
entryPoints['polyfills'].push(...buildOptions.polyfills);
111+
} else {
112+
entryPoints['polyfills'] = buildOptions.polyfills;
116113
}
117114
}
118115

0 commit comments

Comments
 (0)