Skip to content

Commit 889e751

Browse files
committed
fix(@angular-devkit/build-angular): display accurate sizes for downlevelled files
Fixes angular#15425
1 parent f02a8cc commit 889e751

File tree

2 files changed

+114
-18
lines changed
  • packages/angular_devkit/build_angular/src

2 files changed

+114
-18
lines changed

packages/angular_devkit/build_angular/src/angular-cli-files/utilities/stats.ts

+32-11
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
// tslint:disable
99
// TODO: cleanup this file, it's copied as is from Angular CLI.
1010
import { tags, terminal } from '@angular-devkit/core';
11+
import * as path from 'path';
1112

1213

1314
const { bold, green, red, reset, white, yellow } = terminal;
@@ -23,27 +24,47 @@ export function formatSize(size: number): string {
2324
return `${+(size / Math.pow(1024, index)).toPrecision(3)} ${abbreviations[index]}`;
2425
}
2526

27+
export function generateBundleStats(
28+
info: {
29+
id: string | number;
30+
size?: number;
31+
files: string[];
32+
names?: string[];
33+
entry: boolean;
34+
initial: boolean;
35+
rendered?: boolean;
36+
},
37+
colors: boolean,
38+
): string {
39+
const g = (x: string) => (colors ? bold(green(x)) : x);
40+
const y = (x: string) => (colors ? bold(yellow(x)) : x);
41+
42+
const size = typeof info.size === 'number' ? ` ${formatSize(info.size)}` : '';
43+
const files = info.files.map(f => path.basename(f)).join(', ');
44+
const names = info.names ? ` (${info.names.join(', ')})` : '';
45+
const initial = y(info.entry ? '[entry]' : info.initial ? '[initial]' : '');
46+
const flags = ['rendered', 'recorded']
47+
.map(f => (f && (info as any)[f] ? g(` [${f}]`) : ''))
48+
.join('');
49+
50+
return `chunk {${y(info.id.toString())}} ${g(files)}${names}${size} ${initial}${flags}`;
51+
}
52+
53+
export function generateBuildStats(hash: string, time: number, colors: boolean): string {
54+
const w = (x: string) => colors ? bold(white(x)) : x;
55+
return `Date: ${w(new Date().toISOString())} - Hash: ${w(hash)} - Time: ${w('' + time)}ms`
56+
}
2657

2758
export function statsToString(json: any, statsConfig: any) {
2859
const colors = statsConfig.colors;
2960
const rs = (x: string) => colors ? reset(x) : x;
3061
const w = (x: string) => colors ? bold(white(x)) : x;
31-
const g = (x: string) => colors ? bold(green(x)) : x;
32-
const y = (x: string) => colors ? bold(yellow(x)) : x;
3362

3463
const changedChunksStats = json.chunks
3564
.filter((chunk: any) => chunk.rendered)
3665
.map((chunk: any) => {
3766
const asset = json.assets.filter((x: any) => x.name == chunk.files[0])[0];
38-
const size = asset ? ` ${formatSize(asset.size)}` : '';
39-
const files = chunk.files.join(', ');
40-
const names = chunk.names ? ` (${chunk.names.join(', ')})` : '';
41-
const initial = y(chunk.entry ? '[entry]' : chunk.initial ? '[initial]' : '');
42-
const flags = ['rendered', 'recorded']
43-
.map(f => f && chunk[f] ? g(` [${f}]`) : '')
44-
.join('');
45-
46-
return `chunk {${y(chunk.id)}} ${g(files)}${names}${size} ${initial}${flags}`;
67+
return generateBundleStats({ ...chunk, size: asset && asset.size }, colors);
4768
});
4869

4970
const unchangedChunkNumber = json.chunks.length - changedChunksStats.length;

packages/angular_devkit/build_angular/src/browser/index.ts

+82-7
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import { NodeJsSyncHost } from '@angular-devkit/core/node';
2727
import { createHash } from 'crypto';
2828
import * as findCacheDirectory from 'find-cache-dir';
2929
import * as fs from 'fs';
30-
import * as os from 'os';
3130
import * as path from 'path';
3231
import { from, of } from 'rxjs';
3332
import { bufferCount, catchError, concatMap, map, mergeScan, switchMap } from 'rxjs/operators';
@@ -53,6 +52,8 @@ import {
5352
import { readTsconfig } from '../angular-cli-files/utilities/read-tsconfig';
5453
import { augmentAppWithServiceWorker } from '../angular-cli-files/utilities/service-worker';
5554
import {
55+
generateBuildStats,
56+
generateBundleStats,
5657
statsErrorsToString,
5758
statsToString,
5859
statsWarningsToString,
@@ -66,7 +67,12 @@ import {
6667
normalizeSourceMaps,
6768
} from '../utils';
6869
import { manglingDisabled } from '../utils/mangle-options';
69-
import { CacheKey, ProcessBundleOptions, ProcessBundleResult } from '../utils/process-bundle';
70+
import {
71+
CacheKey,
72+
ProcessBundleFile,
73+
ProcessBundleOptions,
74+
ProcessBundleResult,
75+
} from '../utils/process-bundle';
7076
import { assertCompatibleAngularVersion } from '../utils/version';
7177
import {
7278
generateBrowserWebpackConfigFromContext,
@@ -200,9 +206,6 @@ export function buildWebpackBrowser(
200206
// Check Angular version.
201207
assertCompatibleAngularVersion(context.workspaceRoot, context.logger);
202208

203-
const loggingFn =
204-
transforms.logging || createBrowserLoggingCallback(!!options.verbose, context.logger);
205-
206209
return from(initialize(options, context, host, transforms.webpackConfiguration)).pipe(
207210
// tslint:disable-next-line: no-big-function
208211
switchMap(({ workspace, config: configs }) => {
@@ -233,14 +236,24 @@ export function buildWebpackBrowser(
233236
`);
234237
}
235238

239+
const useBundleDownleveling =
240+
isDifferentialLoadingNeeded && !(fullDifferential || options.watch);
241+
const startTime = Date.now();
242+
236243
return from(configs).pipe(
237244
// the concurrency parameter (3rd parameter of mergeScan) is deliberately
238245
// set to 1 to make sure the build steps are executed in sequence.
239246
mergeScan(
240247
(lastResult, config) => {
241248
// Make sure to only run the 2nd build step, if 1st one succeeded
242249
if (lastResult.success) {
243-
return runWebpack(config, context, { logging: loggingFn });
250+
return runWebpack(config, context, {
251+
logging:
252+
transforms.logging ||
253+
(useBundleDownleveling
254+
? () => {}
255+
: createBrowserLoggingCallback(!!options.verbose, context.logger)),
256+
});
244257
} else {
245258
return of();
246259
}
@@ -274,7 +287,7 @@ export function buildWebpackBrowser(
274287
noModuleFiles = secondBuild.emittedFiles;
275288
}
276289
} else if (isDifferentialLoadingNeeded && !fullDifferential) {
277-
const { emittedFiles = [] } = firstBuild;
290+
const { emittedFiles = [], webpackStats } = firstBuild;
278291
moduleFiles = [];
279292
noModuleFiles = [];
280293

@@ -611,6 +624,68 @@ export function buildWebpackBrowser(
611624
}
612625

613626
context.logger.info('ES5 bundle generation complete.');
627+
628+
type ArrayElement<A> = A extends ReadonlyArray<infer T> ? T : never;
629+
function generateBundleInfoStats(
630+
name: string | undefined,
631+
bundle: ProcessBundleFile,
632+
chunk: ArrayElement<webpack.Stats.ToJsonOutput['chunks']> | undefined,
633+
): string {
634+
return generateBundleStats(
635+
{
636+
id: chunk ? chunk.id.toString() : '',
637+
size: bundle.size,
638+
files: bundle.map ? [bundle.filename, bundle.map.filename] : [bundle.filename],
639+
names: name ? [name] : [],
640+
entry: name === 'runtime',
641+
initial: !!chunk && chunk.initial,
642+
rendered: true,
643+
},
644+
true,
645+
);
646+
}
647+
648+
let bundleInfoText = '';
649+
const processedNames = new Set<string>();
650+
for (const result of processResults) {
651+
if (result.name) {
652+
processedNames.add(result.name);
653+
}
654+
const chunk =
655+
webpackStats &&
656+
webpackStats.chunks &&
657+
webpackStats.chunks.find(c => result.name && c.names.includes(result.name));
658+
if (result.original) {
659+
bundleInfoText +=
660+
'\n' + generateBundleInfoStats(result.name, result.original, chunk);
661+
}
662+
if (result.downlevel) {
663+
bundleInfoText +=
664+
'\n' + generateBundleInfoStats(result.name, result.downlevel, chunk);
665+
}
666+
}
667+
668+
if (webpackStats && webpackStats.chunks) {
669+
for (const chunk of webpackStats.chunks) {
670+
if (chunk.names.some(n => processedNames.has(n))) {
671+
continue;
672+
}
673+
674+
const asset =
675+
webpackStats.assets && webpackStats.assets.find(a => a.name === chunk.files[0]);
676+
bundleInfoText +=
677+
'\n' + generateBundleStats({ ...chunk, size: asset && asset.size }, true);
678+
}
679+
}
680+
681+
bundleInfoText +=
682+
'\n' +
683+
generateBuildStats(
684+
(webpackStats && webpackStats.hash) || '<unknown>',
685+
Date.now() - startTime,
686+
true,
687+
);
688+
context.logger.info(bundleInfoText);
614689
} else {
615690
const { emittedFiles = [] } = firstBuild;
616691
files = emittedFiles.filter(x => x.name !== 'polyfills-es5');

0 commit comments

Comments
 (0)