Skip to content

Commit 397fe68

Browse files
committed
feat(@angular-devkit/build-angular): conditional ES2015 polyfill loading
1 parent 3a9230f commit 397fe68

File tree

10 files changed

+86
-9
lines changed

10 files changed

+86
-9
lines changed

packages/angular/cli/lib/config/schema.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -863,6 +863,11 @@
863863
"$ref": "#/definitions/targetOptions/definitions/browser/definitions/budget"
864864
},
865865
"default": []
866+
},
867+
"es5BrowserSupport": {
868+
"description": "Enables conditionally loaded ES2015 polyfills.",
869+
"type": "boolean",
870+
"default": false
866871
}
867872
},
868873
"additionalProperties": false,

packages/angular_devkit/build_angular/src/angular-cli-files/models/build-options.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ export interface BuildOptions {
5858
statsJson: boolean;
5959
forkTypeChecker: boolean;
6060
profile?: boolean;
61+
es5BrowserSupport?: boolean;
6162

6263
main: string;
6364
index: string;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. 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+
import 'core-js/es6/reflect';
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. 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+
import 'core-js/es6/symbol';
9+
import 'core-js/es6/object';
10+
import 'core-js/es6/function';
11+
import 'core-js/es6/parse-int';
12+
import 'core-js/es6/parse-float';
13+
import 'core-js/es6/number';
14+
import 'core-js/es6/math';
15+
import 'core-js/es6/string';
16+
import 'core-js/es6/date';
17+
import 'core-js/es6/array';
18+
import 'core-js/es6/regexp';
19+
import 'core-js/es6/map';
20+
import 'core-js/es6/weak-map';
21+
import 'core-js/es6/set';

packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/browser.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ export function getBrowserConfig(wco: WebpackConfigOptions) {
4444
entrypoints: generateEntryPoints(buildOptions),
4545
deployUrl: buildOptions.deployUrl,
4646
sri: buildOptions.subresourceIntegrity,
47+
noModuleEntrypoints: ['es2015-polyfills'],
4748
}));
4849
}
4950

@@ -112,7 +113,7 @@ export function getBrowserConfig(wco: WebpackConfigOptions) {
112113
const moduleName = module.nameForCondition ? module.nameForCondition() : '';
113114

114115
return /[\\/]node_modules[\\/]/.test(moduleName)
115-
&& !chunks.some(({ name }) => name === 'polyfills'
116+
&& !chunks.some(({ name }) => name === 'polyfills' || name === 'es2015-polyfills'
116117
|| globalStylesBundleNames.includes(name));
117118
},
118119
},

packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/common.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ export function getCommonConfig(wco: WebpackConfigOptions) {
5353
entryPoints['main'] = [path.resolve(root, buildOptions.main)];
5454
}
5555

56+
if (buildOptions.es5BrowserSupport) {
57+
entryPoints['es2015-polyfills'] = [path.join(__dirname, '..', 'es2015-polyfills.js')];
58+
}
59+
5660
if (buildOptions.polyfills) {
5761
entryPoints['polyfills'] = [path.resolve(root, buildOptions.polyfills)];
5862
}
@@ -62,6 +66,13 @@ export function getCommonConfig(wco: WebpackConfigOptions) {
6266
...(entryPoints['polyfills'] || []),
6367
path.join(__dirname, '..', 'jit-polyfills.js'),
6468
];
69+
70+
if (buildOptions.es5BrowserSupport) {
71+
entryPoints['es2015-polyfills'] = [
72+
...entryPoints['es2015-polyfills'],
73+
path.join(__dirname, '..', 'es2015-jit-polyfills.js'),
74+
];
75+
}
6576
}
6677

6778
if (buildOptions.profile) {

packages/angular_devkit/build_angular/src/angular-cli-files/plugins/index-html-webpack-plugin.ts

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export interface IndexHtmlWebpackPluginOptions {
1818
entrypoints: string[];
1919
deployUrl?: string;
2020
sri: boolean;
21+
noModuleEntrypoints: string[];
2122
}
2223

2324
function readFile(filename: string, compilation: compilation.Compilation): Promise<string> {
@@ -53,6 +54,7 @@ export class IndexHtmlWebpackPlugin {
5354
input: 'index.html',
5455
output: 'index.html',
5556
entrypoints: ['polyfills', 'main'],
57+
noModuleEntrypoints: [],
5658
sri: false,
5759
...options,
5860
};
@@ -67,14 +69,26 @@ export class IndexHtmlWebpackPlugin {
6769

6870

6971
// Get all files for selected entrypoints
70-
let unfilteredSortedFiles: string[] = [];
72+
const unfilteredSortedFiles: string[] = [];
73+
const noModuleFiles = new Set<string>();
74+
const otherFiles = new Set<string>();
7175
for (const entryName of this._options.entrypoints) {
7276
const entrypoint = compilation.entrypoints.get(entryName);
7377
if (entrypoint && entrypoint.getFiles) {
74-
unfilteredSortedFiles = unfilteredSortedFiles.concat(entrypoint.getFiles() || []);
78+
const files: string[] = entrypoint.getFiles() || [];
79+
unfilteredSortedFiles.push(...files);
80+
81+
if (this._options.noModuleEntrypoints.includes(entryName)) {
82+
files.forEach(file => noModuleFiles.add(file));
83+
} else {
84+
files.forEach(file => otherFiles.add(file));
85+
}
7586
}
7687
}
7788

89+
// Clean out files that are used in all types of entrypoints
90+
otherFiles.forEach(file => noModuleFiles.delete(file));
91+
7892
// Filter files
7993
const existingFiles = new Set<string>();
8094
const stylesheets: string[] = [];
@@ -137,25 +151,31 @@ export class IndexHtmlWebpackPlugin {
137151
// Inject into the html
138152
const indexSource = new ReplaceSource(new RawSource(inputContent), this._options.input);
139153

140-
const scriptElements = treeAdapter.createDocumentFragment();
154+
let scriptElements = '';
141155
for (const script of scripts) {
142-
const attrs = [
156+
const attrs: { name: string, value: string | null }[] = [
143157
{ name: 'type', value: 'text/javascript' },
144158
{ name: 'src', value: (this._options.deployUrl || '') + script },
145159
];
146160

161+
if (noModuleFiles.has(script)) {
162+
attrs.push({ name: 'nomodule', value: null });
163+
}
164+
147165
if (this._options.sri) {
148166
const content = compilation.assets[script].source();
149167
attrs.push(...this._generateSriAttributes(content));
150168
}
151169

152-
const element = treeAdapter.createElement('script', undefined, attrs);
153-
treeAdapter.appendChild(scriptElements, element);
170+
const attributes = attrs
171+
.map(attr => attr.value === null ? attr.name : `${attr.name}="${attr.value}"`)
172+
.join(' ');
173+
scriptElements += `<script ${attributes}></script>`;
154174
}
155175

156176
indexSource.insert(
157177
scriptInsertionPoint,
158-
parse5.serialize(scriptElements, { treeAdapter }),
178+
scriptElements,
159179
);
160180

161181
// Adjust base href if specified

packages/angular_devkit/build_angular/src/angular-cli-files/utilities/package-chunk-sort.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { normalizeExtraEntryPoints } from '../models/webpack-configs/utils';
1111
export function generateEntryPoints(
1212
appConfig: { styles: ExtraEntryPoint[], scripts: ExtraEntryPoint[] },
1313
) {
14-
const entryPoints = ['polyfills', 'sw-register'];
14+
const entryPoints = ['es2015-polyfills', 'polyfills', 'sw-register'];
1515

1616
// Add all styles/scripts, except lazy-loaded ones.
1717
[

packages/angular_devkit/build_angular/src/browser/schema.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,11 @@ export interface BrowserBuilderSchema {
236236
* Output profile events for Chrome profiler.
237237
*/
238238
profile: boolean;
239+
240+
/**
241+
* Enables conditionally loaded IE9-11 polyfills.
242+
*/
243+
es5BrowserSupport: boolean;
239244
}
240245

241246
export type OptimizationOptions = boolean | OptimizationObject;

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,11 @@
299299
"type": "boolean",
300300
"description": "Output profile events for Chrome profiler.",
301301
"default": false
302+
},
303+
"es5BrowserSupport": {
304+
"description": "Enables conditionally loaded ES2015 polyfills.",
305+
"type": "boolean",
306+
"default": false
302307
}
303308
},
304309
"additionalProperties": false,

0 commit comments

Comments
 (0)