Skip to content

Commit

Permalink
refactor(@angular-devkit/build-angular): reduce Webpack specific over…
Browse files Browse the repository at this point in the history
…lap in bundle budget calculator

Webpack-specific types and imports have been reduced within the logic and test code for the bundle
budget calculator. This reduces the amount of unused code that needs to be loaded when not using
a Webpack-based bundler. The Webpack component style budget plugin was also updated to use only
the `checkBudgets` function instead of the previous two function setup which limits the needed
amount of runtime exports for the plugin.
  • Loading branch information
clydin committed Apr 15, 2024
1 parent 7549f1b commit 4d27c38
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@

import * as path from 'path';
import { Compilation, Compiler } from 'webpack';
import { Budget, Type } from '../../../builders/browser/schema';
import {
BudgetAsset,
BudgetEntry,
BudgetType,
ThresholdSeverity,
calculateThresholds,
checkThresholds,
checkBudgets,
} from '../../../utils/bundle-calculator';
import { addError, addWarning } from '../../../utils/webpack-diagnostics';

Expand All @@ -23,10 +24,10 @@ const PLUGIN_NAME = 'AnyComponentStyleBudgetChecker';
* budget is exceeded by a particular component's styles.
*/
export class AnyComponentStyleBudgetChecker {
private readonly budgets: Budget[];
private readonly budgets: BudgetEntry[];

constructor(budgets: Budget[]) {
this.budgets = budgets.filter((budget) => budget.type === Type.AnyComponentStyle);
constructor(budgets: BudgetEntry[]) {
this.budgets = budgets.filter((budget) => budget.type === BudgetType.AnyComponentStyle);
}

apply(compiler: Compiler) {
Expand All @@ -49,30 +50,28 @@ export class AnyComponentStyleBudgetChecker {

const cssExtensions = ['.css', '.scss', '.less', '.sass'];

const componentStyles = Object.keys(compilation.assets)
const componentStyles: BudgetAsset[] = Object.keys(compilation.assets)
.filter((name) => cssExtensions.includes(path.extname(name)))
.map((name) => ({
name,
size: compilation.assets[name].size(),
label: name,
componentStyle: true,
}));

const thresholds = this.budgets.flatMap((budget) => [...calculateThresholds(budget)]);
for (const { size, label } of componentStyles) {
for (const { severity, message } of checkThresholds(
thresholds[Symbol.iterator](),
size,
label,
)) {
switch (severity) {
case ThresholdSeverity.Warning:
addWarning(compilation, message);
break;
case ThresholdSeverity.Error:
addError(compilation, message);
break;
default:
assertNever(severity);
}
for (const { severity, message } of checkBudgets(
this.budgets,
{ chunks: [], assets: componentStyles },
true,
)) {
switch (severity) {
case ThresholdSeverity.Warning:
addWarning(compilation, message);
break;
case ThresholdSeverity.Error:
addError(compilation, message);
break;
default:
assertNever(severity);
}
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@
* found in the LICENSE file at https://angular.io/license
*/

import { Budget, Type } from '../builders/browser/schema';
import { Budget as BudgetEntry, Type as BudgetType } from '../builders/application/schema';
import { formatSize } from './format-bytes';

// Re-export to avoid direct schema importing throughout code
export { BudgetEntry, BudgetType };

interface Size {
size: number;
label?: string;
Expand Down Expand Up @@ -53,7 +56,7 @@ export interface BudgetStats {
assets?: BudgetAsset[];
}

export function* calculateThresholds(budget: Budget): IterableIterator<Threshold> {
export function* calculateThresholds(budget: BudgetEntry): IterableIterator<Threshold> {
if (budget.maximumWarning) {
yield {
limit: calculateBytes(budget.maximumWarning, budget.baseline, 1),
Expand Down Expand Up @@ -118,11 +121,11 @@ export function* calculateThresholds(budget: Budget): IterableIterator<Threshold
/**
* Calculates the sizes for bundles in the budget type provided.
*/
function calculateSizes(budget: Budget, stats: BudgetStats): Size[] {
function calculateSizes(budget: BudgetEntry, stats: BudgetStats): Size[] {
type CalculatorTypes = {
new (budget: Budget, chunks: BudgetChunk[], assets: BudgetAsset[]): Calculator;
new (budget: BudgetEntry, chunks: BudgetChunk[], assets: BudgetAsset[]): Calculator;
};
const calculatorMap: Record<Budget['type'], CalculatorTypes> = {
const calculatorMap: Record<BudgetType, CalculatorTypes> = {
all: AllCalculator,
allScript: AllScriptCalculator,
any: AnyCalculator,
Expand All @@ -148,7 +151,7 @@ function calculateSizes(budget: Budget, stats: BudgetStats): Size[] {

abstract class Calculator {
constructor(
protected budget: Budget,
protected budget: BudgetEntry,
protected chunks: BudgetChunk[],
protected assets: BudgetAsset[],
) {}
Expand Down Expand Up @@ -321,14 +324,14 @@ function calculateBytes(input: string, baseline?: string, factor: 1 | -1 = 1): n
}

export function* checkBudgets(
budgets: Budget[],
budgets: BudgetEntry[],
stats: BudgetStats,
checkComponentStyles?: boolean,
): IterableIterator<BudgetCalculatorResult> {
// Ignore AnyComponentStyle budgets as these are handled in `AnyComponentStyleBudgetChecker` unless requested
const computableBudgets = checkComponentStyles
? budgets
: budgets.filter((budget) => budget.type !== Type.AnyComponentStyle);
: budgets.filter((budget) => budget.type !== BudgetType.AnyComponentStyle);

for (const budget of computableBudgets) {
const sizes = calculateSizes(budget, stats);
Expand All @@ -339,7 +342,7 @@ export function* checkBudgets(
}

export function* checkThresholds(
thresholds: IterableIterator<Threshold>,
thresholds: Iterable<Threshold>,
size: number,
label?: string,
): IterableIterator<BudgetCalculatorResult> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,16 @@
* found in the LICENSE file at https://angular.io/license
*/

import { StatsCompilation } from 'webpack';
import { Budget, Type } from '../builders/browser/schema';
import { ThresholdSeverity, checkBudgets } from './bundle-calculator';
import { BudgetEntry, BudgetType, ThresholdSeverity, checkBudgets } from './bundle-calculator';

const KB = 1024;

describe('bundle-calculator', () => {
describe('checkBudgets()', () => {
it('yields maximum budgets exceeded', () => {
const budgets: Budget[] = [
const budgets: BudgetEntry[] = [
{
type: Type.Any,
type: BudgetType.Any,
maximumError: '1kb',
},
];
Expand All @@ -33,7 +31,7 @@ describe('bundle-calculator', () => {
size: 0.5 * KB,
},
],
} as unknown as StatsCompilation;
};

const failures = Array.from(checkBudgets(budgets, stats));

Expand All @@ -46,9 +44,9 @@ describe('bundle-calculator', () => {
});

it('yields minimum budgets exceeded', () => {
const budgets: Budget[] = [
const budgets: BudgetEntry[] = [
{
type: Type.Any,
type: BudgetType.Any,
minimumError: '1kb',
},
];
Expand All @@ -64,7 +62,7 @@ describe('bundle-calculator', () => {
size: 0.5 * KB,
},
],
} as unknown as StatsCompilation;
};

const failures = Array.from(checkBudgets(budgets, stats));

Expand All @@ -77,9 +75,9 @@ describe('bundle-calculator', () => {
});

it('yields exceeded bundle budgets', () => {
const budgets: Budget[] = [
const budgets: BudgetEntry[] = [
{
type: Type.Bundle,
type: BudgetType.Bundle,
name: 'foo',
maximumError: '1kb',
},
Expand All @@ -102,7 +100,7 @@ describe('bundle-calculator', () => {
size: 0.75 * KB,
},
],
} as unknown as StatsCompilation;
};

const failures = Array.from(checkBudgets(budgets, stats));

Expand All @@ -115,9 +113,9 @@ describe('bundle-calculator', () => {
});

it('yields exceeded initial budget', () => {
const budgets: Budget[] = [
const budgets: BudgetEntry[] = [
{
type: Type.Initial,
type: BudgetType.Initial,
maximumError: '1kb',
},
];
Expand All @@ -140,7 +138,7 @@ describe('bundle-calculator', () => {
size: 0.75 * KB,
},
],
} as unknown as StatsCompilation;
};

const failures = Array.from(checkBudgets(budgets, stats));

Expand All @@ -153,9 +151,9 @@ describe('bundle-calculator', () => {
});

it('yields exceeded total scripts budget', () => {
const budgets: Budget[] = [
const budgets: BudgetEntry[] = [
{
type: Type.AllScript,
type: BudgetType.AllScript,
maximumError: '1kb',
},
];
Expand All @@ -182,7 +180,7 @@ describe('bundle-calculator', () => {
size: 1.5 * KB,
},
],
} as unknown as StatsCompilation;
};

const failures = Array.from(checkBudgets(budgets, stats));

Expand All @@ -195,9 +193,9 @@ describe('bundle-calculator', () => {
});

it('yields exceeded total budget', () => {
const budgets: Budget[] = [
const budgets: BudgetEntry[] = [
{
type: Type.All,
type: BudgetType.All,
maximumError: '1kb',
},
];
Expand All @@ -220,7 +218,7 @@ describe('bundle-calculator', () => {
size: 0.75 * KB,
},
],
} as unknown as StatsCompilation;
};

const failures = Array.from(checkBudgets(budgets, stats));

Expand All @@ -233,9 +231,9 @@ describe('bundle-calculator', () => {
});

it('skips component style budgets', () => {
const budgets: Budget[] = [
const budgets: BudgetEntry[] = [
{
type: Type.AnyComponentStyle,
type: BudgetType.AnyComponentStyle,
maximumError: '1kb',
},
];
Expand All @@ -258,17 +256,17 @@ describe('bundle-calculator', () => {
size: 0.5 * KB,
},
],
} as unknown as StatsCompilation;
};

const failures = Array.from(checkBudgets(budgets, stats));

expect(failures.length).toBe(0);
});

it('yields exceeded individual script budget', () => {
const budgets: Budget[] = [
const budgets: BudgetEntry[] = [
{
type: Type.AnyScript,
type: BudgetType.AnyScript,
maximumError: '1kb',
},
];
Expand All @@ -291,7 +289,7 @@ describe('bundle-calculator', () => {
size: 0.5 * KB,
},
],
} as unknown as StatsCompilation;
};

const failures = Array.from(checkBudgets(budgets, stats));

Expand All @@ -304,9 +302,9 @@ describe('bundle-calculator', () => {
});

it('yields exceeded individual file budget', () => {
const budgets: Budget[] = [
const budgets: BudgetEntry[] = [
{
type: Type.Any,
type: BudgetType.Any,
maximumError: '1kb',
},
];
Expand All @@ -329,7 +327,7 @@ describe('bundle-calculator', () => {
size: 0.5 * KB,
},
],
} as unknown as StatsCompilation;
};

const failures = Array.from(checkBudgets(budgets, stats));

Expand Down

0 comments on commit 4d27c38

Please sign in to comment.