Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(@angular/cli): Ability to specify budgets for your apps
Closes #7139
- Loading branch information
Showing
10 changed files
with
621 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
# Budgets | ||
|
||
As applications grow in functionality, they also grow in size. Budgets is a feature in the | ||
Angular CLI which allows you to set budget thresholds in your configuration to ensure parts | ||
of your application stay within boundries which you set. | ||
|
||
**.angular-cli.json** | ||
``` | ||
{ | ||
... | ||
apps: [ | ||
{ | ||
... | ||
budgets: [] | ||
} | ||
] | ||
} | ||
``` | ||
|
||
## Budget Definition | ||
|
||
- type | ||
- The type of budget. | ||
- Possible values: | ||
- bundle - The size of a specific bundle. | ||
- initial - The initial size of the app. | ||
- allScript - The size of all scripts. | ||
- all - The size of the entire app. | ||
- anyScript - The size of any one script. | ||
- any - The size of any file. | ||
- name | ||
- The name of the bundle. | ||
- Required only for type of "bundle" | ||
- baseline | ||
- The baseline size for comparison. | ||
- maximumWarning | ||
- The maximum threshold for warning relative to the baseline. | ||
- maximumError | ||
- The maximum threshold for error relative to the baseline. | ||
- minimumWarning | ||
- The minimum threshold for warning relative to the baseline. | ||
- minimumError | ||
- The minimum threshold for error relative to the baseline. | ||
- warning | ||
- The threshold for warning relative to the baseline (min & max). | ||
- error | ||
- The threshold for error relative to the baseline (min & max). | ||
|
||
## Specifying sizes | ||
|
||
Available formats: | ||
123 - size in bytes | ||
123b - size in bytes | ||
123kb - size in kilobytes | ||
123mb - size in megabytes | ||
12% - percentage | ||
|
||
## NOTES | ||
|
||
All sizes are relative to baseline. | ||
Percentages are not valid for baseline values. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
/** | ||
* @license | ||
* Copyright Google Inc. All Rights Reserved. | ||
* | ||
* Use of this source code is governed by an MIT-style license that can be | ||
* found in the LICENSE file at https://angular.io/license | ||
*/ | ||
import { Budget, calculateBytes, calculateSizes } from '../utilities/bundle-calculator'; | ||
|
||
interface Thresholds { | ||
maximumWarning?: number; | ||
maximumError?: number; | ||
minimumWarning?: number; | ||
minimumError?: number; | ||
warningLow?: number; | ||
warningHigh?: number; | ||
errorLow?: number; | ||
errorHigh?: number; | ||
} | ||
|
||
export interface BundleBudgetPluginOptions { | ||
budgets: Budget[]; | ||
} | ||
|
||
export class BundleBudgetPlugin { | ||
constructor(private options: BundleBudgetPluginOptions) {} | ||
|
||
apply(compiler: any): void { | ||
const { budgets } = this.options; | ||
compiler.plugin('after-emit', (compilation: any, cb: Function) => { | ||
if (!budgets || budgets.length === 0) { | ||
cb(); | ||
return; | ||
} | ||
|
||
budgets.map(budget => { | ||
const thresholds = this.calcualte(budget); | ||
return { | ||
budget, | ||
thresholds, | ||
sizes: calculateSizes(budget, compilation) | ||
}; | ||
}) | ||
.forEach(budgetCheck => { | ||
budgetCheck.sizes.forEach(size => { | ||
if (budgetCheck.thresholds.maximumWarning) { | ||
if (budgetCheck.thresholds.maximumWarning < size.size) { | ||
compilation.warnings.push(`budgets, maximum exceeded for ${size.label}.`); | ||
} | ||
} | ||
if (budgetCheck.thresholds.maximumError) { | ||
if (budgetCheck.thresholds.maximumError < size.size) { | ||
compilation.errors.push(`budgets, maximum exceeded for ${size.label}.`); | ||
} | ||
} | ||
if (budgetCheck.thresholds.minimumWarning) { | ||
if (budgetCheck.thresholds.minimumWarning > size.size) { | ||
compilation.warnings.push(`budgets, minimum exceeded for ${size.label}.`); | ||
} | ||
} | ||
if (budgetCheck.thresholds.minimumError) { | ||
if (budgetCheck.thresholds.minimumError > size.size) { | ||
compilation.errors.push(`budgets, minimum exceeded for ${size.label}.`); | ||
} | ||
} | ||
if (budgetCheck.thresholds.warningLow) { | ||
if (budgetCheck.thresholds.warningLow > size.size) { | ||
compilation.warnings.push(`budgets, minimum exceeded for ${size.label}.`); | ||
} | ||
} | ||
if (budgetCheck.thresholds.warningHigh) { | ||
if (budgetCheck.thresholds.warningHigh < size.size) { | ||
compilation.warnings.push(`budgets, maximum exceeded for ${size.label}.`); | ||
} | ||
} | ||
if (budgetCheck.thresholds.errorLow) { | ||
if (budgetCheck.thresholds.errorLow > size.size) { | ||
compilation.errors.push(`budgets, minimum exceeded for ${size.label}.`); | ||
} | ||
} | ||
if (budgetCheck.thresholds.errorHigh) { | ||
if (budgetCheck.thresholds.errorHigh < size.size) { | ||
compilation.errors.push(`budgets, maximum exceeded for ${size.label}.`); | ||
} | ||
} | ||
}); | ||
|
||
}); | ||
cb(); | ||
}); | ||
} | ||
|
||
private calcualte(budget: Budget): Thresholds { | ||
This comment has been minimized.
Sorry, something went wrong. |
||
let thresholds: Thresholds = {}; | ||
if (budget.maximumWarning) { | ||
thresholds.maximumWarning = calculateBytes(budget.maximumWarning, budget.baseline, 'pos'); | ||
} | ||
|
||
if (budget.maximumError) { | ||
thresholds.maximumError = calculateBytes(budget.maximumError, budget.baseline, 'pos'); | ||
} | ||
|
||
if (budget.minimumWarning) { | ||
thresholds.minimumWarning = calculateBytes(budget.minimumWarning, budget.baseline, 'neg'); | ||
} | ||
|
||
if (budget.minimumError) { | ||
thresholds.minimumError = calculateBytes(budget.minimumError, budget.baseline, 'neg'); | ||
} | ||
|
||
if (budget.warning) { | ||
thresholds.warningLow = calculateBytes(budget.warning, budget.baseline, 'neg'); | ||
} | ||
|
||
if (budget.warning) { | ||
thresholds.warningHigh = calculateBytes(budget.warning, budget.baseline, 'pos'); | ||
} | ||
|
||
if (budget.error) { | ||
thresholds.errorLow = calculateBytes(budget.error, budget.baseline, 'neg'); | ||
} | ||
|
||
if (budget.error) { | ||
thresholds.errorHigh = calculateBytes(budget.error, budget.baseline, 'pos'); | ||
} | ||
|
||
return thresholds; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Typo 😄