Skip to content

Commit 7f2d162

Browse files
committed
refactor(@angular-devkit/build-angular): reduce promise creation during estimated transfer size calculation
The promise creation overhead when calculating the estimated transfer size of the output files during an optimized build has been reduced by directly using the `brotliCompress` Node.js function instead of using a promisified variant. Node.js Only provides a callback-based async variant for brotli compression. This change allows for a single promise to be used.
1 parent a708dcc commit 7f2d162

File tree

1 file changed

+36
-23
lines changed
  • packages/angular_devkit/build_angular/src/tools/esbuild

1 file changed

+36
-23
lines changed

Diff for: packages/angular_devkit/build_angular/src/tools/esbuild/utils.ts

+36-23
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import { createHash } from 'node:crypto';
1212
import { constants as fsConstants } from 'node:fs';
1313
import fs from 'node:fs/promises';
1414
import path from 'node:path';
15-
import { promisify } from 'node:util';
1615
import { brotliCompress } from 'node:zlib';
1716
import { coerce } from 'semver';
1817
import { NormalizedOutputOptions } from '../../builders/application/options';
@@ -22,8 +21,6 @@ import { BundleStats, generateBuildStatsTable } from '../webpack/utils/stats';
2221
import { BuildOutputFile, BuildOutputFileType, InitialFileRecord } from './bundler-context';
2322
import { BuildOutputAsset } from './bundler-execution-result';
2423

25-
const compressAsync = promisify(brotliCompress);
26-
2724
export function logBuildStats(
2825
context: BuilderContext,
2926
metafile: Metafile,
@@ -87,31 +84,47 @@ export async function calculateEstimatedTransferSizes(
8784
outputFiles: OutputFile[],
8885
): Promise<Map<string, number>> {
8986
const sizes = new Map<string, number>();
90-
const pendingCompression = [];
87+
if (outputFiles.length <= 0) {
88+
return sizes;
89+
}
9190

92-
for (const outputFile of outputFiles) {
93-
// Only calculate JavaScript and CSS files
94-
if (!outputFile.path.endsWith('.js') && !outputFile.path.endsWith('.css')) {
95-
continue;
96-
}
91+
return new Promise((resolve, reject) => {
92+
let completeCount = 0;
93+
for (const outputFile of outputFiles) {
94+
// Only calculate JavaScript and CSS files
95+
if (!outputFile.path.endsWith('.js') && !outputFile.path.endsWith('.css')) {
96+
++completeCount;
97+
continue;
98+
}
9799

98-
// Skip compressing small files which may end being larger once compressed and will most likely not be
99-
// compressed in actual transit.
100-
if (outputFile.contents.byteLength < 1024) {
101-
sizes.set(outputFile.path, outputFile.contents.byteLength);
102-
continue;
103-
}
100+
// Skip compressing small files which may end being larger once compressed and will most likely not be
101+
// compressed in actual transit.
102+
if (outputFile.contents.byteLength < 1024) {
103+
sizes.set(outputFile.path, outputFile.contents.byteLength);
104+
++completeCount;
105+
continue;
106+
}
104107

105-
pendingCompression.push(
106-
compressAsync(outputFile.contents).then((result) =>
107-
sizes.set(outputFile.path, result.byteLength),
108-
),
109-
);
110-
}
108+
// Directly use the async callback function to minimize the number of Promises that need to be created.
109+
brotliCompress(outputFile.contents, (error, result) => {
110+
if (error) {
111+
reject(error);
111112

112-
await Promise.all(pendingCompression);
113+
return;
114+
}
113115

114-
return sizes;
116+
sizes.set(outputFile.path, result.byteLength);
117+
if (++completeCount >= outputFiles.length) {
118+
resolve(sizes);
119+
}
120+
});
121+
}
122+
123+
// Covers the case where no files need to be compressed
124+
if (completeCount >= outputFiles.length) {
125+
resolve(sizes);
126+
}
127+
});
115128
}
116129

117130
export async function withSpinner<T>(text: string, action: () => T | Promise<T>): Promise<T> {

0 commit comments

Comments
 (0)