Skip to content

Commit 75abe2c

Browse files
committed
refactor(@angular/build): use build output files directly in stats and budgets
The bundle budget calculators and the console build stats output are now calculated directly from the build output file information instead of the esbuild metafile where possible. This provides a more generic method of accessing the information and can more accurately account for post-processing steps that may alter the output files. The metafile is still used for component style budgets and lazy chunk name information.
1 parent f3ba208 commit 75abe2c

File tree

3 files changed

+37
-28
lines changed

3 files changed

+37
-28
lines changed

packages/angular/build/src/builders/application/execute-build.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ export async function executeBuild(
104104
// Analyze files for bundle budget failures if present
105105
let budgetFailures: BudgetCalculatorResult[] | undefined;
106106
if (options.budgets) {
107-
const compatStats = generateBudgetStats(metafile, initialFiles);
107+
const compatStats = generateBudgetStats(metafile, outputFiles, initialFiles);
108108
budgetFailures = [...checkBudgets(options.budgets, compatStats, true)];
109109
for (const { message, severity } of budgetFailures) {
110110
if (severity === 'error') {
@@ -191,6 +191,7 @@ export async function executeBuild(
191191
executionResult.addLog(
192192
logBuildStats(
193193
metafile,
194+
outputFiles,
194195
initialFiles,
195196
budgetFailures,
196197
colors,

packages/angular/build/src/tools/esbuild/budget-stats.ts

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,12 @@
88

99
import type { Metafile } from 'esbuild';
1010
import type { BudgetStats } from '../../utils/bundle-calculator';
11-
import type { InitialFileRecord } from './bundler-context';
12-
import { getEntryPointName } from './utils';
11+
import {
12+
type BuildOutputFile,
13+
BuildOutputFileType,
14+
type InitialFileRecord,
15+
} from './bundler-context';
16+
import { getChunkNameFromMetafile } from './utils';
1317

1418
/**
1519
* Generates a bundle budget calculator compatible stats object that provides
@@ -21,44 +25,52 @@ import { getEntryPointName } from './utils';
2125
*/
2226
export function generateBudgetStats(
2327
metafile: Metafile,
28+
outputFiles: BuildOutputFile[],
2429
initialFiles: Map<string, InitialFileRecord>,
2530
): BudgetStats {
2631
const stats: Required<BudgetStats> = {
2732
chunks: [],
2833
assets: [],
2934
};
3035

31-
for (const [file, entry] of Object.entries(metafile.outputs)) {
36+
for (const { path: file, size, type } of outputFiles) {
3237
if (!file.endsWith('.js') && !file.endsWith('.css')) {
3338
continue;
3439
}
3540

3641
// Exclude server bundles
37-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
38-
if ((entry as any)['ng-platform-server']) {
42+
if (type === BuildOutputFileType.Server) {
3943
continue;
4044
}
4145

4246
const initialRecord = initialFiles.get(file);
43-
let name = initialRecord?.name;
44-
if (name === undefined && entry.entryPoint) {
45-
// For non-initial lazy modules, convert the entry point file into a Webpack compatible name
46-
name = getEntryPointName(entry.entryPoint);
47-
}
47+
const name = initialRecord?.name ?? getChunkNameFromMetafile(metafile, file);
4848

4949
stats.chunks.push({
5050
files: [file],
5151
initial: !!initialRecord,
5252
names: name ? [name] : undefined,
5353
});
5454

55+
stats.assets.push({
56+
name: file,
57+
size,
58+
});
59+
}
60+
61+
// Add component styles from metafile
62+
// TODO: Provide this information directly from the AOT compiler
63+
for (const entry of Object.values(metafile.outputs)) {
5564
// 'ng-component' is set by the angular plugin's component stylesheet bundler
5665
// eslint-disable-next-line @typescript-eslint/no-explicit-any
5766
const componentStyle: boolean = (entry as any)['ng-component'];
67+
if (!componentStyle) {
68+
continue;
69+
}
5870

5971
stats.assets.push({
60-
// Component styles use the input file while all other outputs use the result file
61-
name: (componentStyle && Object.keys(entry.inputs)[0]) || file,
72+
// Component styles use the input file
73+
name: Object.keys(entry.inputs)[0],
6274
size: entry.bytes,
6375
componentStyle,
6476
});

packages/angular/build/src/tools/esbuild/utils.ts

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { BuildOutputAsset, ExecutionResult } from './bundler-execution-result';
2727

2828
export function logBuildStats(
2929
metafile: Metafile,
30+
outputFiles: BuildOutputFile[],
3031
initial: Map<string, InitialFileRecord>,
3132
budgetFailures: BudgetCalculatorResult[] | undefined,
3233
colors: boolean,
@@ -39,39 +40,28 @@ export function logBuildStats(
3940
const serverStats: BundleStats[] = [];
4041
let unchangedCount = 0;
4142

42-
for (const [file, output] of Object.entries(metafile.outputs)) {
43+
for (const { path: file, size, type } of outputFiles) {
4344
// Only display JavaScript and CSS files
4445
if (!/\.(?:css|m?js)$/.test(file)) {
4546
continue;
4647
}
4748

48-
// Skip internal component resources
49-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
50-
if ((output as any)['ng-component']) {
51-
continue;
52-
}
53-
5449
// Show only changed files if a changed list is provided
5550
if (changedFiles && !changedFiles.has(file)) {
5651
++unchangedCount;
5752
continue;
5853
}
5954

60-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
61-
const isPlatformServer = (output as any)['ng-platform-server'];
55+
const isPlatformServer = type === BuildOutputFileType.Server;
6256
if (isPlatformServer && !ssrOutputEnabled) {
6357
// Only log server build stats when SSR is enabled.
6458
continue;
6559
}
6660

67-
let name = initial.get(file)?.name;
68-
if (name === undefined && output.entryPoint) {
69-
name = getEntryPointName(output.entryPoint);
70-
}
71-
61+
const name = initial.get(file)?.name ?? getChunkNameFromMetafile(metafile, file);
7262
const stat: BundleStats = {
7363
initial: initial.has(file),
74-
stats: [file, name ?? '-', output.bytes, estimatedTransferSizes?.get(file) ?? '-'],
64+
stats: [file, name ?? '-', size, estimatedTransferSizes?.get(file) ?? '-'],
7565
};
7666

7767
if (isPlatformServer) {
@@ -102,6 +92,12 @@ export function logBuildStats(
10292
return '';
10393
}
10494

95+
export function getChunkNameFromMetafile(metafile: Metafile, file: string): string | undefined {
96+
if (metafile.outputs[file]?.entryPoint) {
97+
return getEntryPointName(metafile.outputs[file].entryPoint);
98+
}
99+
}
100+
105101
export async function calculateEstimatedTransferSizes(
106102
outputFiles: OutputFile[],
107103
): Promise<Map<string, number>> {

0 commit comments

Comments
 (0)