@angular-devkit/build-angular 0.900.0-rc.7 → 0.900.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +18 -19
- package/src/angular-cli-files/models/build-options.d.ts +2 -1
- package/src/angular-cli-files/models/es5-polyfills.js +4 -1
- package/src/angular-cli-files/models/webpack-configs/browser.js +17 -9
- package/src/angular-cli-files/models/webpack-configs/common.js +34 -31
- package/src/angular-cli-files/models/webpack-configs/test.js +1 -2
- package/src/angular-cli-files/models/webpack-configs/typescript.js +4 -1
- package/src/angular-cli-files/plugins/{cleancss-webpack-plugin.d.ts → optimize-css-webpack-plugin.d.ts} +3 -3
- package/src/angular-cli-files/plugins/{cleancss-webpack-plugin.js → optimize-css-webpack-plugin.js} +26 -36
- package/src/angular-cli-files/plugins/webpack.d.ts +1 -1
- package/src/angular-cli-files/plugins/webpack.js +2 -2
- package/src/browser/index.js +2 -6
- package/src/dev-server/index.js +1 -0
- package/src/protractor/index.js +7 -14
- package/src/utils/action-cache.d.ts +1 -1
- package/src/utils/action-cache.js +13 -9
- package/src/utils/build-browser-features.d.ts +1 -1
- package/src/utils/build-browser-features.js +3 -3
- package/src/utils/environment-options.d.ts +3 -1
- package/src/utils/environment-options.js +48 -5
- package/src/utils/process-bundle.d.ts +2 -1
- package/src/utils/process-bundle.js +97 -111
- package/src/utils/webpack-browser-config.js +21 -0
package/package.json
CHANGED
|
@@ -1,34 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@angular-devkit/build-angular",
|
|
3
|
-
"version": "0.900.
|
|
3
|
+
"version": "0.900.1",
|
|
4
4
|
"description": "Angular Webpack Build Facade",
|
|
5
5
|
"experimental": true,
|
|
6
6
|
"main": "src/index.js",
|
|
7
7
|
"typings": "src/index.d.ts",
|
|
8
8
|
"builders": "builders.json",
|
|
9
9
|
"dependencies": {
|
|
10
|
-
"@angular-devkit/architect": "0.900.
|
|
11
|
-
"@angular-devkit/build-optimizer": "0.900.
|
|
12
|
-
"@angular-devkit/build-webpack": "0.900.
|
|
13
|
-
"@angular-devkit/core": "9.0.
|
|
14
|
-
"@babel/core": "7.7.
|
|
15
|
-
"@babel/generator": "7.7.
|
|
16
|
-
"@babel/preset-env": "7.7.
|
|
17
|
-
"@ngtools/webpack": "9.0.
|
|
10
|
+
"@angular-devkit/architect": "0.900.1",
|
|
11
|
+
"@angular-devkit/build-optimizer": "0.900.1",
|
|
12
|
+
"@angular-devkit/build-webpack": "0.900.1",
|
|
13
|
+
"@angular-devkit/core": "9.0.1",
|
|
14
|
+
"@babel/core": "7.7.7",
|
|
15
|
+
"@babel/generator": "7.7.7",
|
|
16
|
+
"@babel/preset-env": "7.7.7",
|
|
17
|
+
"@ngtools/webpack": "9.0.1",
|
|
18
18
|
"ajv": "6.10.2",
|
|
19
19
|
"autoprefixer": "9.7.1",
|
|
20
20
|
"babel-loader": "8.0.6",
|
|
21
|
-
"browserslist": "4.
|
|
21
|
+
"browserslist": "4.8.3",
|
|
22
22
|
"cacache": "13.0.1",
|
|
23
|
-
"caniuse-lite": "1.0.
|
|
23
|
+
"caniuse-lite": "1.0.30001020",
|
|
24
|
+
"cssnano": "4.1.10",
|
|
24
25
|
"circular-dependency-plugin": "5.2.0",
|
|
25
|
-
"
|
|
26
|
+
"coverage-istanbul-loader": "2.0.3",
|
|
26
27
|
"copy-webpack-plugin": "5.1.1",
|
|
27
|
-
"core-js": "3.
|
|
28
|
+
"core-js": "3.6.0",
|
|
28
29
|
"file-loader": "4.2.0",
|
|
29
30
|
"find-cache-dir": "3.0.0",
|
|
30
31
|
"glob": "7.1.5",
|
|
31
|
-
"istanbul-instrumenter-loader": "3.0.1",
|
|
32
32
|
"jest-worker": "24.9.0",
|
|
33
33
|
"karma-source-map-support": "1.4.0",
|
|
34
34
|
"less": "3.10.3",
|
|
@@ -58,9 +58,9 @@
|
|
|
58
58
|
"style-loader": "1.0.0",
|
|
59
59
|
"stylus": "0.54.7",
|
|
60
60
|
"stylus-loader": "3.0.2",
|
|
61
|
-
"tree-kill": "1.2.
|
|
62
|
-
"terser": "4.
|
|
63
|
-
"terser-webpack-plugin": "2.
|
|
61
|
+
"tree-kill": "1.2.2",
|
|
62
|
+
"terser": "4.5.1",
|
|
63
|
+
"terser-webpack-plugin": "2.3.3",
|
|
64
64
|
"webpack": "4.41.2",
|
|
65
65
|
"webpack-dev-middleware": "3.7.2",
|
|
66
66
|
"webpack-dev-server": "3.9.0",
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
},
|
|
72
72
|
"peerDependencies": {
|
|
73
73
|
"@angular/compiler-cli": ">=9.0.0-beta < 10",
|
|
74
|
-
"typescript": ">=3.6 < 3.
|
|
74
|
+
"typescript": ">=3.6 < 3.8"
|
|
75
75
|
},
|
|
76
76
|
"peerDependenciesMeta": {
|
|
77
77
|
"@angular/localize": {
|
|
@@ -92,7 +92,6 @@
|
|
|
92
92
|
"engines": {
|
|
93
93
|
"node": ">= 10.13.0",
|
|
94
94
|
"npm": ">= 6.11.0",
|
|
95
|
-
"pnpm": ">= 3.2.0",
|
|
96
95
|
"yarn": ">= 1.13.0"
|
|
97
96
|
},
|
|
98
97
|
"author": "Angular Authors",
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { logging } from '@angular-devkit/core';
|
|
9
9
|
import { ParsedConfiguration } from '@angular/compiler-cli';
|
|
10
|
-
import { AssetPatternClass, Budget, ExtraEntryPoint, I18NMissingTranslation, Localize, OptimizationClass, SourceMapClass } from '../../browser/schema';
|
|
10
|
+
import { AssetPatternClass, Budget, CrossOrigin, ExtraEntryPoint, I18NMissingTranslation, Localize, OptimizationClass, SourceMapClass } from '../../browser/schema';
|
|
11
11
|
import { NormalizedFileReplacement } from '../../utils/normalize-file-replacements';
|
|
12
12
|
export interface BuildOptions {
|
|
13
13
|
optimization: OptimizationClass;
|
|
@@ -46,6 +46,7 @@ export interface BuildOptions {
|
|
|
46
46
|
showCircularDependencies?: boolean;
|
|
47
47
|
buildOptimizer?: boolean;
|
|
48
48
|
namedChunks?: boolean;
|
|
49
|
+
crossOrigin?: CrossOrigin;
|
|
49
50
|
subresourceIntegrity?: boolean;
|
|
50
51
|
serviceWorker?: boolean;
|
|
51
52
|
webWorkerTsConfig?: string;
|
|
@@ -91,7 +91,10 @@ import 'core-js/modules/es.parse-float';
|
|
|
91
91
|
import 'core-js/es/number';
|
|
92
92
|
import 'core-js/es/math';
|
|
93
93
|
import 'core-js/es/date';
|
|
94
|
-
|
|
94
|
+
|
|
95
|
+
import 'core-js/modules/es.regexp.constructor';
|
|
96
|
+
import 'core-js/modules/es.regexp.to-string';
|
|
97
|
+
import 'core-js/modules/es.regexp.flags';
|
|
95
98
|
|
|
96
99
|
import 'core-js/modules/es.map';
|
|
97
100
|
import 'core-js/modules/es.weak-map';
|
|
@@ -12,38 +12,46 @@ const utils_1 = require("./utils");
|
|
|
12
12
|
const SubresourceIntegrityPlugin = require('webpack-subresource-integrity');
|
|
13
13
|
function getBrowserConfig(wco) {
|
|
14
14
|
const { buildOptions } = wco;
|
|
15
|
+
const { crossOrigin = 'none', subresourceIntegrity, evalSourceMap, extractLicenses, vendorChunk, commonChunk, styles, } = buildOptions;
|
|
15
16
|
const extraPlugins = [];
|
|
16
17
|
let isEval = false;
|
|
17
18
|
const { styles: stylesOptimization, scripts: scriptsOptimization } = buildOptions.optimization;
|
|
18
19
|
const { styles: stylesSourceMap, scripts: scriptsSourceMap, hidden: hiddenSourceMap, } = buildOptions.sourceMap;
|
|
19
20
|
// See https://webpack.js.org/configuration/devtool/ for sourcemap types.
|
|
20
21
|
if ((stylesSourceMap || scriptsSourceMap) &&
|
|
21
|
-
|
|
22
|
+
evalSourceMap &&
|
|
22
23
|
!stylesOptimization &&
|
|
23
24
|
!scriptsOptimization) {
|
|
24
25
|
// Produce eval sourcemaps for development with serve, which are faster.
|
|
25
26
|
isEval = true;
|
|
26
27
|
}
|
|
27
|
-
if (
|
|
28
|
+
if (subresourceIntegrity) {
|
|
28
29
|
extraPlugins.push(new SubresourceIntegrityPlugin({
|
|
29
30
|
hashFuncNames: ['sha384'],
|
|
30
31
|
}));
|
|
31
32
|
}
|
|
32
|
-
if (
|
|
33
|
+
if (extractLicenses) {
|
|
33
34
|
extraPlugins.push(new license_webpack_plugin_1.LicenseWebpackPlugin({
|
|
34
35
|
stats: {
|
|
35
36
|
warnings: false,
|
|
36
37
|
errors: false,
|
|
37
38
|
},
|
|
38
39
|
perChunkOutput: false,
|
|
39
|
-
outputFilename:
|
|
40
|
+
outputFilename: '3rdpartylicenses.txt',
|
|
40
41
|
}));
|
|
41
42
|
}
|
|
42
43
|
if (!isEval && (scriptsSourceMap || stylesSourceMap)) {
|
|
43
44
|
extraPlugins.push(utils_1.getSourceMapDevTool(scriptsSourceMap, stylesSourceMap, wco.differentialLoadingMode ? true : hiddenSourceMap));
|
|
44
45
|
}
|
|
45
|
-
const globalStylesBundleNames = utils_1.normalizeExtraEntryPoints(
|
|
46
|
+
const globalStylesBundleNames = utils_1.normalizeExtraEntryPoints(styles, 'styles')
|
|
46
47
|
.map(style => style.bundleName);
|
|
48
|
+
let crossOriginLoading = false;
|
|
49
|
+
if (subresourceIntegrity && crossOrigin === 'none') {
|
|
50
|
+
crossOriginLoading = 'anonymous';
|
|
51
|
+
}
|
|
52
|
+
else if (crossOrigin !== 'none') {
|
|
53
|
+
crossOriginLoading = crossOrigin;
|
|
54
|
+
}
|
|
47
55
|
return {
|
|
48
56
|
devtool: isEval ? 'eval' : false,
|
|
49
57
|
resolve: {
|
|
@@ -53,19 +61,19 @@ function getBrowserConfig(wco) {
|
|
|
53
61
|
],
|
|
54
62
|
},
|
|
55
63
|
output: {
|
|
56
|
-
crossOriginLoading
|
|
64
|
+
crossOriginLoading,
|
|
57
65
|
},
|
|
58
66
|
optimization: {
|
|
59
67
|
runtimeChunk: 'single',
|
|
60
68
|
splitChunks: {
|
|
61
69
|
maxAsyncRequests: Infinity,
|
|
62
70
|
cacheGroups: {
|
|
63
|
-
default: !!
|
|
71
|
+
default: !!commonChunk && {
|
|
64
72
|
chunks: 'async',
|
|
65
73
|
minChunks: 2,
|
|
66
74
|
priority: 10,
|
|
67
75
|
},
|
|
68
|
-
common: !!
|
|
76
|
+
common: !!commonChunk && {
|
|
69
77
|
name: 'common',
|
|
70
78
|
chunks: 'async',
|
|
71
79
|
minChunks: 2,
|
|
@@ -73,7 +81,7 @@ function getBrowserConfig(wco) {
|
|
|
73
81
|
priority: 5,
|
|
74
82
|
},
|
|
75
83
|
vendors: false,
|
|
76
|
-
vendor: !!
|
|
84
|
+
vendor: !!vendorChunk && {
|
|
77
85
|
name: 'vendor',
|
|
78
86
|
chunks: 'initial',
|
|
79
87
|
enforce: true,
|
|
@@ -10,6 +10,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
10
10
|
const build_optimizer_1 = require("@angular-devkit/build-optimizer");
|
|
11
11
|
const core_1 = require("@angular-devkit/core");
|
|
12
12
|
const CopyWebpackPlugin = require("copy-webpack-plugin");
|
|
13
|
+
const fs_1 = require("fs");
|
|
13
14
|
const path = require("path");
|
|
14
15
|
const typescript_1 = require("typescript");
|
|
15
16
|
const webpack_1 = require("webpack");
|
|
@@ -18,8 +19,8 @@ const utils_1 = require("../../../utils");
|
|
|
18
19
|
const cache_path_1 = require("../../../utils/cache-path");
|
|
19
20
|
const environment_options_1 = require("../../../utils/environment-options");
|
|
20
21
|
const bundle_budget_1 = require("../../plugins/bundle-budget");
|
|
21
|
-
const cleancss_webpack_plugin_1 = require("../../plugins/cleancss-webpack-plugin");
|
|
22
22
|
const named_chunks_plugin_1 = require("../../plugins/named-chunks-plugin");
|
|
23
|
+
const optimize_css_webpack_plugin_1 = require("../../plugins/optimize-css-webpack-plugin");
|
|
23
24
|
const scripts_webpack_plugin_1 = require("../../plugins/scripts-webpack-plugin");
|
|
24
25
|
const webpack_2 = require("../../plugins/webpack");
|
|
25
26
|
const find_up_1 = require("../../utilities/find-up");
|
|
@@ -32,10 +33,6 @@ function getCommonConfig(wco) {
|
|
|
32
33
|
const { root, projectRoot, buildOptions, tsConfig } = wco;
|
|
33
34
|
const { styles: stylesOptimization, scripts: scriptsOptimization } = buildOptions.optimization;
|
|
34
35
|
const { styles: stylesSourceMap, scripts: scriptsSourceMap, vendor: vendorSourceMap, } = buildOptions.sourceMap;
|
|
35
|
-
const nodeModules = find_up_1.findUp('node_modules', projectRoot);
|
|
36
|
-
if (!nodeModules) {
|
|
37
|
-
throw new Error('Cannot locate node_modules directory.');
|
|
38
|
-
}
|
|
39
36
|
const extraPlugins = [];
|
|
40
37
|
const extraRules = [];
|
|
41
38
|
const entryPoints = {};
|
|
@@ -158,21 +155,24 @@ function getCommonConfig(wco) {
|
|
|
158
155
|
}
|
|
159
156
|
// process global scripts
|
|
160
157
|
const globalScriptsByBundleName = utils_2.normalizeExtraEntryPoints(buildOptions.scripts, 'scripts').reduce((prev, curr) => {
|
|
161
|
-
const bundleName = curr
|
|
162
|
-
const resolvedPath = path.resolve(root,
|
|
158
|
+
const { bundleName, inject, input } = curr;
|
|
159
|
+
const resolvedPath = path.resolve(root, input);
|
|
160
|
+
if (!fs_1.existsSync(resolvedPath)) {
|
|
161
|
+
throw new Error(`Script file ${input} does not exist.`);
|
|
162
|
+
}
|
|
163
163
|
const existingEntry = prev.find(el => el.bundleName === bundleName);
|
|
164
164
|
if (existingEntry) {
|
|
165
|
-
if (existingEntry.inject && !
|
|
165
|
+
if (existingEntry.inject && !inject) {
|
|
166
166
|
// All entries have to be lazy for the bundle to be lazy.
|
|
167
|
-
throw new Error(`The ${
|
|
167
|
+
throw new Error(`The ${bundleName} bundle is mixing injected and non-injected scripts.`);
|
|
168
168
|
}
|
|
169
169
|
existingEntry.paths.push(resolvedPath);
|
|
170
170
|
}
|
|
171
171
|
else {
|
|
172
172
|
prev.push({
|
|
173
173
|
bundleName,
|
|
174
|
+
inject,
|
|
174
175
|
paths: [resolvedPath],
|
|
175
|
-
inject: curr.inject,
|
|
176
176
|
});
|
|
177
177
|
}
|
|
178
178
|
return prev;
|
|
@@ -274,12 +274,12 @@ function getCommonConfig(wco) {
|
|
|
274
274
|
? 'rxjs/_esm2015/path-mapping'
|
|
275
275
|
: 'rxjs/_esm5/path-mapping';
|
|
276
276
|
const rxPaths = require(require.resolve(rxjsPathMappingImport, { paths: [projectRoot] }));
|
|
277
|
-
alias = rxPaths(
|
|
277
|
+
alias = rxPaths();
|
|
278
278
|
}
|
|
279
279
|
catch (_a) { }
|
|
280
280
|
const extraMinimizers = [];
|
|
281
281
|
if (stylesOptimization) {
|
|
282
|
-
extraMinimizers.push(new
|
|
282
|
+
extraMinimizers.push(new optimize_css_webpack_plugin_1.OptimizeCssWebpackPlugin({
|
|
283
283
|
sourceMap: stylesSourceMap,
|
|
284
284
|
// component styles retain their original file name
|
|
285
285
|
test: file => /\.(?:css|scss|sass|less|styl)$/.test(file),
|
|
@@ -313,31 +313,34 @@ function getCommonConfig(wco) {
|
|
|
313
313
|
safari10: true,
|
|
314
314
|
output: {
|
|
315
315
|
ecma: terserEcma,
|
|
316
|
+
// For differential loading, this is handled in the bundle processing.
|
|
317
|
+
// This should also work with just true but the experimental rollup support breaks without this check.
|
|
318
|
+
ascii_only: !differentialLoadingMode,
|
|
316
319
|
// default behavior (undefined value) is to keep only important comments (licenses, etc.)
|
|
317
320
|
comments: !buildOptions.extractLicenses && undefined,
|
|
318
321
|
webkit: true,
|
|
322
|
+
beautify: environment_options_1.shouldBeautify,
|
|
319
323
|
},
|
|
320
324
|
// On server, we don't want to compress anything. We still set the ngDevMode = false for it
|
|
321
325
|
// to remove dev code, and ngI18nClosureMode to remove Closure compiler i18n code
|
|
322
|
-
compress:
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
326
|
+
compress: environment_options_1.allowMinify &&
|
|
327
|
+
(buildOptions.platform == 'server'
|
|
328
|
+
? {
|
|
329
|
+
ecma: terserEcma,
|
|
330
|
+
global_defs: angularGlobalDefinitions,
|
|
331
|
+
keep_fnames: true,
|
|
332
|
+
}
|
|
333
|
+
: {
|
|
334
|
+
ecma: terserEcma,
|
|
335
|
+
pure_getters: buildOptions.buildOptimizer,
|
|
336
|
+
// PURE comments work best with 3 passes.
|
|
337
|
+
// See https://github.com/webpack/webpack/issues/2899#issuecomment-317425926.
|
|
338
|
+
passes: buildOptions.buildOptimizer ? 3 : 1,
|
|
339
|
+
global_defs: angularGlobalDefinitions,
|
|
340
|
+
}),
|
|
336
341
|
// We also want to avoid mangling on server.
|
|
337
342
|
// Name mangling is handled within the browser builder
|
|
338
|
-
mangle:
|
|
339
|
-
buildOptions.platform !== 'server' &&
|
|
340
|
-
!differentialLoadingMode,
|
|
343
|
+
mangle: environment_options_1.allowMangle && buildOptions.platform !== 'server' && !differentialLoadingMode,
|
|
341
344
|
};
|
|
342
345
|
extraMinimizers.push(new TerserPlugin({
|
|
343
346
|
sourceMap: scriptsSourceMap,
|
|
@@ -357,7 +360,7 @@ function getCommonConfig(wco) {
|
|
|
357
360
|
chunkFilter: (chunk) => globalScriptsByBundleName.some(s => s.bundleName === chunk.name),
|
|
358
361
|
terserOptions: {
|
|
359
362
|
...terserOptions,
|
|
360
|
-
compress: {
|
|
363
|
+
compress: environment_options_1.allowMinify && {
|
|
361
364
|
...terserOptions.compress,
|
|
362
365
|
ecma: 5,
|
|
363
366
|
},
|
|
@@ -365,7 +368,7 @@ function getCommonConfig(wco) {
|
|
|
365
368
|
...terserOptions.output,
|
|
366
369
|
ecma: 5,
|
|
367
370
|
},
|
|
368
|
-
mangle:
|
|
371
|
+
mangle: environment_options_1.allowMangle && buildOptions.platform !== 'server',
|
|
369
372
|
},
|
|
370
373
|
}));
|
|
371
374
|
}
|
|
@@ -14,7 +14,6 @@ function getTestConfig(wco) {
|
|
|
14
14
|
const { root, buildOptions, sourceRoot: include } = wco;
|
|
15
15
|
const extraRules = [];
|
|
16
16
|
const extraPlugins = [];
|
|
17
|
-
// if (buildOptions.codeCoverage && CliConfig.fromProject()) {
|
|
18
17
|
if (buildOptions.codeCoverage) {
|
|
19
18
|
const codeCoverageExclude = buildOptions.codeCoverageExclude;
|
|
20
19
|
const exclude = [
|
|
@@ -31,7 +30,7 @@ function getTestConfig(wco) {
|
|
|
31
30
|
}
|
|
32
31
|
extraRules.push({
|
|
33
32
|
test: /\.(jsx?|tsx?)$/,
|
|
34
|
-
loader: require.resolve('istanbul-
|
|
33
|
+
loader: require.resolve('coverage-istanbul-loader'),
|
|
35
34
|
options: { esModules: true },
|
|
36
35
|
enforce: 'post',
|
|
37
36
|
exclude,
|
|
@@ -92,9 +92,12 @@ function getAotConfig(wco, i18nExtract = false) {
|
|
|
92
92
|
});
|
|
93
93
|
}
|
|
94
94
|
const test = /(?:\.ngfactory\.js|\.ngstyle\.js|\.tsx?)$/;
|
|
95
|
+
const optimize = wco.buildOptions.optimization.scripts;
|
|
95
96
|
return {
|
|
96
97
|
module: { rules: [{ test, use: loaders }] },
|
|
97
|
-
plugins: [
|
|
98
|
+
plugins: [
|
|
99
|
+
_createAotPlugin(wco, { tsConfigPath, emitClassMetadata: !optimize, emitNgModuleScope: !optimize }, i18nExtract),
|
|
100
|
+
],
|
|
98
101
|
};
|
|
99
102
|
}
|
|
100
103
|
exports.getAotConfig = getAotConfig;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Compiler } from 'webpack';
|
|
2
|
-
export interface
|
|
2
|
+
export interface OptimizeCssWebpackPluginOptions {
|
|
3
3
|
sourceMap: boolean;
|
|
4
4
|
test: (file: string) => boolean;
|
|
5
5
|
}
|
|
6
|
-
export declare class
|
|
6
|
+
export declare class OptimizeCssWebpackPlugin {
|
|
7
7
|
private readonly _options;
|
|
8
|
-
constructor(options: Partial<
|
|
8
|
+
constructor(options: Partial<OptimizeCssWebpackPluginOptions>);
|
|
9
9
|
apply(compiler: Compiler): void;
|
|
10
10
|
}
|
package/src/angular-cli-files/plugins/{cleancss-webpack-plugin.js → optimize-css-webpack-plugin.js}
RENAMED
|
@@ -7,14 +7,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
7
7
|
* Use of this source code is governed by an MIT-style license that can be
|
|
8
8
|
* found in the LICENSE file at https://angular.io/license
|
|
9
9
|
*/
|
|
10
|
-
const
|
|
10
|
+
const cssNano = require("cssnano");
|
|
11
11
|
const webpack_sources_1 = require("webpack-sources");
|
|
12
12
|
function hook(compiler, action) {
|
|
13
|
-
compiler.hooks.compilation.tap('
|
|
14
|
-
compilation.hooks.optimizeChunkAssets.tapPromise('
|
|
13
|
+
compiler.hooks.compilation.tap('optimize-css-webpack-plugin', (compilation) => {
|
|
14
|
+
compilation.hooks.optimizeChunkAssets.tapPromise('optimize-css-webpack-plugin', chunks => action(compilation, chunks));
|
|
15
15
|
});
|
|
16
16
|
}
|
|
17
|
-
class
|
|
17
|
+
class OptimizeCssWebpackPlugin {
|
|
18
18
|
constructor(options) {
|
|
19
19
|
this._options = {
|
|
20
20
|
sourceMap: false,
|
|
@@ -24,20 +24,6 @@ class CleanCssWebpackPlugin {
|
|
|
24
24
|
}
|
|
25
25
|
apply(compiler) {
|
|
26
26
|
hook(compiler, (compilation, chunks) => {
|
|
27
|
-
const cleancss = new CleanCSS({
|
|
28
|
-
compatibility: 'ie9',
|
|
29
|
-
level: {
|
|
30
|
-
2: {
|
|
31
|
-
skipProperties: [
|
|
32
|
-
'transition',
|
|
33
|
-
'font',
|
|
34
|
-
],
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
inline: false,
|
|
38
|
-
returnPromise: true,
|
|
39
|
-
sourceMap: this._options.sourceMap,
|
|
40
|
-
});
|
|
41
27
|
const files = [...compilation.additionalChunkAssets];
|
|
42
28
|
chunks.forEach(chunk => {
|
|
43
29
|
if (chunk.files && chunk.files.length > 0) {
|
|
@@ -65,28 +51,32 @@ class CleanCssWebpackPlugin {
|
|
|
65
51
|
if (content.length === 0) {
|
|
66
52
|
return;
|
|
67
53
|
}
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
54
|
+
const cssNanoOptions = {
|
|
55
|
+
preset: 'default',
|
|
56
|
+
};
|
|
57
|
+
const postCssOptions = {
|
|
58
|
+
from: file,
|
|
59
|
+
map: map && { annotation: false, prev: map },
|
|
60
|
+
};
|
|
61
|
+
const output = await new Promise((resolve, reject) => {
|
|
62
|
+
// the last parameter is not in the typings
|
|
63
|
+
// tslint:disable-next-line: no-any
|
|
64
|
+
cssNano.process(content, postCssOptions, cssNanoOptions)
|
|
65
|
+
.then(resolve)
|
|
66
|
+
.catch(reject);
|
|
67
|
+
});
|
|
68
|
+
const warnings = output.warnings();
|
|
69
|
+
if (warnings.length) {
|
|
70
|
+
compilation.warnings.push(...warnings.map(({ text }) => text));
|
|
81
71
|
}
|
|
82
72
|
let newSource;
|
|
83
|
-
if (output.
|
|
84
|
-
newSource = new webpack_sources_1.SourceMapSource(output.
|
|
73
|
+
if (output.map) {
|
|
74
|
+
newSource = new webpack_sources_1.SourceMapSource(output.css, file,
|
|
85
75
|
// tslint:disable-next-line: no-any
|
|
86
|
-
output.
|
|
76
|
+
output.map.toString(), content, map);
|
|
87
77
|
}
|
|
88
78
|
else {
|
|
89
|
-
newSource = new webpack_sources_1.RawSource(output.
|
|
79
|
+
newSource = new webpack_sources_1.RawSource(output.css);
|
|
90
80
|
}
|
|
91
81
|
compilation.assets[file] = newSource;
|
|
92
82
|
});
|
|
@@ -94,4 +84,4 @@ class CleanCssWebpackPlugin {
|
|
|
94
84
|
});
|
|
95
85
|
}
|
|
96
86
|
}
|
|
97
|
-
exports.
|
|
87
|
+
exports.OptimizeCssWebpackPlugin = OptimizeCssWebpackPlugin;
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* found in the LICENSE file at https://angular.io/license
|
|
7
7
|
*/
|
|
8
8
|
export { AnyComponentStyleBudgetChecker } from './any-component-style-budget-checker';
|
|
9
|
-
export {
|
|
9
|
+
export { OptimizeCssWebpackPlugin, OptimizeCssWebpackPluginOptions } from './optimize-css-webpack-plugin';
|
|
10
10
|
export { BundleBudgetPlugin, BundleBudgetPluginOptions } from './bundle-budget';
|
|
11
11
|
export { ScriptsWebpackPlugin, ScriptsWebpackPluginOptions } from './scripts-webpack-plugin';
|
|
12
12
|
export { SuppressExtractedTextChunksWebpackPlugin } from './suppress-entry-chunks-webpack-plugin';
|
|
@@ -10,8 +10,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
10
10
|
// Exports the webpack plugins we use internally.
|
|
11
11
|
var any_component_style_budget_checker_1 = require("./any-component-style-budget-checker");
|
|
12
12
|
exports.AnyComponentStyleBudgetChecker = any_component_style_budget_checker_1.AnyComponentStyleBudgetChecker;
|
|
13
|
-
var
|
|
14
|
-
exports.
|
|
13
|
+
var optimize_css_webpack_plugin_1 = require("./optimize-css-webpack-plugin");
|
|
14
|
+
exports.OptimizeCssWebpackPlugin = optimize_css_webpack_plugin_1.OptimizeCssWebpackPlugin;
|
|
15
15
|
var bundle_budget_1 = require("./bundle-budget");
|
|
16
16
|
exports.BundleBudgetPlugin = bundle_budget_1.BundleBudgetPlugin;
|
|
17
17
|
var scripts_webpack_plugin_1 = require("./scripts-webpack-plugin");
|
package/src/browser/index.js
CHANGED
|
@@ -233,12 +233,6 @@ function buildWebpackBrowser(options, context, transforms = {}) {
|
|
|
233
233
|
if (!es5Polyfills) {
|
|
234
234
|
moduleFiles.push(file);
|
|
235
235
|
}
|
|
236
|
-
// If not optimizing then ES2015 polyfills do not need processing
|
|
237
|
-
// Unlike other module scripts, it is never downleveled
|
|
238
|
-
const es2015Polyfills = file.file.startsWith('polyfills-es20');
|
|
239
|
-
if (!actionOptions.optimize && es2015Polyfills) {
|
|
240
|
-
continue;
|
|
241
|
-
}
|
|
242
236
|
// Retrieve the content/map for the file
|
|
243
237
|
// NOTE: Additional future optimizations will read directly from memory
|
|
244
238
|
// tslint:disable-next-line: no-non-null-assertion
|
|
@@ -258,6 +252,7 @@ function buildWebpackBrowser(options, context, transforms = {}) {
|
|
|
258
252
|
fs.unlinkSync(filename);
|
|
259
253
|
filename = filename.replace(/\-es20\d{2}/, '');
|
|
260
254
|
}
|
|
255
|
+
const es2015Polyfills = file.file.startsWith('polyfills-es20');
|
|
261
256
|
// Record the bundle processing action
|
|
262
257
|
// The runtime chunk gets special processing for lazy loaded files
|
|
263
258
|
actions.push({
|
|
@@ -307,6 +302,7 @@ function buildWebpackBrowser(options, context, transforms = {}) {
|
|
|
307
302
|
const runtimeOptions = {
|
|
308
303
|
...processRuntimeAction,
|
|
309
304
|
runtimeData: processResults,
|
|
305
|
+
supportedBrowsers: buildBrowserFeatures.supportedBrowsers,
|
|
310
306
|
};
|
|
311
307
|
processResults.push(await Promise.resolve().then(() => require('../utils/process-bundle')).then(m => m.process(runtimeOptions)));
|
|
312
308
|
}
|
package/src/dev-server/index.js
CHANGED
|
@@ -254,6 +254,7 @@ async function setupLocalize(i18n, browserOptions, webpackConfig) {
|
|
|
254
254
|
loader: require.resolve('babel-loader'),
|
|
255
255
|
options: {
|
|
256
256
|
babelrc: false,
|
|
257
|
+
configFile: false,
|
|
257
258
|
compact: false,
|
|
258
259
|
cacheCompression: false,
|
|
259
260
|
cacheDirectory: cache_path_1.findCachePath('babel-loader'),
|
package/src/protractor/index.js
CHANGED
|
@@ -27,21 +27,14 @@ function runProtractor(root, options) {
|
|
|
27
27
|
async function updateWebdriver() {
|
|
28
28
|
// The webdriver-manager update command can only be accessed via a deep import.
|
|
29
29
|
const webdriverDeepImport = 'webdriver-manager/built/lib/cmds/update';
|
|
30
|
-
const importOptions = [
|
|
31
|
-
// When using npm, webdriver is within protractor/node_modules.
|
|
32
|
-
`protractor/node_modules/${webdriverDeepImport}`,
|
|
33
|
-
// When using yarn, webdriver is found as a root module.
|
|
34
|
-
webdriverDeepImport,
|
|
35
|
-
];
|
|
36
30
|
let path;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
31
|
+
try {
|
|
32
|
+
const protractorPath = require.resolve('protractor');
|
|
33
|
+
path = require.resolve(webdriverDeepImport, { paths: [protractorPath] });
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
if (error.code !== 'MODULE_NOT_FOUND') {
|
|
37
|
+
throw error;
|
|
45
38
|
}
|
|
46
39
|
}
|
|
47
40
|
if (!path) {
|
|
@@ -13,6 +13,6 @@ export declare class BundleActionCache {
|
|
|
13
13
|
static copyEntryContent(entry: CacheEntry | string, dest: fs.PathLike): void;
|
|
14
14
|
generateBaseCacheKey(content: string): string;
|
|
15
15
|
generateCacheKeys(action: ProcessBundleOptions): string[];
|
|
16
|
-
getCacheEntries(cacheKeys: (string |
|
|
16
|
+
getCacheEntries(cacheKeys: (string | undefined)[]): Promise<(CacheEntry | null)[] | false>;
|
|
17
17
|
getCachedBundleResult(action: ProcessBundleOptions): Promise<ProcessBundleResult | null>;
|
|
18
18
|
}
|
|
@@ -35,32 +35,36 @@ class BundleActionCache {
|
|
|
35
35
|
.update(content)
|
|
36
36
|
.digest('base64');
|
|
37
37
|
let baseCacheKey = `${packageVersion}|${content.length}|${algorithm}-${codeHash}`;
|
|
38
|
-
if (environment_options_1.
|
|
38
|
+
if (!environment_options_1.allowMangle) {
|
|
39
39
|
baseCacheKey += '|MD';
|
|
40
40
|
}
|
|
41
41
|
return baseCacheKey;
|
|
42
42
|
}
|
|
43
43
|
generateCacheKeys(action) {
|
|
44
|
-
|
|
45
|
-
// Postfix added to sourcemap cache keys when vendor sourcemaps are present
|
|
44
|
+
// Postfix added to sourcemap cache keys when vendor, hidden sourcemaps are present
|
|
46
45
|
// Allows non-destructive caching of both variants
|
|
47
|
-
const
|
|
46
|
+
const sourceMapVendorPostfix = action.sourceMaps && action.vendorSourceMaps ? '|vendor' : '';
|
|
47
|
+
// sourceMappingURL is added at the very end which causes the code to be the same when sourcemaps are enabled/disabled
|
|
48
|
+
// When using hiddenSourceMaps we can omit the postfix since sourceMappingURL will not be added.
|
|
49
|
+
// When having sourcemaps a hashed file and non hashed file can have the same content. But the sourceMappingURL will differ.
|
|
50
|
+
const sourceMapPostFix = action.sourceMaps && !action.hiddenSourceMaps ? `|sourcemap|${action.filename}` : '';
|
|
51
|
+
const baseCacheKey = this.generateBaseCacheKey(action.code);
|
|
48
52
|
// Determine cache entries required based on build settings
|
|
49
53
|
const cacheKeys = [];
|
|
50
54
|
// If optimizing and the original is not ignored, add original as required
|
|
51
|
-
if (
|
|
52
|
-
cacheKeys[0 /* OriginalCode */] = baseCacheKey + '|orig';
|
|
55
|
+
if (!action.ignoreOriginal) {
|
|
56
|
+
cacheKeys[0 /* OriginalCode */] = baseCacheKey + sourceMapPostFix + '|orig';
|
|
53
57
|
// If sourcemaps are enabled, add original sourcemap as required
|
|
54
58
|
if (action.sourceMaps) {
|
|
55
|
-
cacheKeys[1 /* OriginalMap */] = baseCacheKey +
|
|
59
|
+
cacheKeys[1 /* OriginalMap */] = baseCacheKey + sourceMapVendorPostfix + '|orig-map';
|
|
56
60
|
}
|
|
57
61
|
}
|
|
58
62
|
// If not only optimizing, add downlevel as required
|
|
59
63
|
if (!action.optimizeOnly) {
|
|
60
|
-
cacheKeys[2 /* DownlevelCode */] = baseCacheKey + '|dl';
|
|
64
|
+
cacheKeys[2 /* DownlevelCode */] = baseCacheKey + sourceMapPostFix + '|dl';
|
|
61
65
|
// If sourcemaps are enabled, add downlevel sourcemap as required
|
|
62
66
|
if (action.sourceMaps) {
|
|
63
|
-
cacheKeys[3 /* DownlevelMap */] = baseCacheKey +
|
|
67
|
+
cacheKeys[3 /* DownlevelMap */] = baseCacheKey + sourceMapVendorPostfix + '|dl-map';
|
|
64
68
|
}
|
|
65
69
|
}
|
|
66
70
|
return cacheKeys;
|
|
@@ -9,8 +9,8 @@ import * as ts from 'typescript';
|
|
|
9
9
|
export declare class BuildBrowserFeatures {
|
|
10
10
|
private projectRoot;
|
|
11
11
|
private scriptTarget;
|
|
12
|
-
private readonly _supportedBrowsers;
|
|
13
12
|
private readonly _es6TargetOrLater;
|
|
13
|
+
readonly supportedBrowsers: string[];
|
|
14
14
|
constructor(projectRoot: string, scriptTarget: ts.ScriptTarget);
|
|
15
15
|
/**
|
|
16
16
|
* True, when one or more browsers requires ES5
|
|
@@ -14,7 +14,7 @@ class BuildBrowserFeatures {
|
|
|
14
14
|
constructor(projectRoot, scriptTarget) {
|
|
15
15
|
this.projectRoot = projectRoot;
|
|
16
16
|
this.scriptTarget = scriptTarget;
|
|
17
|
-
this.
|
|
17
|
+
this.supportedBrowsers = browserslist(undefined, { path: this.projectRoot });
|
|
18
18
|
this._es6TargetOrLater = this.scriptTarget > ts.ScriptTarget.ES5;
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
@@ -44,7 +44,7 @@ class BuildBrowserFeatures {
|
|
|
44
44
|
'safari 10.1',
|
|
45
45
|
'ios_saf 10.3',
|
|
46
46
|
];
|
|
47
|
-
return this.
|
|
47
|
+
return this.supportedBrowsers.some(browser => safariBrowsers.includes(browser));
|
|
48
48
|
}
|
|
49
49
|
/**
|
|
50
50
|
* True, when a browser feature is supported partially or fully.
|
|
@@ -59,7 +59,7 @@ class BuildBrowserFeatures {
|
|
|
59
59
|
'a',
|
|
60
60
|
];
|
|
61
61
|
const data = caniuse_lite_1.feature(caniuse_lite_1.features[featureId]);
|
|
62
|
-
return !this.
|
|
62
|
+
return !this.supportedBrowsers
|
|
63
63
|
.some(browser => {
|
|
64
64
|
const [agentId, version] = browser.split(' ');
|
|
65
65
|
const browserData = data.stats[agentId];
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
export declare const
|
|
1
|
+
export declare const allowMangle: boolean;
|
|
2
|
+
export declare const shouldBeautify: boolean;
|
|
3
|
+
export declare const allowMinify: boolean;
|
|
2
4
|
export declare const cachingDisabled: boolean;
|
|
3
5
|
export declare const cachingBasePath: string | null;
|
|
@@ -8,14 +8,57 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
8
8
|
* found in the LICENSE file at https://angular.io/license
|
|
9
9
|
*/
|
|
10
10
|
const path = require("path");
|
|
11
|
+
function isDisabled(variable) {
|
|
12
|
+
return variable === '0' || variable.toLowerCase() === 'false';
|
|
13
|
+
}
|
|
14
|
+
function isEnabled(variable) {
|
|
15
|
+
return variable === '1' || variable.toLowerCase() === 'true';
|
|
16
|
+
}
|
|
17
|
+
function isPresent(variable) {
|
|
18
|
+
return typeof variable === 'string' && variable !== '';
|
|
19
|
+
}
|
|
20
|
+
const debugOptimizeVariable = process.env['NG_BUILD_DEBUG_OPTIMIZE'];
|
|
21
|
+
const debugOptimize = (() => {
|
|
22
|
+
if (!isPresent(debugOptimizeVariable) || isDisabled(debugOptimizeVariable)) {
|
|
23
|
+
return {
|
|
24
|
+
mangle: true,
|
|
25
|
+
minify: true,
|
|
26
|
+
beautify: false,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
const debugValue = {
|
|
30
|
+
mangle: false,
|
|
31
|
+
minify: false,
|
|
32
|
+
beautify: true,
|
|
33
|
+
};
|
|
34
|
+
if (isEnabled(debugOptimizeVariable)) {
|
|
35
|
+
return debugValue;
|
|
36
|
+
}
|
|
37
|
+
for (const part of debugOptimizeVariable.split(',')) {
|
|
38
|
+
switch (part.trim().toLowerCase()) {
|
|
39
|
+
case 'mangle':
|
|
40
|
+
debugValue.mangle = true;
|
|
41
|
+
break;
|
|
42
|
+
case 'minify':
|
|
43
|
+
debugValue.minify = true;
|
|
44
|
+
break;
|
|
45
|
+
case 'beautify':
|
|
46
|
+
debugValue.beautify = true;
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return debugValue;
|
|
51
|
+
})();
|
|
11
52
|
const mangleVariable = process.env['NG_BUILD_MANGLE'];
|
|
12
|
-
exports.
|
|
53
|
+
exports.allowMangle = isPresent(mangleVariable)
|
|
54
|
+
? !isDisabled(mangleVariable)
|
|
55
|
+
: debugOptimize.mangle;
|
|
56
|
+
exports.shouldBeautify = debugOptimize.beautify;
|
|
57
|
+
exports.allowMinify = debugOptimize.minify;
|
|
13
58
|
const cacheVariable = process.env['NG_BUILD_CACHE'];
|
|
14
|
-
exports.cachingDisabled =
|
|
59
|
+
exports.cachingDisabled = isPresent(cacheVariable) && isDisabled(cacheVariable);
|
|
15
60
|
exports.cachingBasePath = (() => {
|
|
16
|
-
if (exports.cachingDisabled ||
|
|
17
|
-
!cacheVariable ||
|
|
18
|
-
(cacheVariable === '1' || cacheVariable.toLowerCase() === 'true')) {
|
|
61
|
+
if (exports.cachingDisabled || !isPresent(cacheVariable) || isEnabled(cacheVariable)) {
|
|
19
62
|
return null;
|
|
20
63
|
}
|
|
21
64
|
if (!path.isAbsolute(cacheVariable)) {
|
|
@@ -11,10 +11,11 @@ export interface ProcessBundleOptions {
|
|
|
11
11
|
optimize?: boolean;
|
|
12
12
|
optimizeOnly?: boolean;
|
|
13
13
|
ignoreOriginal?: boolean;
|
|
14
|
-
cacheKeys?: (string |
|
|
14
|
+
cacheKeys?: (string | undefined)[];
|
|
15
15
|
integrityAlgorithm?: 'sha256' | 'sha384' | 'sha512';
|
|
16
16
|
runtimeData?: ProcessBundleResult[];
|
|
17
17
|
replacements?: [string, string][];
|
|
18
|
+
supportedBrowsers?: string[] | Record<string, string>;
|
|
18
19
|
}
|
|
19
20
|
export interface ProcessBundleResult {
|
|
20
21
|
name: string;
|
|
@@ -18,6 +18,8 @@ const webpack_sources_1 = require("webpack-sources");
|
|
|
18
18
|
const environment_options_1 = require("./environment-options");
|
|
19
19
|
const cacache = require('cacache');
|
|
20
20
|
const deserialize = v8.deserialize;
|
|
21
|
+
// If code size is larger than 500KB, consider lower fidelity but faster sourcemap merge
|
|
22
|
+
const FAST_SOURCEMAP_THRESHOLD = 500 * 1024;
|
|
21
23
|
let cachePath;
|
|
22
24
|
let i18n;
|
|
23
25
|
function setup(data) {
|
|
@@ -30,7 +32,7 @@ function setup(data) {
|
|
|
30
32
|
exports.setup = setup;
|
|
31
33
|
async function cachePut(content, key, integrity) {
|
|
32
34
|
if (cachePath && key) {
|
|
33
|
-
await cacache.put(cachePath, key, content, {
|
|
35
|
+
await cacache.put(cachePath, key || null, content, {
|
|
34
36
|
metadata: { integrity },
|
|
35
37
|
});
|
|
36
38
|
}
|
|
@@ -52,11 +54,6 @@ async function process(options) {
|
|
|
52
54
|
const filename = path.basename(options.filename);
|
|
53
55
|
const downlevelFilename = filename.replace(/\-es20\d{2}/, '-es5');
|
|
54
56
|
const downlevel = !options.optimizeOnly;
|
|
55
|
-
// if code size is larger than 500kB, manually handle sourcemaps with newer source-map package.
|
|
56
|
-
// babel currently uses an older version that still supports sync calls
|
|
57
|
-
const codeSize = Buffer.byteLength(options.code);
|
|
58
|
-
const mapSize = options.map ? Buffer.byteLength(options.map) : 0;
|
|
59
|
-
const manualSourceMaps = codeSize >= 500 * 1024 || mapSize >= 500 * 1024;
|
|
60
57
|
const sourceCode = options.code;
|
|
61
58
|
const sourceMap = options.map ? JSON.parse(options.map) : undefined;
|
|
62
59
|
let downlevelCode;
|
|
@@ -64,12 +61,18 @@ async function process(options) {
|
|
|
64
61
|
if (downlevel) {
|
|
65
62
|
// Downlevel the bundle
|
|
66
63
|
const transformResult = await core_1.transformAsync(sourceCode, {
|
|
67
|
-
filename
|
|
68
|
-
|
|
64
|
+
filename,
|
|
65
|
+
// using false ensures that babel will NOT search and process sourcemap comments (large memory usage)
|
|
66
|
+
// The types do not include the false option even though it is valid
|
|
67
|
+
// tslint:disable-next-line: no-any
|
|
68
|
+
inputSourceMap: false,
|
|
69
69
|
babelrc: false,
|
|
70
|
+
configFile: false,
|
|
70
71
|
presets: [[
|
|
71
72
|
require.resolve('@babel/preset-env'),
|
|
72
73
|
{
|
|
74
|
+
// browserslist-compatible query or object of minimum environment versions to support
|
|
75
|
+
targets: options.supportedBrowsers,
|
|
73
76
|
// modules aren't needed since the bundles use webpack's custom module loading
|
|
74
77
|
modules: false,
|
|
75
78
|
// 'transform-typeof-symbol' generates slower code
|
|
@@ -77,61 +80,46 @@ async function process(options) {
|
|
|
77
80
|
},
|
|
78
81
|
]],
|
|
79
82
|
plugins: options.replacements ? [createReplacePlugin(options.replacements)] : [],
|
|
80
|
-
minified: options.optimize,
|
|
81
|
-
|
|
82
|
-
compact: options.optimize || false,
|
|
83
|
+
minified: environment_options_1.allowMinify && !!options.optimize,
|
|
84
|
+
compact: !environment_options_1.shouldBeautify && !!options.optimize,
|
|
83
85
|
sourceMaps: !!sourceMap,
|
|
84
86
|
});
|
|
85
87
|
if (!transformResult || !transformResult.code) {
|
|
86
88
|
throw new Error(`Unknown error occurred processing bundle for "${options.filename}".`);
|
|
87
89
|
}
|
|
88
90
|
downlevelCode = transformResult.code;
|
|
89
|
-
if (
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
//
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
if (options.optimize) {
|
|
98
|
-
if (downlevelCode) {
|
|
99
|
-
const minifyResult = terserMangle(downlevelCode, {
|
|
100
|
-
filename: downlevelFilename,
|
|
101
|
-
map: downlevelMap,
|
|
102
|
-
compress: true,
|
|
103
|
-
});
|
|
104
|
-
downlevelCode = minifyResult.code;
|
|
105
|
-
downlevelMap = minifyResult.map;
|
|
106
|
-
}
|
|
107
|
-
if (!options.ignoreOriginal) {
|
|
108
|
-
result.original = await mangleOriginal(options);
|
|
91
|
+
if (sourceMap && transformResult.map) {
|
|
92
|
+
// String length is used as an estimate for byte length
|
|
93
|
+
const fastSourceMaps = sourceCode.length > FAST_SOURCEMAP_THRESHOLD;
|
|
94
|
+
downlevelMap = await mergeSourceMaps(sourceCode, sourceMap, downlevelCode, transformResult.map, filename,
|
|
95
|
+
// When not optimizing, the sourcemaps are significantly less complex
|
|
96
|
+
// and can use the higher fidelity merge
|
|
97
|
+
!!options.optimize && fastSourceMaps);
|
|
109
98
|
}
|
|
110
99
|
}
|
|
111
100
|
if (downlevelCode) {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
await cachePut(mapContent, options.cacheKeys[3 /* DownlevelMap */]);
|
|
120
|
-
fs.writeFileSync(downlevelPath + '.map', mapContent);
|
|
121
|
-
}
|
|
122
|
-
result.downlevel = createFileEntry(path.join(basePath, downlevelFilename), downlevelCode, mapContent, options.integrityAlgorithm);
|
|
123
|
-
await cachePut(downlevelCode, options.cacheKeys[2 /* DownlevelCode */], result.downlevel.integrity);
|
|
124
|
-
fs.writeFileSync(downlevelPath, downlevelCode);
|
|
101
|
+
result.downlevel = await processBundle({
|
|
102
|
+
...options,
|
|
103
|
+
code: downlevelCode,
|
|
104
|
+
map: downlevelMap,
|
|
105
|
+
filename: path.join(basePath, downlevelFilename),
|
|
106
|
+
isOriginal: false,
|
|
107
|
+
});
|
|
125
108
|
}
|
|
126
|
-
// If original was not processed, add info
|
|
127
109
|
if (!result.original && !options.ignoreOriginal) {
|
|
128
|
-
result.original =
|
|
110
|
+
result.original = await processBundle({
|
|
111
|
+
...options,
|
|
112
|
+
isOriginal: true,
|
|
113
|
+
});
|
|
129
114
|
}
|
|
130
115
|
return result;
|
|
131
116
|
}
|
|
132
117
|
exports.process = process;
|
|
133
|
-
function mergeSourceMaps(inputCode, inputSourceMap, resultCode, resultSourceMap, filename) {
|
|
134
|
-
|
|
118
|
+
async function mergeSourceMaps(inputCode, inputSourceMap, resultCode, resultSourceMap, filename, fast = false) {
|
|
119
|
+
if (fast) {
|
|
120
|
+
return mergeSourceMapsFast(inputSourceMap, resultSourceMap);
|
|
121
|
+
}
|
|
122
|
+
// SourceMapSource produces high-quality sourcemaps
|
|
135
123
|
// The last argument is not yet in the typings
|
|
136
124
|
// tslint:disable-next-line: no-any
|
|
137
125
|
return new webpack_sources_1.SourceMapSource(resultCode, filename, resultSourceMap, inputCode, inputSourceMap, true).map();
|
|
@@ -180,45 +168,58 @@ async function mergeSourceMapsFast(first, second) {
|
|
|
180
168
|
}
|
|
181
169
|
return map;
|
|
182
170
|
}
|
|
183
|
-
async function
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
171
|
+
async function processBundle(options) {
|
|
172
|
+
const { optimize, isOriginal, code, map, filename: filepath, hiddenSourceMaps, cacheKeys = [], integrityAlgorithm, } = options;
|
|
173
|
+
const rawMap = typeof map === 'string' ? JSON.parse(map) : map;
|
|
174
|
+
const filename = path.basename(filepath);
|
|
175
|
+
let result;
|
|
176
|
+
if (rawMap) {
|
|
177
|
+
rawMap.file = filename;
|
|
178
|
+
}
|
|
179
|
+
if (optimize) {
|
|
180
|
+
result = await terserMangle(code, {
|
|
181
|
+
filename,
|
|
182
|
+
map: rawMap,
|
|
183
|
+
compress: !isOriginal,
|
|
184
|
+
ecma: isOriginal ? 6 : 5,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
result = {
|
|
189
|
+
map: rawMap,
|
|
190
|
+
code,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
189
193
|
let mapContent;
|
|
190
194
|
if (result.map) {
|
|
191
|
-
if (!
|
|
192
|
-
result.code += `\n//# sourceMappingURL=${
|
|
195
|
+
if (!hiddenSourceMaps) {
|
|
196
|
+
result.code += `\n//# sourceMappingURL=${filename}.map`;
|
|
193
197
|
}
|
|
194
198
|
mapContent = JSON.stringify(result.map);
|
|
195
|
-
await cachePut(mapContent,
|
|
196
|
-
fs.writeFileSync(
|
|
199
|
+
await cachePut(mapContent, cacheKeys[isOriginal ? 1 /* OriginalMap */ : 3 /* DownlevelMap */]);
|
|
200
|
+
fs.writeFileSync(filepath + '.map', mapContent);
|
|
197
201
|
}
|
|
198
|
-
const fileResult = createFileEntry(
|
|
199
|
-
await cachePut(result.code,
|
|
200
|
-
fs.writeFileSync(
|
|
202
|
+
const fileResult = createFileEntry(filepath, result.code, mapContent, integrityAlgorithm);
|
|
203
|
+
await cachePut(result.code, cacheKeys[isOriginal ? 0 /* OriginalCode */ : 2 /* DownlevelCode */], fileResult.integrity);
|
|
204
|
+
fs.writeFileSync(filepath, result.code);
|
|
201
205
|
return fileResult;
|
|
202
206
|
}
|
|
203
|
-
function terserMangle(code, options = {}) {
|
|
207
|
+
async function terserMangle(code, options = {}) {
|
|
204
208
|
// Note: Investigate converting the AST instead of re-parsing
|
|
205
209
|
// estree -> terser is already supported; need babel -> estree/terser
|
|
206
210
|
// Mangle downlevel code
|
|
207
|
-
const minifyOutput = terser_1.minify(code, {
|
|
208
|
-
compress: options.compress
|
|
211
|
+
const minifyOutput = terser_1.minify(options.filename ? { [options.filename]: code } : code, {
|
|
212
|
+
compress: environment_options_1.allowMinify && !!options.compress,
|
|
209
213
|
ecma: options.ecma || 5,
|
|
210
|
-
mangle:
|
|
214
|
+
mangle: environment_options_1.allowMangle,
|
|
211
215
|
safari10: true,
|
|
212
216
|
output: {
|
|
213
217
|
ascii_only: true,
|
|
214
218
|
webkit: true,
|
|
219
|
+
beautify: environment_options_1.shouldBeautify,
|
|
215
220
|
},
|
|
216
221
|
sourceMap: !!options.map &&
|
|
217
222
|
{
|
|
218
|
-
filename: options.filename,
|
|
219
|
-
// terser uses an old version of the sourcemap typings
|
|
220
|
-
// tslint:disable-next-line: no-any
|
|
221
|
-
content: options.map,
|
|
222
223
|
asObject: true,
|
|
223
224
|
},
|
|
224
225
|
});
|
|
@@ -226,7 +227,12 @@ function terserMangle(code, options = {}) {
|
|
|
226
227
|
throw minifyOutput.error;
|
|
227
228
|
}
|
|
228
229
|
// tslint:disable-next-line: no-non-null-assertion
|
|
229
|
-
|
|
230
|
+
const outputCode = minifyOutput.code;
|
|
231
|
+
let outputMap;
|
|
232
|
+
if (options.map && minifyOutput.map) {
|
|
233
|
+
outputMap = await mergeSourceMaps(code, options.map, outputCode, minifyOutput.map, options.filename || '0', code.length > FAST_SOURCEMAP_THRESHOLD);
|
|
234
|
+
}
|
|
235
|
+
return { code: outputCode, map: outputMap };
|
|
230
236
|
}
|
|
231
237
|
function createFileEntry(filename, code, map, integrityAlgorithm) {
|
|
232
238
|
return {
|
|
@@ -271,42 +277,19 @@ async function processRuntime(options) {
|
|
|
271
277
|
// Adjust lazy loaded scripts to point to the proper variant
|
|
272
278
|
// Extra spacing is intentional to align source line positions
|
|
273
279
|
downlevelCode = downlevelCode.replace(/"\-es20\d{2}\./, ' "-es5.');
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
};
|
|
288
|
-
}
|
|
289
|
-
else {
|
|
290
|
-
if (options.map) {
|
|
291
|
-
const rawMap = JSON.parse(options.map);
|
|
292
|
-
rawMap.file = path.basename(downlevelFilePath);
|
|
293
|
-
downlevelMap = JSON.stringify(rawMap);
|
|
294
|
-
}
|
|
295
|
-
result = {
|
|
296
|
-
original: createFileEntry(options.filename, originalCode, options.map, options.integrityAlgorithm),
|
|
297
|
-
downlevel: createFileEntry(downlevelFilePath, downlevelCode, downlevelMap, options.integrityAlgorithm),
|
|
298
|
-
};
|
|
299
|
-
}
|
|
300
|
-
if (downlevelMap) {
|
|
301
|
-
await cachePut(downlevelMap, (options.cacheKeys && options.cacheKeys[3 /* DownlevelMap */]) || null);
|
|
302
|
-
fs.writeFileSync(downlevelFilePath + '.map', downlevelMap);
|
|
303
|
-
if (!options.hiddenSourceMaps) {
|
|
304
|
-
downlevelCode += `\n//# sourceMappingURL=${path.basename(downlevelFilePath)}.map`;
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
await cachePut(downlevelCode, (options.cacheKeys && options.cacheKeys[2 /* DownlevelCode */]) || null);
|
|
308
|
-
fs.writeFileSync(downlevelFilePath, downlevelCode);
|
|
309
|
-
return result;
|
|
280
|
+
return {
|
|
281
|
+
original: await processBundle({
|
|
282
|
+
...options,
|
|
283
|
+
code: originalCode,
|
|
284
|
+
isOriginal: true,
|
|
285
|
+
}),
|
|
286
|
+
downlevel: await processBundle({
|
|
287
|
+
...options,
|
|
288
|
+
code: downlevelCode,
|
|
289
|
+
filename: options.filename.replace(/\-es20\d{2}/, '-es5'),
|
|
290
|
+
isOriginal: false,
|
|
291
|
+
}),
|
|
292
|
+
};
|
|
310
293
|
}
|
|
311
294
|
function createReplacePlugin(replacements) {
|
|
312
295
|
return {
|
|
@@ -345,7 +328,8 @@ async function inlineLocales(options) {
|
|
|
345
328
|
if (positions.length === 0 && !options.setLocale) {
|
|
346
329
|
return inlineCopyOnly(options);
|
|
347
330
|
}
|
|
348
|
-
|
|
331
|
+
// tslint:disable-next-line: no-any
|
|
332
|
+
let content = new MagicString(options.code, { filename: options.filename });
|
|
349
333
|
const inputMap = options.map && JSON.parse(options.map);
|
|
350
334
|
let contentClone;
|
|
351
335
|
for (const locale of i18n.inlineLocales) {
|
|
@@ -365,7 +349,7 @@ async function inlineLocales(options) {
|
|
|
365
349
|
// If locale data is provided, load it and prepend to file
|
|
366
350
|
const localeDataPath = i18n.locales[locale] && i18n.locales[locale].dataPath;
|
|
367
351
|
if (localeDataPath) {
|
|
368
|
-
const localDataContent = loadLocaleData(localeDataPath, true);
|
|
352
|
+
const localDataContent = await loadLocaleData(localeDataPath, true);
|
|
369
353
|
// The semicolon ensures that there is no syntax error between statements
|
|
370
354
|
content.prepend(localDataContent + ';');
|
|
371
355
|
}
|
|
@@ -375,7 +359,7 @@ async function inlineLocales(options) {
|
|
|
375
359
|
fs.writeFileSync(outputPath, output);
|
|
376
360
|
if (inputMap) {
|
|
377
361
|
const contentMap = content.generateMap();
|
|
378
|
-
const outputMap = mergeSourceMaps(options.code, inputMap, output, contentMap, options.filename);
|
|
362
|
+
const outputMap = mergeSourceMaps(options.code, inputMap, output, contentMap, options.filename, options.code.length > FAST_SOURCEMAP_THRESHOLD);
|
|
379
363
|
fs.writeFileSync(outputPath + '.map', JSON.stringify(outputMap));
|
|
380
364
|
}
|
|
381
365
|
if (contentClone) {
|
|
@@ -406,7 +390,9 @@ utils) {
|
|
|
406
390
|
try {
|
|
407
391
|
ast = core_1.parseSync(options.code, {
|
|
408
392
|
babelrc: false,
|
|
393
|
+
configFile: false,
|
|
409
394
|
sourceType: 'script',
|
|
395
|
+
filename: options.filename,
|
|
410
396
|
});
|
|
411
397
|
}
|
|
412
398
|
catch (error) {
|
|
@@ -464,12 +450,12 @@ utils) {
|
|
|
464
450
|
}
|
|
465
451
|
return positions;
|
|
466
452
|
}
|
|
467
|
-
function loadLocaleData(path, optimize) {
|
|
453
|
+
async function loadLocaleData(path, optimize) {
|
|
468
454
|
// The path is validated during option processing before the build starts
|
|
469
455
|
const content = fs.readFileSync(path, 'utf8');
|
|
470
456
|
// NOTE: This can be removed once the locale data files are preprocessed in the framework
|
|
471
457
|
if (optimize) {
|
|
472
|
-
const result = terserMangle(content, {
|
|
458
|
+
const result = await terserMangle(content, {
|
|
473
459
|
compress: true,
|
|
474
460
|
ecma: 5,
|
|
475
461
|
});
|
|
@@ -94,6 +94,27 @@ async function generateI18nBrowserWebpackConfigFromContext(options, context, web
|
|
|
94
94
|
config.resolve.alias = {};
|
|
95
95
|
}
|
|
96
96
|
config.resolve.alias['@angular/localize/init'] = require.resolve('./empty.js');
|
|
97
|
+
// Update file hashes to include translation file content
|
|
98
|
+
const i18nHash = Object.values(i18n.locales).reduce((data, locale) => data + (locale.integrity || ''), '');
|
|
99
|
+
if (!config.plugins) {
|
|
100
|
+
config.plugins = [];
|
|
101
|
+
}
|
|
102
|
+
config.plugins.push({
|
|
103
|
+
apply(compiler) {
|
|
104
|
+
compiler.hooks.compilation.tap('build-angular', compilation => {
|
|
105
|
+
// Webpack typings do not contain template hashForChunk hook
|
|
106
|
+
// tslint:disable-next-line: no-any
|
|
107
|
+
compilation.mainTemplate.hooks.hashForChunk.tap('build-angular', (hash) => {
|
|
108
|
+
hash.update('$localize' + i18nHash);
|
|
109
|
+
});
|
|
110
|
+
// Webpack typings do not contain hooks property
|
|
111
|
+
// tslint:disable-next-line: no-any
|
|
112
|
+
compilation.chunkTemplate.hooks.hashForChunk.tap('build-angular', (hash) => {
|
|
113
|
+
hash.update('$localize' + i18nHash);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
},
|
|
117
|
+
});
|
|
97
118
|
}
|
|
98
119
|
return { ...result, i18n };
|
|
99
120
|
}
|