@angular-devkit/build-angular 0.803.4 → 0.803.8
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 +7 -7
- package/plugins/webpack/analytics.d.ts +2 -1
- package/plugins/webpack/analytics.js +10 -1
- package/src/angular-cli-files/models/webpack-configs/common.js +7 -3
- package/src/angular-cli-files/utilities/package-chunk-sort.js +2 -0
- package/src/angular-cli-files/utilities/stats.d.ts +10 -0
- package/src/angular-cli-files/utilities/stats.js +20 -10
- package/src/browser/action-executor.d.ts +12 -0
- package/src/browser/action-executor.js +45 -0
- package/src/browser/index.js +201 -55
- package/src/protractor/index.js +1 -1
- package/src/utils/process-bundle.d.ts +20 -2
- package/src/utils/process-bundle.js +82 -19
package/package.json
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@angular-devkit/build-angular",
|
|
3
|
-
"version": "0.803.
|
|
3
|
+
"version": "0.803.8",
|
|
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.803.
|
|
11
|
-
"@angular-devkit/build-optimizer": "0.803.
|
|
12
|
-
"@angular-devkit/build-webpack": "0.803.
|
|
13
|
-
"@angular-devkit/core": "8.3.
|
|
10
|
+
"@angular-devkit/architect": "0.803.8",
|
|
11
|
+
"@angular-devkit/build-optimizer": "0.803.8",
|
|
12
|
+
"@angular-devkit/build-webpack": "0.803.8",
|
|
13
|
+
"@angular-devkit/core": "8.3.8",
|
|
14
14
|
"@babel/core": "7.5.5",
|
|
15
15
|
"@babel/preset-env": "7.5.5",
|
|
16
|
-
"@ngtools/webpack": "8.3.
|
|
16
|
+
"@ngtools/webpack": "8.3.8",
|
|
17
17
|
"ajv": "6.10.2",
|
|
18
18
|
"autoprefixer": "9.6.1",
|
|
19
19
|
"browserslist": "4.6.6",
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
"find-cache-dir": "3.0.0",
|
|
28
28
|
"glob": "7.1.4",
|
|
29
29
|
"istanbul-instrumenter-loader": "3.0.1",
|
|
30
|
+
"jest-worker": "24.9.0",
|
|
30
31
|
"karma-source-map-support": "1.4.0",
|
|
31
32
|
"less": "3.9.0",
|
|
32
33
|
"less-loader": "5.0.0",
|
|
@@ -61,7 +62,6 @@
|
|
|
61
62
|
"webpack-merge": "4.2.1",
|
|
62
63
|
"webpack-sources": "1.4.3",
|
|
63
64
|
"webpack-subresource-integrity": "1.1.0-rc.6",
|
|
64
|
-
"worker-farm": "1.7.0",
|
|
65
65
|
"worker-plugin": "3.2.0"
|
|
66
66
|
},
|
|
67
67
|
"peerDependencies": {
|
|
@@ -26,6 +26,7 @@ export declare function countOccurrences(source: string, match: string, wordBrea
|
|
|
26
26
|
* Holder of statistics related to the build.
|
|
27
27
|
*/
|
|
28
28
|
declare class AnalyticsBuildStats {
|
|
29
|
+
isIvy: boolean;
|
|
29
30
|
errors: string[];
|
|
30
31
|
numberOfNgOnInit: number;
|
|
31
32
|
numberOfComponents: number;
|
|
@@ -51,7 +52,7 @@ export declare class NgBuildAnalyticsPlugin {
|
|
|
51
52
|
constructor(_projectRoot: string, _analytics: analytics.Analytics, _category: string);
|
|
52
53
|
protected _reset(): void;
|
|
53
54
|
protected _getMetrics(stats: Stats): (string | number)[];
|
|
54
|
-
protected _getDimensions(stats: Stats): (
|
|
55
|
+
protected _getDimensions(stats: Stats): import("../../../../../dist-schema/packages/angular/cli/commands/config").Value[];
|
|
55
56
|
protected _reportBuildMetrics(stats: Stats): void;
|
|
56
57
|
protected _reportRebuildMetrics(stats: Stats): void;
|
|
57
58
|
protected _checkTsNormalModule(module: NormalModule): void;
|
|
@@ -54,6 +54,7 @@ exports.countOccurrences = countOccurrences;
|
|
|
54
54
|
*/
|
|
55
55
|
class AnalyticsBuildStats {
|
|
56
56
|
constructor() {
|
|
57
|
+
this.isIvy = false;
|
|
57
58
|
this.errors = [];
|
|
58
59
|
this.numberOfNgOnInit = 0;
|
|
59
60
|
this.numberOfComponents = 0;
|
|
@@ -106,6 +107,7 @@ class NgBuildAnalyticsPlugin {
|
|
|
106
107
|
// Adding commas before and after so the regex are easier to define filters.
|
|
107
108
|
dimensions[core_1.analytics.NgCliAnalyticsDimensions.BuildErrors] = `,${this._stats.errors.join()},`;
|
|
108
109
|
}
|
|
110
|
+
dimensions[core_1.analytics.NgCliAnalyticsDimensions.NgIvyEnabled] = this._stats.isIvy;
|
|
109
111
|
return dimensions;
|
|
110
112
|
}
|
|
111
113
|
_reportBuildMetrics(stats) {
|
|
@@ -129,7 +131,14 @@ class NgBuildAnalyticsPlugin {
|
|
|
129
131
|
// This does not include View Engine AOT compilation, we use the ngfactory for it.
|
|
130
132
|
this._stats.numberOfComponents += countOccurrences(module._source.source(), ' Component({');
|
|
131
133
|
// For Ivy we just count ngComponentDef.
|
|
132
|
-
|
|
134
|
+
const numIvyComponents = countOccurrences(module._source.source(), 'ngComponentDef', true);
|
|
135
|
+
this._stats.numberOfComponents += numIvyComponents;
|
|
136
|
+
// Check whether this is an Ivy app so that it can reported as part of analytics.
|
|
137
|
+
if (!this._stats.isIvy) {
|
|
138
|
+
if (numIvyComponents > 0 || module._source.source().includes('ngModuleDef')) {
|
|
139
|
+
this._stats.isIvy = true;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
133
142
|
}
|
|
134
143
|
}
|
|
135
144
|
_checkNgFactoryNormalModule(module) {
|
|
@@ -254,11 +254,13 @@ function getCommonConfig(wco) {
|
|
|
254
254
|
};
|
|
255
255
|
}
|
|
256
256
|
}
|
|
257
|
+
// TODO: Investigate why this fails for some packages: wco.supportES2015 ? 6 : 5;
|
|
258
|
+
const terserEcma = 5;
|
|
257
259
|
const terserOptions = {
|
|
258
260
|
warnings: !!buildOptions.verbose,
|
|
259
261
|
safari10: true,
|
|
260
262
|
output: {
|
|
261
|
-
ecma:
|
|
263
|
+
ecma: terserEcma,
|
|
262
264
|
comments: false,
|
|
263
265
|
webkit: true,
|
|
264
266
|
},
|
|
@@ -266,12 +268,12 @@ function getCommonConfig(wco) {
|
|
|
266
268
|
// to remove dev code, and ngI18nClosureMode to remove Closure compiler i18n code
|
|
267
269
|
compress: buildOptions.platform == 'server'
|
|
268
270
|
? {
|
|
269
|
-
ecma:
|
|
271
|
+
ecma: terserEcma,
|
|
270
272
|
global_defs: angularGlobalDefinitions,
|
|
271
273
|
keep_fnames: true,
|
|
272
274
|
}
|
|
273
275
|
: {
|
|
274
|
-
ecma:
|
|
276
|
+
ecma: terserEcma,
|
|
275
277
|
pure_getters: buildOptions.buildOptimizer,
|
|
276
278
|
// PURE comments work best with 3 passes.
|
|
277
279
|
// See https://github.com/webpack/webpack/issues/2899#issuecomment-317425926.
|
|
@@ -375,6 +377,8 @@ function getCommonConfig(wco) {
|
|
|
375
377
|
},
|
|
376
378
|
{
|
|
377
379
|
test: /\.js$/,
|
|
380
|
+
// Factory files are processed by BO in the rules added in typescript.ts.
|
|
381
|
+
exclude: /(ngfactory|ngstyle)\.js$/,
|
|
378
382
|
...buildOptimizerUseRule,
|
|
379
383
|
},
|
|
380
384
|
{
|
|
@@ -12,11 +12,13 @@ function generateEntryPoints(appConfig) {
|
|
|
12
12
|
};
|
|
13
13
|
const entryPoints = [
|
|
14
14
|
'polyfills-nomodule-es5',
|
|
15
|
+
'runtime',
|
|
15
16
|
'polyfills-es5',
|
|
16
17
|
'polyfills',
|
|
17
18
|
'sw-register',
|
|
18
19
|
...extraEntryPoints(appConfig.styles, 'styles'),
|
|
19
20
|
...extraEntryPoints(appConfig.scripts, 'scripts'),
|
|
21
|
+
'vendor',
|
|
20
22
|
'main',
|
|
21
23
|
];
|
|
22
24
|
const duplicates = [
|
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
export declare function formatSize(size: number): string;
|
|
2
|
+
export declare function generateBundleStats(info: {
|
|
3
|
+
id: string | number;
|
|
4
|
+
size?: number;
|
|
5
|
+
files: string[];
|
|
6
|
+
names?: string[];
|
|
7
|
+
entry: boolean;
|
|
8
|
+
initial: boolean;
|
|
9
|
+
rendered?: boolean;
|
|
10
|
+
}, colors: boolean): string;
|
|
11
|
+
export declare function generateBuildStats(hash: string, time: number, colors: boolean): string;
|
|
2
12
|
export declare function statsToString(json: any, statsConfig: any): string;
|
|
3
13
|
export declare function statsWarningsToString(json: any, statsConfig: any): string;
|
|
4
14
|
export declare function statsErrorsToString(json: any, statsConfig: any): string;
|
|
@@ -10,6 +10,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
10
10
|
// tslint:disable
|
|
11
11
|
// TODO: cleanup this file, it's copied as is from Angular CLI.
|
|
12
12
|
const core_1 = require("@angular-devkit/core");
|
|
13
|
+
const path = require("path");
|
|
13
14
|
const { bold, green, red, reset, white, yellow } = core_1.terminal;
|
|
14
15
|
function formatSize(size) {
|
|
15
16
|
if (size <= 0) {
|
|
@@ -20,24 +21,33 @@ function formatSize(size) {
|
|
|
20
21
|
return `${+(size / Math.pow(1024, index)).toPrecision(3)} ${abbreviations[index]}`;
|
|
21
22
|
}
|
|
22
23
|
exports.formatSize = formatSize;
|
|
24
|
+
function generateBundleStats(info, colors) {
|
|
25
|
+
const g = (x) => (colors ? bold(green(x)) : x);
|
|
26
|
+
const y = (x) => (colors ? bold(yellow(x)) : x);
|
|
27
|
+
const size = typeof info.size === 'number' ? ` ${formatSize(info.size)}` : '';
|
|
28
|
+
const files = info.files.map(f => path.basename(f)).join(', ');
|
|
29
|
+
const names = info.names ? ` (${info.names.join(', ')})` : '';
|
|
30
|
+
const initial = y(info.entry ? '[entry]' : info.initial ? '[initial]' : '');
|
|
31
|
+
const flags = ['rendered', 'recorded']
|
|
32
|
+
.map(f => (f && info[f] ? g(` [${f}]`) : ''))
|
|
33
|
+
.join('');
|
|
34
|
+
return `chunk {${y(info.id.toString())}} ${g(files)}${names}${size} ${initial}${flags}`;
|
|
35
|
+
}
|
|
36
|
+
exports.generateBundleStats = generateBundleStats;
|
|
37
|
+
function generateBuildStats(hash, time, colors) {
|
|
38
|
+
const w = (x) => colors ? bold(white(x)) : x;
|
|
39
|
+
return `Date: ${w(new Date().toISOString())} - Hash: ${w(hash)} - Time: ${w('' + time)}ms`;
|
|
40
|
+
}
|
|
41
|
+
exports.generateBuildStats = generateBuildStats;
|
|
23
42
|
function statsToString(json, statsConfig) {
|
|
24
43
|
const colors = statsConfig.colors;
|
|
25
44
|
const rs = (x) => colors ? reset(x) : x;
|
|
26
45
|
const w = (x) => colors ? bold(white(x)) : x;
|
|
27
|
-
const g = (x) => colors ? bold(green(x)) : x;
|
|
28
|
-
const y = (x) => colors ? bold(yellow(x)) : x;
|
|
29
46
|
const changedChunksStats = json.chunks
|
|
30
47
|
.filter((chunk) => chunk.rendered)
|
|
31
48
|
.map((chunk) => {
|
|
32
49
|
const asset = json.assets.filter((x) => x.name == chunk.files[0])[0];
|
|
33
|
-
|
|
34
|
-
const files = chunk.files.join(', ');
|
|
35
|
-
const names = chunk.names ? ` (${chunk.names.join(', ')})` : '';
|
|
36
|
-
const initial = y(chunk.entry ? '[entry]' : chunk.initial ? '[initial]' : '');
|
|
37
|
-
const flags = ['rendered', 'recorded']
|
|
38
|
-
.map(f => f && chunk[f] ? g(` [${f}]`) : '')
|
|
39
|
-
.join('');
|
|
40
|
-
return `chunk {${y(chunk.id)}} ${g(files)}${names}${size} ${initial}${flags}`;
|
|
50
|
+
return generateBundleStats({ ...chunk, size: asset && asset.size }, colors);
|
|
41
51
|
});
|
|
42
52
|
const unchangedChunkNumber = json.chunks.length - changedChunksStats.length;
|
|
43
53
|
if (unchangedChunkNumber > 0) {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare class ActionExecutor<Input extends {
|
|
2
|
+
size: number;
|
|
3
|
+
}, Output> {
|
|
4
|
+
private readonly actionName;
|
|
5
|
+
private largeWorker;
|
|
6
|
+
private smallWorker;
|
|
7
|
+
private smallThreshold;
|
|
8
|
+
constructor(actionFile: string, actionName: string);
|
|
9
|
+
execute(options: Input): Promise<Output>;
|
|
10
|
+
executeAll(options: Input[]): Promise<Output[]>;
|
|
11
|
+
stop(): void;
|
|
12
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/**
|
|
4
|
+
* @license
|
|
5
|
+
* Copyright Google Inc. All Rights Reserved.
|
|
6
|
+
*
|
|
7
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
8
|
+
* found in the LICENSE file at https://angular.io/license
|
|
9
|
+
*/
|
|
10
|
+
const jest_worker_1 = require("jest-worker");
|
|
11
|
+
const os = require("os");
|
|
12
|
+
class ActionExecutor {
|
|
13
|
+
constructor(actionFile, actionName) {
|
|
14
|
+
this.actionName = actionName;
|
|
15
|
+
this.smallThreshold = 32 * 1024;
|
|
16
|
+
// larger files are processed in a separate process to limit memory usage in the main process
|
|
17
|
+
this.largeWorker = new jest_worker_1.default(actionFile, {
|
|
18
|
+
exposedMethods: [actionName],
|
|
19
|
+
});
|
|
20
|
+
// small files are processed in a limited number of threads to improve speed
|
|
21
|
+
// The limited number also prevents a large increase in memory usage for an otherwise short operation
|
|
22
|
+
this.smallWorker = new jest_worker_1.default(actionFile, {
|
|
23
|
+
exposedMethods: [actionName],
|
|
24
|
+
numWorkers: os.cpus().length < 2 ? 1 : 2,
|
|
25
|
+
// Will automatically fallback to processes if not supported
|
|
26
|
+
enableWorkerThreads: true,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
execute(options) {
|
|
30
|
+
if (options.size > this.smallThreshold) {
|
|
31
|
+
return this.largeWorker[this.actionName](options);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
return this.smallWorker[this.actionName](options);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
executeAll(options) {
|
|
38
|
+
return Promise.all(options.map(o => this.execute(o)));
|
|
39
|
+
}
|
|
40
|
+
stop() {
|
|
41
|
+
this.largeWorker.end();
|
|
42
|
+
this.smallWorker.end();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
exports.ActionExecutor = ActionExecutor;
|
package/src/browser/index.js
CHANGED
|
@@ -18,7 +18,6 @@ const path = require("path");
|
|
|
18
18
|
const rxjs_1 = require("rxjs");
|
|
19
19
|
const operators_1 = require("rxjs/operators");
|
|
20
20
|
const typescript_1 = require("typescript");
|
|
21
|
-
const workerFarm = require("worker-farm");
|
|
22
21
|
const analytics_1 = require("../../plugins/webpack/analytics");
|
|
23
22
|
const webpack_configs_1 = require("../angular-cli-files/models/webpack-configs");
|
|
24
23
|
const write_index_html_1 = require("../angular-cli-files/utilities/index-file/write-index-html");
|
|
@@ -26,8 +25,10 @@ const read_tsconfig_1 = require("../angular-cli-files/utilities/read-tsconfig");
|
|
|
26
25
|
const service_worker_1 = require("../angular-cli-files/utilities/service-worker");
|
|
27
26
|
const stats_1 = require("../angular-cli-files/utilities/stats");
|
|
28
27
|
const utils_1 = require("../utils");
|
|
28
|
+
const mangle_options_1 = require("../utils/mangle-options");
|
|
29
29
|
const version_1 = require("../utils/version");
|
|
30
30
|
const webpack_browser_config_1 = require("../utils/webpack-browser-config");
|
|
31
|
+
const action_executor_1 = require("./action-executor");
|
|
31
32
|
const cacache = require('cacache');
|
|
32
33
|
const cacheDownlevelPath = findCacheDirectory({ name: 'angular-build-dl' });
|
|
33
34
|
const packageVersion = require('../../package.json').version;
|
|
@@ -104,7 +105,6 @@ function buildWebpackBrowser(options, context, transforms = {}) {
|
|
|
104
105
|
const root = core_1.normalize(context.workspaceRoot);
|
|
105
106
|
// Check Angular version.
|
|
106
107
|
version_1.assertCompatibleAngularVersion(context.workspaceRoot, context.logger);
|
|
107
|
-
const loggingFn = transforms.logging || createBrowserLoggingCallback(!!options.verbose, context.logger);
|
|
108
108
|
return rxjs_1.from(initialize(options, context, host, transforms.webpackConfiguration)).pipe(
|
|
109
109
|
// tslint:disable-next-line: no-big-function
|
|
110
110
|
operators_1.switchMap(({ workspace, config: configs }) => {
|
|
@@ -126,13 +126,20 @@ function buildWebpackBrowser(options, context, transforms = {}) {
|
|
|
126
126
|
referenced with script[type="module"] but they may not support ES2016+ syntax.
|
|
127
127
|
`);
|
|
128
128
|
}
|
|
129
|
+
const useBundleDownleveling = isDifferentialLoadingNeeded && !(utils_1.fullDifferential || options.watch);
|
|
130
|
+
const startTime = Date.now();
|
|
129
131
|
return rxjs_1.from(configs).pipe(
|
|
130
132
|
// the concurrency parameter (3rd parameter of mergeScan) is deliberately
|
|
131
133
|
// set to 1 to make sure the build steps are executed in sequence.
|
|
132
134
|
operators_1.mergeScan((lastResult, config) => {
|
|
133
135
|
// Make sure to only run the 2nd build step, if 1st one succeeded
|
|
134
136
|
if (lastResult.success) {
|
|
135
|
-
return build_webpack_1.runWebpack(config, context, {
|
|
137
|
+
return build_webpack_1.runWebpack(config, context, {
|
|
138
|
+
logging: transforms.logging ||
|
|
139
|
+
(useBundleDownleveling
|
|
140
|
+
? () => { }
|
|
141
|
+
: createBrowserLoggingCallback(!!options.verbose, context.logger)),
|
|
142
|
+
});
|
|
136
143
|
}
|
|
137
144
|
else {
|
|
138
145
|
return rxjs_1.of();
|
|
@@ -142,7 +149,19 @@ function buildWebpackBrowser(options, context, transforms = {}) {
|
|
|
142
149
|
operators_1.switchMap(async (buildEvents) => {
|
|
143
150
|
configs.length = 0;
|
|
144
151
|
const success = buildEvents.every(r => r.success);
|
|
145
|
-
if (success) {
|
|
152
|
+
if (!success && useBundleDownleveling) {
|
|
153
|
+
// If using bundle downleveling then there is only one build
|
|
154
|
+
// If it fails show any diagnostic messages and bail
|
|
155
|
+
const webpackStats = buildEvents[0].webpackStats;
|
|
156
|
+
if (webpackStats && webpackStats.warnings.length > 0) {
|
|
157
|
+
context.logger.warn(stats_1.statsWarningsToString(webpackStats, { colors: true }));
|
|
158
|
+
}
|
|
159
|
+
if (webpackStats && webpackStats.errors.length > 0) {
|
|
160
|
+
context.logger.error(stats_1.statsErrorsToString(webpackStats, { colors: true }));
|
|
161
|
+
}
|
|
162
|
+
return { success };
|
|
163
|
+
}
|
|
164
|
+
else if (success) {
|
|
146
165
|
let noModuleFiles;
|
|
147
166
|
let moduleFiles;
|
|
148
167
|
let files;
|
|
@@ -156,7 +175,7 @@ function buildWebpackBrowser(options, context, transforms = {}) {
|
|
|
156
175
|
}
|
|
157
176
|
}
|
|
158
177
|
else if (isDifferentialLoadingNeeded && !utils_1.fullDifferential) {
|
|
159
|
-
const { emittedFiles = [] } = firstBuild;
|
|
178
|
+
const { emittedFiles = [], webpackStats } = firstBuild;
|
|
160
179
|
moduleFiles = [];
|
|
161
180
|
noModuleFiles = [];
|
|
162
181
|
// Common options for all bundle process actions
|
|
@@ -166,6 +185,7 @@ function buildWebpackBrowser(options, context, transforms = {}) {
|
|
|
166
185
|
sourceMaps: sourceMapOptions.scripts,
|
|
167
186
|
hiddenSourceMaps: sourceMapOptions.hidden,
|
|
168
187
|
vendorSourceMaps: sourceMapOptions.vendor,
|
|
188
|
+
integrityAlgorithm: options.subresourceIntegrity ? 'sha384' : undefined,
|
|
169
189
|
};
|
|
170
190
|
const actions = [];
|
|
171
191
|
const seen = new Set();
|
|
@@ -189,8 +209,9 @@ function buildWebpackBrowser(options, context, transforms = {}) {
|
|
|
189
209
|
}
|
|
190
210
|
seen.add(file.file);
|
|
191
211
|
// All files at this point except ES5 polyfills are module scripts
|
|
192
|
-
const es5Polyfills = file.file.startsWith('polyfills-es5')
|
|
193
|
-
|
|
212
|
+
const es5Polyfills = file.file.startsWith('polyfills-es5') ||
|
|
213
|
+
file.file.startsWith('polyfills-nomodule-es5');
|
|
214
|
+
if (!es5Polyfills) {
|
|
194
215
|
moduleFiles.push(file);
|
|
195
216
|
}
|
|
196
217
|
// If not optimizing then ES2015 polyfills do not need processing
|
|
@@ -223,6 +244,9 @@ function buildWebpackBrowser(options, context, transforms = {}) {
|
|
|
223
244
|
filename,
|
|
224
245
|
code,
|
|
225
246
|
map,
|
|
247
|
+
// id is always present for non-assets
|
|
248
|
+
// tslint:disable-next-line: no-non-null-assertion
|
|
249
|
+
name: file.id,
|
|
226
250
|
optimizeOnly: true,
|
|
227
251
|
});
|
|
228
252
|
continue;
|
|
@@ -234,6 +258,9 @@ function buildWebpackBrowser(options, context, transforms = {}) {
|
|
|
234
258
|
filename,
|
|
235
259
|
code,
|
|
236
260
|
map,
|
|
261
|
+
// id is always present for non-assets
|
|
262
|
+
// tslint:disable-next-line: no-non-null-assertion
|
|
263
|
+
name: file.id,
|
|
237
264
|
runtime: file.file.startsWith('runtime'),
|
|
238
265
|
ignoreOriginal: es5Polyfills,
|
|
239
266
|
});
|
|
@@ -246,15 +273,21 @@ function buildWebpackBrowser(options, context, transforms = {}) {
|
|
|
246
273
|
// Execute the bundle processing actions
|
|
247
274
|
context.logger.info('Generating ES5 bundles for differential loading...');
|
|
248
275
|
const processActions = [];
|
|
276
|
+
let processRuntimeAction;
|
|
249
277
|
const cacheActions = [];
|
|
278
|
+
const processResults = [];
|
|
250
279
|
for (const action of actions) {
|
|
251
280
|
// Create base cache key with elements:
|
|
252
281
|
// * package version - different build-angular versions cause different final outputs
|
|
253
282
|
// * code length/hash - ensure cached version matches the same input code
|
|
254
|
-
const
|
|
283
|
+
const algorithm = action.integrityAlgorithm || 'sha1';
|
|
284
|
+
const codeHash = crypto_1.createHash(algorithm)
|
|
255
285
|
.update(action.code)
|
|
256
|
-
.digest('
|
|
257
|
-
|
|
286
|
+
.digest('base64');
|
|
287
|
+
let baseCacheKey = `${packageVersion}|${action.code.length}|${algorithm}-${codeHash}`;
|
|
288
|
+
if (mangle_options_1.manglingDisabled) {
|
|
289
|
+
baseCacheKey += '|MD';
|
|
290
|
+
}
|
|
258
291
|
// Postfix added to sourcemap cache keys when vendor sourcemaps are present
|
|
259
292
|
// Allows non-destructive caching of both variants
|
|
260
293
|
const SourceMapVendorPostfix = !!action.sourceMaps && action.vendorSourceMaps ? '|vendor' : '';
|
|
@@ -280,49 +313,99 @@ function buildWebpackBrowser(options, context, transforms = {}) {
|
|
|
280
313
|
}
|
|
281
314
|
// Attempt to get required cache entries
|
|
282
315
|
const cacheEntries = [];
|
|
316
|
+
let cached = cacheKeys.length > 0;
|
|
283
317
|
for (const key of cacheKeys) {
|
|
284
318
|
if (key) {
|
|
285
|
-
|
|
319
|
+
const entry = await cacache.get.info(cacheDownlevelPath, key);
|
|
320
|
+
if (!entry) {
|
|
321
|
+
cached = false;
|
|
322
|
+
break;
|
|
323
|
+
}
|
|
324
|
+
cacheEntries.push(entry);
|
|
286
325
|
}
|
|
287
326
|
else {
|
|
288
327
|
cacheEntries.push(null);
|
|
289
328
|
}
|
|
290
329
|
}
|
|
291
|
-
// Check if required cache entries are present
|
|
292
|
-
let cached = cacheKeys.length > 0;
|
|
293
|
-
for (let i = 0; i < cacheKeys.length; ++i) {
|
|
294
|
-
if (cacheKeys[i] && !cacheEntries[i]) {
|
|
295
|
-
cached = false;
|
|
296
|
-
break;
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
330
|
// If all required cached entries are present, use the cached entries
|
|
300
331
|
// Otherwise process the files
|
|
301
|
-
|
|
302
|
-
|
|
332
|
+
// If SRI is enabled always process the runtime bundle
|
|
333
|
+
// Lazy route integrity values are stored in the runtime bundle
|
|
334
|
+
if (action.integrityAlgorithm && action.runtime) {
|
|
335
|
+
processRuntimeAction = action;
|
|
336
|
+
}
|
|
337
|
+
else if (cached) {
|
|
338
|
+
const result = { name: action.name };
|
|
339
|
+
if (action.integrityAlgorithm) {
|
|
340
|
+
result.integrity = `${action.integrityAlgorithm}-${codeHash}`;
|
|
341
|
+
}
|
|
342
|
+
let cacheEntry = cacheEntries[0 /* OriginalCode */];
|
|
343
|
+
if (cacheEntry) {
|
|
303
344
|
cacheActions.push({
|
|
304
|
-
src:
|
|
345
|
+
src: cacheEntry.path,
|
|
305
346
|
dest: action.filename,
|
|
306
347
|
});
|
|
348
|
+
result.original = {
|
|
349
|
+
filename: action.filename,
|
|
350
|
+
size: cacheEntry.size,
|
|
351
|
+
integrity: cacheEntry.metadata && cacheEntry.metadata.integrity,
|
|
352
|
+
};
|
|
353
|
+
cacheEntry = cacheEntries[1 /* OriginalMap */];
|
|
354
|
+
if (cacheEntry) {
|
|
355
|
+
cacheActions.push({
|
|
356
|
+
src: cacheEntry.path,
|
|
357
|
+
dest: action.filename + '.map',
|
|
358
|
+
});
|
|
359
|
+
result.original.map = {
|
|
360
|
+
filename: action.filename + '.map',
|
|
361
|
+
size: cacheEntry.size,
|
|
362
|
+
};
|
|
363
|
+
}
|
|
307
364
|
}
|
|
308
|
-
if (
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
365
|
+
else if (!action.ignoreOriginal) {
|
|
366
|
+
// If the original wasn't processed (and therefore not cached), add info
|
|
367
|
+
result.original = {
|
|
368
|
+
filename: action.filename,
|
|
369
|
+
size: Buffer.byteLength(action.code, 'utf8'),
|
|
370
|
+
map: action.map === undefined
|
|
371
|
+
? undefined
|
|
372
|
+
: {
|
|
373
|
+
filename: action.filename + '.map',
|
|
374
|
+
size: Buffer.byteLength(action.map, 'utf8'),
|
|
375
|
+
},
|
|
376
|
+
};
|
|
313
377
|
}
|
|
314
|
-
|
|
378
|
+
cacheEntry = cacheEntries[2 /* DownlevelCode */];
|
|
379
|
+
if (cacheEntry) {
|
|
315
380
|
cacheActions.push({
|
|
316
|
-
src:
|
|
381
|
+
src: cacheEntry.path,
|
|
317
382
|
dest: action.filename.replace('es2015', 'es5'),
|
|
318
383
|
});
|
|
384
|
+
result.downlevel = {
|
|
385
|
+
filename: action.filename.replace('es2015', 'es5'),
|
|
386
|
+
size: cacheEntry.size,
|
|
387
|
+
integrity: cacheEntry.metadata && cacheEntry.metadata.integrity,
|
|
388
|
+
};
|
|
389
|
+
cacheEntry = cacheEntries[3 /* DownlevelMap */];
|
|
390
|
+
if (cacheEntry) {
|
|
391
|
+
cacheActions.push({
|
|
392
|
+
src: cacheEntry.path,
|
|
393
|
+
dest: action.filename.replace('es2015', 'es5') + '.map',
|
|
394
|
+
});
|
|
395
|
+
result.downlevel.map = {
|
|
396
|
+
filename: action.filename.replace('es2015', 'es5') + '.map',
|
|
397
|
+
size: cacheEntry.size,
|
|
398
|
+
};
|
|
399
|
+
}
|
|
319
400
|
}
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
401
|
+
processResults.push(result);
|
|
402
|
+
}
|
|
403
|
+
else if (action.runtime) {
|
|
404
|
+
processRuntimeAction = {
|
|
405
|
+
...action,
|
|
406
|
+
cacheKeys,
|
|
407
|
+
cachePath: cacheDownlevelPath || undefined,
|
|
408
|
+
};
|
|
326
409
|
}
|
|
327
410
|
else {
|
|
328
411
|
processActions.push({
|
|
@@ -332,7 +415,24 @@ function buildWebpackBrowser(options, context, transforms = {}) {
|
|
|
332
415
|
});
|
|
333
416
|
}
|
|
334
417
|
}
|
|
418
|
+
// Workaround Node.js issue prior to 10.16 with copyFile on macOS
|
|
419
|
+
// https://github.com/angular/angular-cli/issues/15544 & https://github.com/nodejs/node/pull/27241
|
|
420
|
+
let copyFileWorkaround = false;
|
|
421
|
+
if (process.platform === 'darwin') {
|
|
422
|
+
const version = process.versions.node.split('.').map(part => Number(part));
|
|
423
|
+
if (version[0] < 10 ||
|
|
424
|
+
version[0] === 11 ||
|
|
425
|
+
(version[0] === 10 && version[1] < 16)) {
|
|
426
|
+
copyFileWorkaround = true;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
335
429
|
for (const action of cacheActions) {
|
|
430
|
+
if (copyFileWorkaround) {
|
|
431
|
+
try {
|
|
432
|
+
fs.unlinkSync(action.dest);
|
|
433
|
+
}
|
|
434
|
+
catch (_b) { }
|
|
435
|
+
}
|
|
336
436
|
fs.copyFileSync(action.src, action.dest, fs.constants.COPYFILE_FICLONE);
|
|
337
437
|
if (process.platform !== 'win32') {
|
|
338
438
|
// The cache writes entries as readonly and when using copyFile the permissions will also be copied.
|
|
@@ -341,28 +441,74 @@ function buildWebpackBrowser(options, context, transforms = {}) {
|
|
|
341
441
|
}
|
|
342
442
|
}
|
|
343
443
|
if (processActions.length > 0) {
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
});
|
|
444
|
+
const workerFile = require.resolve('../utils/process-bundle');
|
|
445
|
+
const executor = new action_executor_1.ActionExecutor(path.extname(workerFile) !== '.ts'
|
|
446
|
+
? workerFile
|
|
447
|
+
: require.resolve('../utils/process-bundle-bootstrap'), 'process');
|
|
448
|
+
try {
|
|
449
|
+
const results = await executor.executeAll(processActions.map(a => ({ ...a, size: a.code.length })));
|
|
450
|
+
results.forEach(result => processResults.push(result));
|
|
451
|
+
}
|
|
452
|
+
finally {
|
|
453
|
+
executor.stop();
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
// Runtime must be processed after all other files
|
|
457
|
+
if (processRuntimeAction) {
|
|
458
|
+
const runtimeOptions = {
|
|
459
|
+
...processRuntimeAction,
|
|
460
|
+
runtimeData: processResults,
|
|
461
|
+
};
|
|
462
|
+
processResults.push(await Promise.resolve().then(() => require('../utils/process-bundle')).then(m => m.process(runtimeOptions)));
|
|
364
463
|
}
|
|
365
464
|
context.logger.info('ES5 bundle generation complete.');
|
|
465
|
+
function generateBundleInfoStats(id, bundle, chunk) {
|
|
466
|
+
return stats_1.generateBundleStats({
|
|
467
|
+
id,
|
|
468
|
+
size: bundle.size,
|
|
469
|
+
files: bundle.map ? [bundle.filename, bundle.map.filename] : [bundle.filename],
|
|
470
|
+
names: chunk && chunk.names,
|
|
471
|
+
entry: !!chunk && chunk.names.includes('runtime'),
|
|
472
|
+
initial: !!chunk && chunk.initial,
|
|
473
|
+
rendered: true,
|
|
474
|
+
}, true);
|
|
475
|
+
}
|
|
476
|
+
let bundleInfoText = '';
|
|
477
|
+
const processedNames = new Set();
|
|
478
|
+
for (const result of processResults) {
|
|
479
|
+
processedNames.add(result.name);
|
|
480
|
+
const chunk = webpackStats &&
|
|
481
|
+
webpackStats.chunks &&
|
|
482
|
+
webpackStats.chunks.find(c => result.name === c.id.toString());
|
|
483
|
+
if (result.original) {
|
|
484
|
+
bundleInfoText +=
|
|
485
|
+
'\n' + generateBundleInfoStats(result.name, result.original, chunk);
|
|
486
|
+
}
|
|
487
|
+
if (result.downlevel) {
|
|
488
|
+
bundleInfoText +=
|
|
489
|
+
'\n' + generateBundleInfoStats(result.name, result.downlevel, chunk);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
if (webpackStats && webpackStats.chunks) {
|
|
493
|
+
for (const chunk of webpackStats.chunks) {
|
|
494
|
+
if (processedNames.has(chunk.id.toString())) {
|
|
495
|
+
continue;
|
|
496
|
+
}
|
|
497
|
+
const asset = webpackStats.assets && webpackStats.assets.find(a => a.name === chunk.files[0]);
|
|
498
|
+
bundleInfoText +=
|
|
499
|
+
'\n' + stats_1.generateBundleStats({ ...chunk, size: asset && asset.size }, true);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
bundleInfoText +=
|
|
503
|
+
'\n' +
|
|
504
|
+
stats_1.generateBuildStats((webpackStats && webpackStats.hash) || '<unknown>', Date.now() - startTime, true);
|
|
505
|
+
context.logger.info(bundleInfoText);
|
|
506
|
+
if (webpackStats && webpackStats.warnings.length > 0) {
|
|
507
|
+
context.logger.warn(stats_1.statsWarningsToString(webpackStats, { colors: true }));
|
|
508
|
+
}
|
|
509
|
+
if (webpackStats && webpackStats.errors.length > 0) {
|
|
510
|
+
context.logger.error(stats_1.statsErrorsToString(webpackStats, { colors: true }));
|
|
511
|
+
}
|
|
366
512
|
}
|
|
367
513
|
else {
|
|
368
514
|
const { emittedFiles = [] } = firstBuild;
|
package/src/protractor/index.js
CHANGED
|
@@ -71,7 +71,7 @@ async function execute(options, context) {
|
|
|
71
71
|
if (options.webdriverUpdate) {
|
|
72
72
|
await updateWebdriver();
|
|
73
73
|
}
|
|
74
|
-
let baseUrl;
|
|
74
|
+
let baseUrl = options.baseUrl;
|
|
75
75
|
let server;
|
|
76
76
|
if (options.devServerTarget) {
|
|
77
77
|
const target = architect_1.targetFromTargetString(options.devServerTarget);
|
|
@@ -2,15 +2,33 @@ export interface ProcessBundleOptions {
|
|
|
2
2
|
filename: string;
|
|
3
3
|
code: string;
|
|
4
4
|
map?: string;
|
|
5
|
+
name: string;
|
|
5
6
|
sourceMaps?: boolean;
|
|
6
7
|
hiddenSourceMaps?: boolean;
|
|
7
8
|
vendorSourceMaps?: boolean;
|
|
8
9
|
runtime?: boolean;
|
|
9
|
-
optimize
|
|
10
|
+
optimize?: boolean;
|
|
10
11
|
optimizeOnly?: boolean;
|
|
11
12
|
ignoreOriginal?: boolean;
|
|
12
13
|
cacheKeys?: (string | null)[];
|
|
13
14
|
cachePath?: string;
|
|
15
|
+
integrityAlgorithm?: 'sha256' | 'sha384' | 'sha512';
|
|
16
|
+
runtimeData?: ProcessBundleResult[];
|
|
17
|
+
}
|
|
18
|
+
export interface ProcessBundleResult {
|
|
19
|
+
name: string;
|
|
20
|
+
integrity?: string;
|
|
21
|
+
original?: ProcessBundleFile;
|
|
22
|
+
downlevel?: ProcessBundleFile;
|
|
23
|
+
}
|
|
24
|
+
export interface ProcessBundleFile {
|
|
25
|
+
filename: string;
|
|
26
|
+
size: number;
|
|
27
|
+
integrity?: string;
|
|
28
|
+
map?: {
|
|
29
|
+
filename: string;
|
|
30
|
+
size: number;
|
|
31
|
+
};
|
|
14
32
|
}
|
|
15
33
|
export declare const enum CacheKey {
|
|
16
34
|
OriginalCode = 0,
|
|
@@ -18,4 +36,4 @@ export declare const enum CacheKey {
|
|
|
18
36
|
DownlevelCode = 2,
|
|
19
37
|
DownlevelMap = 3
|
|
20
38
|
}
|
|
21
|
-
export declare function process(options: ProcessBundleOptions
|
|
39
|
+
export declare function process(options: ProcessBundleOptions): Promise<ProcessBundleResult>;
|
|
@@ -7,6 +7,7 @@ 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 crypto_1 = require("crypto");
|
|
10
11
|
const fs = require("fs");
|
|
11
12
|
const path = require("path");
|
|
12
13
|
const source_map_1 = require("source-map");
|
|
@@ -14,34 +15,47 @@ const terser_1 = require("terser");
|
|
|
14
15
|
const mangle_options_1 = require("./mangle-options");
|
|
15
16
|
const { transformAsync } = require('@babel/core');
|
|
16
17
|
const cacache = require('cacache');
|
|
17
|
-
function process(options
|
|
18
|
-
processWorker(options).then(() => callback(null, {}), error => callback(error));
|
|
19
|
-
}
|
|
20
|
-
exports.process = process;
|
|
21
|
-
async function processWorker(options) {
|
|
18
|
+
async function process(options) {
|
|
22
19
|
if (!options.cacheKeys) {
|
|
23
20
|
options.cacheKeys = [];
|
|
24
21
|
}
|
|
25
22
|
// If no downlevelling required than just mangle code and return
|
|
26
23
|
if (options.optimizeOnly) {
|
|
27
|
-
|
|
24
|
+
const result = { name: options.name };
|
|
25
|
+
if (options.integrityAlgorithm) {
|
|
26
|
+
result.integrity = generateIntegrityValue(options.integrityAlgorithm, options.code);
|
|
27
|
+
}
|
|
28
|
+
// Replace integrity hashes with updated values
|
|
29
|
+
// NOTE: This should eventually be a babel plugin
|
|
30
|
+
if (options.runtime && options.integrityAlgorithm && options.runtimeData) {
|
|
31
|
+
for (const data of options.runtimeData) {
|
|
32
|
+
if (!data.integrity || !data.original || !data.original.integrity) {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
options.code = options.code.replace(data.integrity, data.original.integrity);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
result.original = await mangleOriginal(options);
|
|
39
|
+
return result;
|
|
28
40
|
}
|
|
29
41
|
// if code size is larger than 500kB, manually handle sourcemaps with newer source-map package.
|
|
30
42
|
// babel currently uses an older version that still supports sync calls
|
|
31
43
|
const codeSize = Buffer.byteLength(options.code, 'utf8');
|
|
32
|
-
const
|
|
44
|
+
const mapSize = options.map ? Buffer.byteLength(options.map, 'utf8') : 0;
|
|
45
|
+
const manualSourceMaps = codeSize >= 500 * 1024 || mapSize >= 500 * 1024;
|
|
33
46
|
// downlevel the bundle
|
|
34
47
|
let { code, map } = await transformAsync(options.code, {
|
|
35
48
|
filename: options.filename,
|
|
36
49
|
inputSourceMap: !manualSourceMaps && options.map !== undefined && JSON.parse(options.map),
|
|
37
50
|
babelrc: false,
|
|
38
|
-
// modules aren't needed since the bundles use
|
|
39
|
-
// loose generates more ES5-like code but does not strictly adhere to the ES2015 spec (Typescript is loose)
|
|
51
|
+
// modules aren't needed since the bundles use webpack's custom module loading
|
|
40
52
|
// 'transform-typeof-symbol' generates slower code
|
|
41
53
|
presets: [
|
|
42
|
-
['@babel/preset-env', { modules: false,
|
|
54
|
+
['@babel/preset-env', { modules: false, exclude: ['transform-typeof-symbol'] }],
|
|
43
55
|
],
|
|
44
|
-
minified:
|
|
56
|
+
minified: options.optimize,
|
|
57
|
+
// `false` ensures it is disabled and prevents large file warnings
|
|
58
|
+
compact: options.optimize || false,
|
|
45
59
|
sourceMaps: options.sourceMaps,
|
|
46
60
|
});
|
|
47
61
|
const newFilePath = options.filename.replace('es2015', 'es5');
|
|
@@ -49,6 +63,16 @@ async function processWorker(options) {
|
|
|
49
63
|
// Extra spacing is intentional to align source line positions
|
|
50
64
|
if (options.runtime) {
|
|
51
65
|
code = code.replace('"-es2015.', ' "-es5.');
|
|
66
|
+
// Replace integrity hashes with updated values
|
|
67
|
+
// NOTE: This should eventually be a babel plugin
|
|
68
|
+
if (options.integrityAlgorithm && options.runtimeData) {
|
|
69
|
+
for (const data of options.runtimeData) {
|
|
70
|
+
if (!data.integrity || !data.downlevel || !data.downlevel.integrity) {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
code = code.replace(data.integrity, data.downlevel.integrity);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
52
76
|
}
|
|
53
77
|
if (options.sourceMaps && manualSourceMaps && options.map) {
|
|
54
78
|
const generator = new source_map_1.SourceMapGenerator();
|
|
@@ -88,11 +112,12 @@ async function processWorker(options) {
|
|
|
88
112
|
map.file = path.basename(newFilePath);
|
|
89
113
|
map.sourceRoot = sourceRoot;
|
|
90
114
|
}
|
|
115
|
+
const result = { name: options.name };
|
|
91
116
|
if (options.optimize) {
|
|
92
117
|
// Note: Investigate converting the AST instead of re-parsing
|
|
93
118
|
// estree -> terser is already supported; need babel -> estree/terser
|
|
94
119
|
// Mangle downlevel code
|
|
95
|
-
const
|
|
120
|
+
const minifyOutput = terser_1.minify(code, {
|
|
96
121
|
compress: true,
|
|
97
122
|
ecma: 5,
|
|
98
123
|
mangle: !mangle_options_1.manglingDisabled,
|
|
@@ -106,14 +131,14 @@ async function processWorker(options) {
|
|
|
106
131
|
content: map,
|
|
107
132
|
},
|
|
108
133
|
});
|
|
109
|
-
if (
|
|
110
|
-
throw
|
|
134
|
+
if (minifyOutput.error) {
|
|
135
|
+
throw minifyOutput.error;
|
|
111
136
|
}
|
|
112
|
-
code =
|
|
113
|
-
map =
|
|
137
|
+
code = minifyOutput.code;
|
|
138
|
+
map = minifyOutput.map;
|
|
114
139
|
// Mangle original code
|
|
115
140
|
if (!options.ignoreOriginal) {
|
|
116
|
-
await mangleOriginal(options);
|
|
141
|
+
result.original = await mangleOriginal(options);
|
|
117
142
|
}
|
|
118
143
|
}
|
|
119
144
|
else if (map) {
|
|
@@ -128,11 +153,23 @@ async function processWorker(options) {
|
|
|
128
153
|
}
|
|
129
154
|
fs.writeFileSync(newFilePath + '.map', map);
|
|
130
155
|
}
|
|
156
|
+
result.downlevel = createFileEntry(newFilePath, code, map, options.integrityAlgorithm);
|
|
131
157
|
if (options.cachePath && options.cacheKeys[2 /* DownlevelCode */]) {
|
|
132
|
-
await cacache.put(options.cachePath, options.cacheKeys[2 /* DownlevelCode */], code
|
|
158
|
+
await cacache.put(options.cachePath, options.cacheKeys[2 /* DownlevelCode */], code, {
|
|
159
|
+
metadata: { integrity: result.downlevel.integrity },
|
|
160
|
+
});
|
|
133
161
|
}
|
|
134
162
|
fs.writeFileSync(newFilePath, code);
|
|
163
|
+
// If original was not processed, add info
|
|
164
|
+
if (!result.original && !options.ignoreOriginal) {
|
|
165
|
+
result.original = createFileEntry(options.filename, options.code, options.map, options.integrityAlgorithm);
|
|
166
|
+
}
|
|
167
|
+
if (options.integrityAlgorithm) {
|
|
168
|
+
result.integrity = generateIntegrityValue(options.integrityAlgorithm, options.code);
|
|
169
|
+
}
|
|
170
|
+
return result;
|
|
135
171
|
}
|
|
172
|
+
exports.process = process;
|
|
136
173
|
async function mangleOriginal(options) {
|
|
137
174
|
const resultOriginal = terser_1.minify(options.code, {
|
|
138
175
|
compress: false,
|
|
@@ -161,8 +198,34 @@ async function mangleOriginal(options) {
|
|
|
161
198
|
}
|
|
162
199
|
fs.writeFileSync(options.filename + '.map', resultOriginal.map);
|
|
163
200
|
}
|
|
201
|
+
const fileResult = createFileEntry(options.filename,
|
|
202
|
+
// tslint:disable-next-line: no-non-null-assertion
|
|
203
|
+
resultOriginal.code, resultOriginal.map, options.integrityAlgorithm);
|
|
164
204
|
if (options.cachePath && options.cacheKeys && options.cacheKeys[0 /* OriginalCode */]) {
|
|
165
|
-
await cacache.put(options.cachePath, options.cacheKeys[0 /* OriginalCode */], resultOriginal.code
|
|
205
|
+
await cacache.put(options.cachePath, options.cacheKeys[0 /* OriginalCode */], resultOriginal.code, {
|
|
206
|
+
metadata: { integrity: fileResult.integrity },
|
|
207
|
+
});
|
|
166
208
|
}
|
|
167
209
|
fs.writeFileSync(options.filename, resultOriginal.code);
|
|
210
|
+
return fileResult;
|
|
211
|
+
}
|
|
212
|
+
function createFileEntry(filename, code, map, integrityAlgorithm) {
|
|
213
|
+
return {
|
|
214
|
+
filename: filename,
|
|
215
|
+
size: Buffer.byteLength(code),
|
|
216
|
+
integrity: integrityAlgorithm && generateIntegrityValue(integrityAlgorithm, code),
|
|
217
|
+
map: !map
|
|
218
|
+
? undefined
|
|
219
|
+
: {
|
|
220
|
+
filename: filename + '.map',
|
|
221
|
+
size: Buffer.byteLength(map),
|
|
222
|
+
},
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
function generateIntegrityValue(hashAlgorithm, code) {
|
|
226
|
+
return (hashAlgorithm +
|
|
227
|
+
'-' +
|
|
228
|
+
crypto_1.createHash(hashAlgorithm)
|
|
229
|
+
.update(code)
|
|
230
|
+
.digest('base64'));
|
|
168
231
|
}
|