Skip to content

Commit 1c6f665

Browse files
clydinKeen Yee Liau
authored and
Keen Yee Liau
committed
feat(@angular-devkit/build-angular): implement bundle level downleveling to support differential loading
1 parent 4183d16 commit 1c6f665

File tree

21 files changed

+1313
-216
lines changed

21 files changed

+1313
-216
lines changed

packages/angular_devkit/build_angular/package.json

+5
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
"@angular-devkit/build-optimizer": "0.0.0",
1212
"@angular-devkit/build-webpack": "0.0.0",
1313
"@angular-devkit/core": "0.0.0",
14+
"@babel/core": "7.5.5",
15+
"@babel/preset-env": "7.5.5",
1416
"@ngtools/webpack": "0.0.0",
1517
"ajv": "6.10.2",
1618
"autoprefixer": "9.6.1",
@@ -40,20 +42,23 @@
4042
"sass": "1.22.9",
4143
"sass-loader": "7.1.0",
4244
"semver": "6.3.0",
45+
"source-map": "0.7.3",
4346
"source-map-support": "0.5.13",
4447
"source-map-loader": "0.2.4",
4548
"speed-measure-webpack-plugin": "1.3.1",
4649
"style-loader": "0.23.1",
4750
"stylus": "0.54.5",
4851
"stylus-loader": "3.0.2",
4952
"tree-kill": "1.2.1",
53+
"terser": "4.1.3",
5054
"terser-webpack-plugin": "1.4.1",
5155
"webpack": "4.38.0",
5256
"webpack-dev-middleware": "3.7.0",
5357
"webpack-dev-server": "3.7.2",
5458
"webpack-merge": "4.2.1",
5559
"webpack-sources": "1.4.1",
5660
"webpack-subresource-integrity": "1.1.0-rc.6",
61+
"worker-farm": "1.7.0",
5762
"worker-plugin": "3.1.0"
5863
},
5964
"devDependencies": {

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

+34-9
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import {
2323
} from 'webpack';
2424
import { RawSource } from 'webpack-sources';
2525
import { AssetPatternClass, ExtraEntryPoint } from '../../../browser/schema';
26-
import { BuildBrowserFeatures } from '../../../utils/build-browser-features';
26+
import { BuildBrowserFeatures, fullDifferential } from '../../../utils';
2727
import { BundleBudgetPlugin } from '../../plugins/bundle-budget';
2828
import { CleanCssWebpackPlugin } from '../../plugins/cleancss-webpack-plugin';
2929
import { NamedLazyChunksPlugin } from '../../plugins/named-chunks-plugin';
@@ -59,19 +59,23 @@ export function getCommonConfig(wco: WebpackConfigOptions): Configuration {
5959
const entryPoints: { [key: string]: string[] } = {};
6060

6161
const targetInFileName = getEsVersionForFileName(
62-
buildOptions.scriptTargetOverride,
62+
fullDifferential ? buildOptions.scriptTargetOverride : tsConfig.options.target,
6363
buildOptions.esVersionInFileName,
6464
);
6565

6666
if (buildOptions.main) {
6767
entryPoints['main'] = [path.resolve(root, buildOptions.main)];
6868
}
6969

70+
let differentialLoadingNeeded = false;
7071
if (wco.buildOptions.platform !== 'server') {
7172
const buildBrowserFeatures = new BuildBrowserFeatures(
7273
projectRoot,
7374
tsConfig.options.target || ScriptTarget.ES5,
7475
);
76+
77+
differentialLoadingNeeded = buildBrowserFeatures.isDifferentialLoadingNeeded();
78+
7579
if ((buildOptions.scriptTargetOverride || tsConfig.options.target) === ScriptTarget.ES5) {
7680
if (
7781
buildOptions.es5BrowserSupport ||
@@ -90,16 +94,28 @@ export function getCommonConfig(wco: WebpackConfigOptions): Configuration {
9094
: [noModuleScript];
9195
}
9296

93-
// For differential loading we don't need to generate a seperate polyfill file
97+
// For full build differential loading we don't need to generate a seperate polyfill file
9498
// because they will be loaded exclusivly based on module and nomodule
95-
const polyfillsChunkName = buildBrowserFeatures.isDifferentialLoadingNeeded()
96-
? 'polyfills'
97-
: 'polyfills-es5';
99+
const polyfillsChunkName =
100+
fullDifferential && differentialLoadingNeeded ? 'polyfills' : 'polyfills-es5';
98101

99102
entryPoints[polyfillsChunkName] = [path.join(__dirname, '..', 'es5-polyfills.js')];
103+
if (!fullDifferential && differentialLoadingNeeded) {
104+
// Add zone.js legacy support to the es5 polyfills
105+
// This is a noop execution-wise if zone-evergreen is not used.
106+
entryPoints[polyfillsChunkName].push('zone.js/dist/zone-legacy');
107+
}
100108
if (!buildOptions.aot) {
109+
// If not performing a full differential build the JIT polyfills need to be added to ES5
110+
if (!fullDifferential && differentialLoadingNeeded) {
111+
entryPoints[polyfillsChunkName].push(path.join(__dirname, '..', 'jit-polyfills.js'));
112+
}
101113
entryPoints[polyfillsChunkName].push(path.join(__dirname, '..', 'es5-jit-polyfills.js'));
102114
}
115+
// If not performing a full differential build the polyfills need to be added to ES5 bundle
116+
if (!fullDifferential && buildOptions.polyfills) {
117+
entryPoints[polyfillsChunkName].push(path.resolve(root, buildOptions.polyfills));
118+
}
103119
}
104120
}
105121

@@ -316,11 +332,17 @@ export function getCommonConfig(wco: WebpackConfigOptions): Configuration {
316332
}
317333

318334
const terserOptions = {
319-
ecma: wco.supportES2015 ? 6 : 5,
335+
// Use 5 if using bundle downleveling to ensure script bundles do not use ES2015+ features
336+
// Script bundles are shared for differential loading
337+
// Bundle processing will use the ES2015+ optimizations on the ES2015 bundles
338+
ecma:
339+
wco.supportES2015 &&
340+
(!differentialLoadingNeeded || (differentialLoadingNeeded && fullDifferential))
341+
? 6
342+
: 5,
320343
warnings: !!buildOptions.verbose,
321344
safari10: true,
322345
output: {
323-
ascii_only: true,
324346
comments: false,
325347
webkit: true,
326348
},
@@ -339,7 +361,10 @@ export function getCommonConfig(wco: WebpackConfigOptions): Configuration {
339361
global_defs: angularGlobalDefinitions,
340362
},
341363
// We also want to avoid mangling on server.
342-
...(buildOptions.platform == 'server' ? { mangle: false } : {}),
364+
// Name mangling is handled within the browser builder
365+
mangle:
366+
buildOptions.platform !== 'server' &&
367+
(!differentialLoadingNeeded || (differentialLoadingNeeded && fullDifferential)),
343368
};
344369

345370
extraMinimizers.push(

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
NgToolsLoader,
1616
PLATFORM
1717
} from '@ngtools/webpack';
18+
import { fullDifferential } from '../../../utils';
1819
import { WebpackConfigOptions, BuildOptions } from '../build-options';
1920

2021
function _pluginOptionsOverrides(
@@ -32,7 +33,7 @@ function _pluginOptionsOverrides(
3233
}
3334
}
3435

35-
if (buildOptions.scriptTargetOverride) {
36+
if (fullDifferential && buildOptions.scriptTargetOverride) {
3637
compilerOptions.target = buildOptions.scriptTargetOverride;
3738
}
3839

packages/angular_devkit/build_angular/src/angular-cli-files/utilities/index-file/augment-index-html.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,10 @@ export async function augmentIndexHtml(params: AugmentIndexHtmlOptions): Promise
150150
const isModuleType = moduleFiles.some(scriptPredictor);
151151

152152
if (isNoModuleType && !isModuleType) {
153-
attrs.push({ name: 'nomodule', value: null }, { name: 'defer', value: null });
153+
attrs.push({ name: 'nomodule', value: null });
154+
if (!script.startsWith('polyfills-nomodule-es5')) {
155+
attrs.push({ name: 'defer', value: null });
156+
}
154157
} else if (isModuleType && !isNoModuleType) {
155158
attrs.push({ name: 'type', value: 'module' });
156159
} else {

0 commit comments

Comments
 (0)