lighthouse 11.7.0-dev.20240416 → 11.7.0-dev.20240417
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/bin.js +0 -7
- package/cli/cli-flags.d.ts +1 -5
- package/cli/cli-flags.js +1 -5
- package/cli/test/smokehouse/core-tests.js +0 -2
- package/core/audits/byte-efficiency/render-blocking-resources.js +3 -1
- package/core/audits/byte-efficiency/unminified-css.js +2 -2
- package/core/audits/byte-efficiency/unused-css-rules.js +3 -1
- package/core/audits/font-display.js +2 -2
- package/core/audits/resource-summary.d.ts +2 -0
- package/core/audits/resource-summary.js +5 -4
- package/core/computed/resource-summary.d.ts +10 -12
- package/core/computed/resource-summary.js +12 -19
- package/core/computed/unused-css.d.ts +3 -1
- package/core/computed/unused-css.js +6 -5
- package/core/config/config-helpers.js +0 -4
- package/core/config/constants.js +0 -1
- package/core/config/default-config.js +1 -14
- package/core/gather/gatherers/css-usage.d.ts +0 -21
- package/core/gather/gatherers/css-usage.js +9 -119
- package/core/gather/gatherers/stylesheets.d.ts +26 -0
- package/core/gather/gatherers/stylesheets.js +138 -0
- package/core/lib/i18n/i18n.d.ts +0 -1
- package/core/lib/i18n/i18n.js +0 -2
- package/core/runner.js +0 -1
- package/dist/report/bundle.esm.js +2 -19
- package/dist/report/flow.js +5 -22
- package/dist/report/standalone.js +3 -20
- package/package.json +1 -1
- package/readme.md +2 -2
- package/report/assets/styles.css +0 -17
- package/report/renderer/components.js +1 -1
- package/report/renderer/dom.d.ts +1 -1
- package/report/renderer/dom.js +1 -1
- package/report/renderer/performance-category-renderer.js +0 -21
- package/shared/localization/locales/ar-XB.json +61 -91
- package/shared/localization/locales/ar.json +61 -91
- package/shared/localization/locales/bg.json +61 -91
- package/shared/localization/locales/ca.json +61 -91
- package/shared/localization/locales/cs.json +61 -91
- package/shared/localization/locales/da.json +61 -91
- package/shared/localization/locales/de.json +61 -91
- package/shared/localization/locales/el.json +61 -91
- package/shared/localization/locales/en-GB.json +61 -91
- package/shared/localization/locales/en-US.json +0 -30
- package/shared/localization/locales/en-XA.json +61 -91
- package/shared/localization/locales/en-XL.json +0 -30
- package/shared/localization/locales/es-419.json +61 -91
- package/shared/localization/locales/es.json +61 -91
- package/shared/localization/locales/fi.json +61 -91
- package/shared/localization/locales/fil.json +60 -90
- package/shared/localization/locales/fr.json +61 -91
- package/shared/localization/locales/he.json +61 -91
- package/shared/localization/locales/hi.json +61 -91
- package/shared/localization/locales/hr.json +62 -92
- package/shared/localization/locales/hu.json +61 -91
- package/shared/localization/locales/id.json +61 -91
- package/shared/localization/locales/it.json +61 -91
- package/shared/localization/locales/ja.json +61 -91
- package/shared/localization/locales/ko.json +61 -91
- package/shared/localization/locales/lt.json +61 -91
- package/shared/localization/locales/lv.json +61 -91
- package/shared/localization/locales/nl.json +61 -91
- package/shared/localization/locales/no.json +61 -91
- package/shared/localization/locales/pl.json +60 -90
- package/shared/localization/locales/pt-PT.json +61 -91
- package/shared/localization/locales/pt.json +63 -93
- package/shared/localization/locales/ro.json +61 -91
- package/shared/localization/locales/ru.json +61 -91
- package/shared/localization/locales/sk.json +61 -91
- package/shared/localization/locales/sl.json +61 -91
- package/shared/localization/locales/sr-Latn.json +61 -91
- package/shared/localization/locales/sr.json +61 -91
- package/shared/localization/locales/sv.json +61 -91
- package/shared/localization/locales/ta.json +60 -90
- package/shared/localization/locales/te.json +61 -91
- package/shared/localization/locales/th.json +61 -91
- package/shared/localization/locales/tr.json +61 -91
- package/shared/localization/locales/uk.json +61 -91
- package/shared/localization/locales/vi.json +60 -90
- package/shared/localization/locales/zh-HK.json +61 -91
- package/shared/localization/locales/zh-TW.json +60 -90
- package/shared/localization/locales/zh.json +61 -91
- package/tsconfig.json +0 -1
- package/types/artifacts.d.ts +3 -1
- package/types/externs.d.ts +0 -2
- package/types/lh.d.ts +0 -2
- package/types/lhr/settings.d.ts +0 -4
- package/core/audits/performance-budget.d.ts +0 -39
- package/core/audits/performance-budget.js +0 -154
- package/core/audits/timing-budget.d.ts +0 -43
- package/core/audits/timing-budget.js +0 -175
- package/core/config/budget.d.ts +0 -74
- package/core/config/budget.js +0 -340
- package/types/lhr/budget.d.ts +0 -60
package/tsconfig.json
CHANGED
|
@@ -37,7 +37,6 @@
|
|
|
37
37
|
"cli/test/fixtures/**/*.js",
|
|
38
38
|
"core/scripts/legacy-javascript/variants",
|
|
39
39
|
// These test files require further changes before they can be type checked.
|
|
40
|
-
"core/test/config/budget-test.js",
|
|
41
40
|
"core/test/config/config-helpers-test.js",
|
|
42
41
|
"core/test/config/config-plugin-test.js",
|
|
43
42
|
"core/test/config/default-config-test.js",
|
package/types/artifacts.d.ts
CHANGED
|
@@ -110,7 +110,7 @@ export interface GathererArtifacts extends PublicGathererArtifacts {
|
|
|
110
110
|
/** Array of all URLs cached in CacheStorage. */
|
|
111
111
|
CacheContents: string[];
|
|
112
112
|
/** CSS coverage information for styles used by page's final state. */
|
|
113
|
-
CSSUsage:
|
|
113
|
+
CSSUsage: Crdp.CSS.RuleUsage[];
|
|
114
114
|
/** The log of devtools protocol activity if there was a page load error and Chrome navigated to a `chrome-error://` page. */
|
|
115
115
|
DevtoolsLogError: DevtoolsLog;
|
|
116
116
|
/** Information on the document's doctype(or null if not present), specifically the name, publicId, and systemId.
|
|
@@ -145,6 +145,8 @@ export interface GathererArtifacts extends PublicGathererArtifacts {
|
|
|
145
145
|
SourceMaps: Array<Artifacts.SourceMap>;
|
|
146
146
|
/** Information on detected tech stacks (e.g. JS libraries) used by the page. */
|
|
147
147
|
Stacks: Artifacts.DetectedStack[];
|
|
148
|
+
/** CSS stylesheets found on the page. */
|
|
149
|
+
Stylesheets: Artifacts.CSSStyleSheetInfo[];
|
|
148
150
|
/** The trace if there was a page load error and Chrome navigated to a `chrome-error://` page. */
|
|
149
151
|
TraceError: Trace;
|
|
150
152
|
/** Elements associated with metrics (ie: Largest Contentful Paint element). */
|
package/types/externs.d.ts
CHANGED
|
@@ -57,8 +57,6 @@ export interface CliFlags extends Flags {
|
|
|
57
57
|
precomputedLanternDataPath?: string;
|
|
58
58
|
/** Path to the file where precomputed lantern data should be written to. */
|
|
59
59
|
lanternDataOutputPath?: string;
|
|
60
|
-
/** Path to the budget.json file for LightWallet. */
|
|
61
|
-
budgetPath?: string | null;
|
|
62
60
|
|
|
63
61
|
// The following are given defaults in cli-flags, so are not optional like in Flags or SharedFlagsSettings.
|
|
64
62
|
output: OutputMode[];
|
package/types/lh.d.ts
CHANGED
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
import {ArbitraryEqualityMap as ArbitraryEqualityMap_} from '../core/lib/arbitrary-equality-map.js';
|
|
8
8
|
import * as Artifacts_ from './artifacts.js';
|
|
9
9
|
import Audit_ from './audit.js';
|
|
10
|
-
import Budget_ from './lhr/budget.js';
|
|
11
10
|
import Config_ from './config.js';
|
|
12
11
|
import {Protocol as _Crdp} from 'devtools-protocol/types/protocol.js';
|
|
13
12
|
import {ProtocolMapping as _CrdpMappings} from 'devtools-protocol/types/protocol-mapping.js';
|
|
@@ -42,7 +41,6 @@ export import TraceCpuProfile = Artifacts_.TraceCpuProfile;
|
|
|
42
41
|
export import TraceEvent = Artifacts_.TraceEvent;
|
|
43
42
|
|
|
44
43
|
export import Audit = Audit_;
|
|
45
|
-
export import Budget = Budget_;
|
|
46
44
|
export import Config = Config_;
|
|
47
45
|
export import Crdp = _Crdp;
|
|
48
46
|
export import CrdpEvents = _CrdpMappings.Events;
|
package/types/lhr/settings.d.ts
CHANGED
|
@@ -6,8 +6,6 @@
|
|
|
6
6
|
|
|
7
7
|
import type {Protocol as Crdp} from 'devtools-protocol/types/protocol.js';
|
|
8
8
|
|
|
9
|
-
import Budget from './budget.js';
|
|
10
|
-
|
|
11
9
|
export type Locale = 'en-US'|'en'|'en-AU'|'en-GB'|'en-IE'|'en-SG'|'en-ZA'|'en-IN'|'ar-XB'|'ar'|'bg'|'ca'|'cs'|'da'|'de'|'el'|'en-XA'|'en-XL'|'es'|'es-419'|'es-AR'|'es-BO'|'es-BR'|'es-BZ'|'es-CL'|'es-CO'|'es-CR'|'es-CU'|'es-DO'|'es-EC'|'es-GT'|'es-HN'|'es-MX'|'es-NI'|'es-PA'|'es-PE'|'es-PR'|'es-PY'|'es-SV'|'es-US'|'es-UY'|'es-VE'|'fi'|'fil'|'fr'|'he'|'hi'|'hr'|'hu'|'gsw'|'id'|'in'|'it'|'iw'|'ja'|'ko'|'lt'|'lv'|'mo'|'nl'|'nb'|'no'|'pl'|'pt'|'pt-PT'|'ro'|'ru'|'sk'|'sl'|'sr'|'sr-Latn'|'sv'|'ta'|'te'|'th'|'tl'|'tr'|'uk'|'vi'|'zh'|'zh-HK'|'zh-TW';
|
|
12
10
|
|
|
13
11
|
/** Simulation settings that control the amount of network & cpu throttling in the run. */
|
|
@@ -109,8 +107,6 @@ export type ScreenEmulationSettings = {
|
|
|
109
107
|
channel?: string
|
|
110
108
|
/** Precomputed lantern estimates to use instead of observed analysis. */
|
|
111
109
|
precomputedLanternData?: PrecomputedLanternData | null;
|
|
112
|
-
/** The budget.json object for LightWallet. */
|
|
113
|
-
budgets?: Array<Budget> | null;
|
|
114
110
|
|
|
115
111
|
/** The number of milliseconds to wait after FCP until the page should be considered loaded. */
|
|
116
112
|
pauseAfterFcpMs?: number;
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
export default ResourceBudget;
|
|
2
|
-
export type ResourceEntry = import('../computed/resource-summary.js').ResourceEntry;
|
|
3
|
-
export type BudgetItem = {
|
|
4
|
-
resourceType: LH.Budget.ResourceType;
|
|
5
|
-
label: LH.IcuMessage;
|
|
6
|
-
requestCount: number;
|
|
7
|
-
transferSize: number;
|
|
8
|
-
sizeOverBudget: number | undefined;
|
|
9
|
-
countOverBudget: LH.IcuMessage | undefined;
|
|
10
|
-
};
|
|
11
|
-
/** @typedef {import('../computed/resource-summary.js').ResourceEntry} ResourceEntry */
|
|
12
|
-
/** @typedef {{resourceType: LH.Budget.ResourceType, label: LH.IcuMessage, requestCount: number, transferSize: number, sizeOverBudget: number | undefined, countOverBudget: LH.IcuMessage | undefined}} BudgetItem */
|
|
13
|
-
declare class ResourceBudget extends Audit {
|
|
14
|
-
/**
|
|
15
|
-
* @param {LH.Budget.ResourceType} resourceType
|
|
16
|
-
* @return {string}
|
|
17
|
-
*/
|
|
18
|
-
static getRowLabel(resourceType: LH.Budget.ResourceType): string;
|
|
19
|
-
/**
|
|
20
|
-
* @param {LH.Util.Immutable<LH.Budget>} budget
|
|
21
|
-
* @param {Record<LH.Budget.ResourceType, ResourceEntry>} summary
|
|
22
|
-
* @return {Array<BudgetItem>}
|
|
23
|
-
*/
|
|
24
|
-
static tableItems(budget: LH.Util.Immutable<LH.Budget>, summary: Record<LH.Budget.ResourceType, ResourceEntry>): Array<BudgetItem>;
|
|
25
|
-
/**
|
|
26
|
-
* @param {LH.Artifacts} artifacts
|
|
27
|
-
* @param {LH.Audit.Context} context
|
|
28
|
-
* @return {Promise<LH.Audit.Product>}
|
|
29
|
-
*/
|
|
30
|
-
static audit(artifacts: LH.Artifacts, context: LH.Audit.Context): Promise<LH.Audit.Product>;
|
|
31
|
-
}
|
|
32
|
-
export namespace UIStrings {
|
|
33
|
-
const title: string;
|
|
34
|
-
const description: string;
|
|
35
|
-
const requestCountOverBudget: string;
|
|
36
|
-
}
|
|
37
|
-
import { Budget } from '../config/budget.js';
|
|
38
|
-
import { Audit } from './audit.js';
|
|
39
|
-
//# sourceMappingURL=performance-budget.d.ts.map
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2019 Google LLC
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import {Audit} from './audit.js';
|
|
8
|
-
import {ResourceSummary} from '../computed/resource-summary.js';
|
|
9
|
-
import {MainResource} from '../computed/main-resource.js';
|
|
10
|
-
import {Budget} from '../config/budget.js';
|
|
11
|
-
import * as i18n from '../lib/i18n/i18n.js';
|
|
12
|
-
|
|
13
|
-
const UIStrings = {
|
|
14
|
-
/** Title of a Lighthouse audit that compares the size and quantity of page resources against targets set by the user. These targets are thought of as "performance budgets" because these metrics impact page performance (i.e. how quickly a page loads). */
|
|
15
|
-
title: 'Performance budget',
|
|
16
|
-
/** Description of a Lighthouse audit where a user sets budgets for the quantity and size of page resources. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
|
|
17
|
-
description: 'Keep the quantity and size of network requests under the targets ' +
|
|
18
|
-
'set by the provided performance budget. ' +
|
|
19
|
-
'[Learn more about performance budgets](https://developers.google.com/web/tools/lighthouse/audits/budgets).',
|
|
20
|
-
/** [ICU Syntax] Entry in a data table identifying the number of network requests of a particular type. Count will be a whole number. String should be as short as possible to be able to fit well into the table. */
|
|
21
|
-
requestCountOverBudget: `{count, plural,
|
|
22
|
-
=1 {1 request}
|
|
23
|
-
other {# requests}
|
|
24
|
-
}`,
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
|
|
28
|
-
|
|
29
|
-
/** @typedef {import('../computed/resource-summary.js').ResourceEntry} ResourceEntry */
|
|
30
|
-
/** @typedef {{resourceType: LH.Budget.ResourceType, label: LH.IcuMessage, requestCount: number, transferSize: number, sizeOverBudget: number | undefined, countOverBudget: LH.IcuMessage | undefined}} BudgetItem */
|
|
31
|
-
|
|
32
|
-
class ResourceBudget extends Audit {
|
|
33
|
-
/**
|
|
34
|
-
* @return {LH.Audit.Meta}
|
|
35
|
-
*/
|
|
36
|
-
static get meta() {
|
|
37
|
-
return {
|
|
38
|
-
id: 'performance-budget',
|
|
39
|
-
title: str_(UIStrings.title),
|
|
40
|
-
description: str_(UIStrings.description),
|
|
41
|
-
scoreDisplayMode: Audit.SCORING_MODES.INFORMATIVE,
|
|
42
|
-
supportedModes: ['navigation'],
|
|
43
|
-
requiredArtifacts: ['devtoolsLogs', 'URL'],
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* @param {LH.Budget.ResourceType} resourceType
|
|
49
|
-
* @return {string}
|
|
50
|
-
*/
|
|
51
|
-
static getRowLabel(resourceType) {
|
|
52
|
-
/** @type {Record<LH.Budget.ResourceType,string>} */
|
|
53
|
-
const strMappings = {
|
|
54
|
-
'total': i18n.UIStrings.totalResourceType,
|
|
55
|
-
'document': i18n.UIStrings.documentResourceType,
|
|
56
|
-
'script': i18n.UIStrings.scriptResourceType,
|
|
57
|
-
'stylesheet': i18n.UIStrings.stylesheetResourceType,
|
|
58
|
-
'image': i18n.UIStrings.imageResourceType,
|
|
59
|
-
'media': i18n.UIStrings.mediaResourceType,
|
|
60
|
-
'font': i18n.UIStrings.fontResourceType,
|
|
61
|
-
'other': i18n.UIStrings.otherResourceType,
|
|
62
|
-
'third-party': i18n.UIStrings.thirdPartyResourceType,
|
|
63
|
-
};
|
|
64
|
-
return strMappings[resourceType];
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* @param {LH.Util.Immutable<LH.Budget>} budget
|
|
69
|
-
* @param {Record<LH.Budget.ResourceType, ResourceEntry>} summary
|
|
70
|
-
* @return {Array<BudgetItem>}
|
|
71
|
-
*/
|
|
72
|
-
static tableItems(budget, summary) {
|
|
73
|
-
const resourceTypes = /** @type {Array<LH.Budget.ResourceType>} */ (Object.keys(summary));
|
|
74
|
-
return resourceTypes.map((resourceType) => {
|
|
75
|
-
const label = str_(this.getRowLabel(resourceType));
|
|
76
|
-
const requestCount = summary[resourceType].count;
|
|
77
|
-
const transferSize = summary[resourceType].transferSize;
|
|
78
|
-
|
|
79
|
-
let sizeOverBudget;
|
|
80
|
-
let countOverBudget;
|
|
81
|
-
|
|
82
|
-
if (budget.resourceSizes) {
|
|
83
|
-
const sizeBudget = budget.resourceSizes.find(b => b.resourceType === resourceType);
|
|
84
|
-
if (sizeBudget && (transferSize > (sizeBudget.budget * 1024))) {
|
|
85
|
-
sizeOverBudget = transferSize - (sizeBudget.budget * 1024);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
if (budget.resourceCounts) {
|
|
89
|
-
const countBudget = budget.resourceCounts.find(b => b.resourceType === resourceType);
|
|
90
|
-
if (countBudget && (requestCount > countBudget.budget)) {
|
|
91
|
-
const requestDifference = requestCount - countBudget.budget;
|
|
92
|
-
countOverBudget = str_(UIStrings.requestCountOverBudget, {count: requestDifference});
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
return {
|
|
96
|
-
resourceType,
|
|
97
|
-
label,
|
|
98
|
-
requestCount,
|
|
99
|
-
transferSize,
|
|
100
|
-
countOverBudget,
|
|
101
|
-
sizeOverBudget,
|
|
102
|
-
};
|
|
103
|
-
}).filter((row) => {
|
|
104
|
-
// Only resources with budgets should be included in the table
|
|
105
|
-
if (budget.resourceSizes) {
|
|
106
|
-
if (budget.resourceSizes.some(b => b.resourceType === row.resourceType)) return true;
|
|
107
|
-
}
|
|
108
|
-
if (budget.resourceCounts) {
|
|
109
|
-
if (budget.resourceCounts.some(b => b.resourceType === row.resourceType)) return true;
|
|
110
|
-
}
|
|
111
|
-
return false;
|
|
112
|
-
}).sort((a, b) => {
|
|
113
|
-
return (b.sizeOverBudget || 0) - (a.sizeOverBudget || 0);
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* @param {LH.Artifacts} artifacts
|
|
119
|
-
* @param {LH.Audit.Context} context
|
|
120
|
-
* @return {Promise<LH.Audit.Product>}
|
|
121
|
-
*/
|
|
122
|
-
static async audit(artifacts, context) {
|
|
123
|
-
const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
|
|
124
|
-
const data = {devtoolsLog, URL: artifacts.URL, budgets: context.settings.budgets};
|
|
125
|
-
const summary = await ResourceSummary.request(data, context);
|
|
126
|
-
const mainResource = await MainResource.request({URL: artifacts.URL, devtoolsLog}, context);
|
|
127
|
-
const budget = Budget.getMatchingBudget(context.settings.budgets, mainResource.url);
|
|
128
|
-
|
|
129
|
-
if (!budget) {
|
|
130
|
-
return {
|
|
131
|
-
score: 0,
|
|
132
|
-
notApplicable: true,
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/** @type {LH.Audit.Details.Table['headings']} */
|
|
137
|
-
const headers = [
|
|
138
|
-
{key: 'label', valueType: 'text', label: str_(i18n.UIStrings.columnResourceType)},
|
|
139
|
-
{key: 'requestCount', valueType: 'numeric', label: str_(i18n.UIStrings.columnRequests)},
|
|
140
|
-
{key: 'transferSize', valueType: 'bytes', label: str_(i18n.UIStrings.columnTransferSize)},
|
|
141
|
-
{key: 'countOverBudget', valueType: 'text', label: ''},
|
|
142
|
-
{key: 'sizeOverBudget', valueType: 'bytes', label: str_(i18n.UIStrings.columnOverBudget)},
|
|
143
|
-
];
|
|
144
|
-
|
|
145
|
-
return {
|
|
146
|
-
details: Audit.makeTableDetails(headers,
|
|
147
|
-
this.tableItems(budget, summary), {sortedBy: ['sizeOverBudget']}),
|
|
148
|
-
score: 1,
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
export default ResourceBudget;
|
|
154
|
-
export {UIStrings};
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
export default TimingBudget;
|
|
2
|
-
export type BudgetItem = {
|
|
3
|
-
metric: LH.Budget.TimingMetric;
|
|
4
|
-
label: LH.IcuMessage;
|
|
5
|
-
measurement?: LH.Audit.Details.NumericValue | number;
|
|
6
|
-
overBudget?: LH.Audit.Details.NumericValue | number;
|
|
7
|
-
};
|
|
8
|
-
/** @typedef {{metric: LH.Budget.TimingMetric, label: LH.IcuMessage, measurement?: LH.Audit.Details.NumericValue|number, overBudget?: LH.Audit.Details.NumericValue|number}} BudgetItem */
|
|
9
|
-
declare class TimingBudget extends Audit {
|
|
10
|
-
/**
|
|
11
|
-
* @param {LH.Budget.TimingMetric} timingMetric
|
|
12
|
-
* @return {LH.IcuMessage}
|
|
13
|
-
*/
|
|
14
|
-
static getRowLabel(timingMetric: LH.Budget.TimingMetric): LH.IcuMessage;
|
|
15
|
-
/**
|
|
16
|
-
* @param {LH.Budget.TimingMetric} timingMetric
|
|
17
|
-
* @param {LH.Artifacts.TimingSummary} summary
|
|
18
|
-
* @return {number|undefined}
|
|
19
|
-
*/
|
|
20
|
-
static getMeasurement(timingMetric: LH.Budget.TimingMetric, summary: LH.Artifacts.TimingSummary): number | undefined;
|
|
21
|
-
/**
|
|
22
|
-
* @param {LH.Util.Immutable<LH.Budget>} budget
|
|
23
|
-
* @param {LH.Artifacts.TimingSummary} summary
|
|
24
|
-
* @return {Array<BudgetItem>}
|
|
25
|
-
*/
|
|
26
|
-
static tableItems(budget: LH.Util.Immutable<LH.Budget>, summary: LH.Artifacts.TimingSummary): Array<BudgetItem>;
|
|
27
|
-
/**
|
|
28
|
-
* @param {LH.Artifacts} artifacts
|
|
29
|
-
* @param {LH.Audit.Context} context
|
|
30
|
-
* @return {Promise<LH.Audit.Product>}
|
|
31
|
-
*/
|
|
32
|
-
static audit(artifacts: LH.Artifacts, context: LH.Audit.Context): Promise<LH.Audit.Product>;
|
|
33
|
-
}
|
|
34
|
-
export namespace UIStrings {
|
|
35
|
-
const title: string;
|
|
36
|
-
const description: string;
|
|
37
|
-
const columnTimingMetric: string;
|
|
38
|
-
const columnMeasurement: string;
|
|
39
|
-
}
|
|
40
|
-
import { Budget } from '../config/budget.js';
|
|
41
|
-
import { Audit } from './audit.js';
|
|
42
|
-
import { TimingSummary } from '../computed/metrics/timing-summary.js';
|
|
43
|
-
//# sourceMappingURL=timing-budget.d.ts.map
|
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2019 Google LLC
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import {Audit} from './audit.js';
|
|
8
|
-
import {TimingSummary} from '../computed/metrics/timing-summary.js';
|
|
9
|
-
import {MainResource} from '../computed/main-resource.js';
|
|
10
|
-
import {Budget} from '../config/budget.js';
|
|
11
|
-
import * as i18n from '../lib/i18n/i18n.js';
|
|
12
|
-
|
|
13
|
-
const UIStrings = {
|
|
14
|
-
/** Title of a Lighthouse audit that compares how quickly the page loads against targets set by the user. Timing budgets are a type of performance budget. */
|
|
15
|
-
title: 'Timing budget',
|
|
16
|
-
/** Description of a Lighthouse audit where a user sets budgets for how quickly the page loads. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
|
|
17
|
-
description: 'Set a timing budget to help you keep an eye on the performance of your site. Performant sites load fast and respond to user input events quickly. [Learn more about performance budgets](https://developers.google.com/web/tools/lighthouse/audits/budgets).',
|
|
18
|
-
/** Label for a column in a data table; entries will be the names of different timing metrics, e.g. "Time to Interactive", "First Contentful Paint", etc. */
|
|
19
|
-
columnTimingMetric: 'Metric',
|
|
20
|
-
/** Label for a column in a data table; entries will be the measured value of a particular timing metric. Most entries will have a unit of milliseconds, but units could be other things as well. */
|
|
21
|
-
columnMeasurement: 'Measurement',
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
|
|
25
|
-
|
|
26
|
-
/** @typedef {{metric: LH.Budget.TimingMetric, label: LH.IcuMessage, measurement?: LH.Audit.Details.NumericValue|number, overBudget?: LH.Audit.Details.NumericValue|number}} BudgetItem */
|
|
27
|
-
|
|
28
|
-
class TimingBudget extends Audit {
|
|
29
|
-
/**
|
|
30
|
-
* @return {LH.Audit.Meta}
|
|
31
|
-
*/
|
|
32
|
-
static get meta() {
|
|
33
|
-
return {
|
|
34
|
-
id: 'timing-budget',
|
|
35
|
-
title: str_(UIStrings.title),
|
|
36
|
-
description: str_(UIStrings.description),
|
|
37
|
-
scoreDisplayMode: Audit.SCORING_MODES.INFORMATIVE,
|
|
38
|
-
supportedModes: ['navigation'],
|
|
39
|
-
requiredArtifacts: ['devtoolsLogs', 'traces', 'URL', 'GatherContext'],
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* @param {LH.Budget.TimingMetric} timingMetric
|
|
45
|
-
* @return {LH.IcuMessage}
|
|
46
|
-
*/
|
|
47
|
-
static getRowLabel(timingMetric) {
|
|
48
|
-
/** @type {Record<LH.Budget.TimingMetric, string>} */
|
|
49
|
-
const strMappings = {
|
|
50
|
-
'first-contentful-paint': i18n.UIStrings.firstContentfulPaintMetric,
|
|
51
|
-
'interactive': i18n.UIStrings.interactiveMetric,
|
|
52
|
-
'first-meaningful-paint': i18n.UIStrings.firstMeaningfulPaintMetric,
|
|
53
|
-
'max-potential-fid': i18n.UIStrings.maxPotentialFIDMetric,
|
|
54
|
-
'total-blocking-time': i18n.UIStrings.totalBlockingTimeMetric,
|
|
55
|
-
'speed-index': i18n.UIStrings.speedIndexMetric,
|
|
56
|
-
'largest-contentful-paint': i18n.UIStrings.largestContentfulPaintMetric,
|
|
57
|
-
'cumulative-layout-shift': i18n.UIStrings.cumulativeLayoutShiftMetric,
|
|
58
|
-
};
|
|
59
|
-
return str_(strMappings[timingMetric]);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* @param {LH.Budget.TimingMetric} timingMetric
|
|
64
|
-
* @param {LH.Artifacts.TimingSummary} summary
|
|
65
|
-
* @return {number|undefined}
|
|
66
|
-
*/
|
|
67
|
-
static getMeasurement(timingMetric, summary) {
|
|
68
|
-
/** @type {Record<LH.Budget.TimingMetric, number|undefined>} */
|
|
69
|
-
const measurements = {
|
|
70
|
-
'first-contentful-paint': summary.firstContentfulPaint,
|
|
71
|
-
'interactive': summary.interactive,
|
|
72
|
-
'first-meaningful-paint': summary.firstMeaningfulPaint,
|
|
73
|
-
'max-potential-fid': summary.maxPotentialFID,
|
|
74
|
-
'total-blocking-time': summary.totalBlockingTime,
|
|
75
|
-
'speed-index': summary.speedIndex,
|
|
76
|
-
'largest-contentful-paint': summary.largestContentfulPaint,
|
|
77
|
-
'cumulative-layout-shift': summary.cumulativeLayoutShift,
|
|
78
|
-
};
|
|
79
|
-
return measurements[timingMetric];
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* @param {LH.Util.Immutable<LH.Budget>} budget
|
|
84
|
-
* @param {LH.Artifacts.TimingSummary} summary
|
|
85
|
-
* @return {Array<BudgetItem>}
|
|
86
|
-
*/
|
|
87
|
-
static tableItems(budget, summary) {
|
|
88
|
-
/** @type {Array<BudgetItem>} */
|
|
89
|
-
let items = [];
|
|
90
|
-
if (!budget.timings) {
|
|
91
|
-
return items;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
items = budget.timings.map((timingBudget) => {
|
|
95
|
-
const metricName = timingBudget.metric;
|
|
96
|
-
const label = this.getRowLabel(metricName);
|
|
97
|
-
const measurement = this.getMeasurement(metricName, summary);
|
|
98
|
-
const overBudget = measurement && (measurement > timingBudget.budget)
|
|
99
|
-
? (measurement - timingBudget.budget) : undefined;
|
|
100
|
-
return {
|
|
101
|
-
metric: metricName,
|
|
102
|
-
label,
|
|
103
|
-
measurement,
|
|
104
|
-
overBudget,
|
|
105
|
-
};
|
|
106
|
-
}).sort((a, b) => {
|
|
107
|
-
return (b.overBudget || 0) - (a.overBudget || 0);
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
// CLS requires a different granularity and should be a numeric type.
|
|
111
|
-
// Defining type here overrides the column setting so that it doesn't receive ms units.
|
|
112
|
-
const clsItem = items.find(item => item.metric === 'cumulative-layout-shift');
|
|
113
|
-
if (clsItem) {
|
|
114
|
-
if (typeof clsItem.measurement === 'number') {
|
|
115
|
-
clsItem.measurement = {
|
|
116
|
-
type: 'numeric',
|
|
117
|
-
value: Number(clsItem.measurement),
|
|
118
|
-
granularity: 0.01,
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
if (typeof clsItem.overBudget === 'number') {
|
|
122
|
-
clsItem.overBudget = {
|
|
123
|
-
type: 'numeric',
|
|
124
|
-
value: Number(clsItem.overBudget),
|
|
125
|
-
granularity: 0.01,
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return items;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* @param {LH.Artifacts} artifacts
|
|
135
|
-
* @param {LH.Audit.Context} context
|
|
136
|
-
* @return {Promise<LH.Audit.Product>}
|
|
137
|
-
*/
|
|
138
|
-
static async audit(artifacts, context) {
|
|
139
|
-
const gatherContext = artifacts.GatherContext;
|
|
140
|
-
const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
|
|
141
|
-
const trace = artifacts.traces[Audit.DEFAULT_PASS];
|
|
142
|
-
const URL = artifacts.URL;
|
|
143
|
-
const mainResource = await MainResource.request({URL, devtoolsLog}, context);
|
|
144
|
-
const data = {trace, devtoolsLog, gatherContext, settings: context.settings, URL};
|
|
145
|
-
const summary = (await TimingSummary.request(data, context)).metrics;
|
|
146
|
-
const budget = Budget.getMatchingBudget(context.settings.budgets, mainResource.url);
|
|
147
|
-
|
|
148
|
-
if (!budget) {
|
|
149
|
-
return {
|
|
150
|
-
score: 0,
|
|
151
|
-
notApplicable: true,
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/** @type {LH.Audit.Details.Table['headings']} */
|
|
156
|
-
const headers = [
|
|
157
|
-
{key: 'label', valueType: 'text', label: str_(UIStrings.columnTimingMetric)},
|
|
158
|
-
/**
|
|
159
|
-
* Note: SpeedIndex, unlike other timing metrics, is not measured in milliseconds.
|
|
160
|
-
* The renderer applies the correct units to the 'measurement' and 'overBudget' columns for SpeedIndex.
|
|
161
|
-
*/
|
|
162
|
-
{key: 'measurement', valueType: 'ms', label: str_(UIStrings.columnMeasurement)},
|
|
163
|
-
{key: 'overBudget', valueType: 'ms', label: str_(i18n.UIStrings.columnOverBudget)},
|
|
164
|
-
];
|
|
165
|
-
|
|
166
|
-
return {
|
|
167
|
-
details: Audit.makeTableDetails(headers, this.tableItems(budget, summary),
|
|
168
|
-
{sortedBy: ['overBudget']}),
|
|
169
|
-
score: 1,
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
export default TimingBudget;
|
|
175
|
-
export {UIStrings};
|
package/core/config/budget.d.ts
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
export class Budget {
|
|
2
|
-
/**
|
|
3
|
-
* Asserts that obj has no own properties, throwing a nice error message if it does.
|
|
4
|
-
* `objectName` is included for nicer logging.
|
|
5
|
-
* @param {Record<string, unknown>} obj
|
|
6
|
-
* @param {string} objectName
|
|
7
|
-
*/
|
|
8
|
-
static assertNoExcessProperties(obj: Record<string, unknown>, objectName: string): void;
|
|
9
|
-
/**
|
|
10
|
-
* Asserts that `strings` has no duplicate strings in it, throwing an error if
|
|
11
|
-
* it does. `arrayName` is included for nicer logging.
|
|
12
|
-
* @param {Array<string>} strings
|
|
13
|
-
* @param {string} arrayName
|
|
14
|
-
*/
|
|
15
|
-
static assertNoDuplicateStrings(strings: Array<string>, arrayName: string): void;
|
|
16
|
-
/**
|
|
17
|
-
* @param {Record<string, unknown>} resourceBudget
|
|
18
|
-
* @return {LH.Budget.ResourceBudget}
|
|
19
|
-
*/
|
|
20
|
-
static validateResourceBudget(resourceBudget: Record<string, unknown>): LH.Budget.ResourceBudget;
|
|
21
|
-
/**
|
|
22
|
-
* @param {unknown} path
|
|
23
|
-
* @param {string} error
|
|
24
|
-
*/
|
|
25
|
-
static throwInvalidPathError(path: unknown, error: string): void;
|
|
26
|
-
/**
|
|
27
|
-
* Validates that path is either: a) undefined or ) properly formed.
|
|
28
|
-
* Verifies the quantity and location of the two robot.txt regex characters: $, *
|
|
29
|
-
* @param {unknown} path
|
|
30
|
-
* @return {undefined|string}
|
|
31
|
-
*/
|
|
32
|
-
static validatePath(path: unknown): undefined | string;
|
|
33
|
-
/**
|
|
34
|
-
* Returns the budget that applies to a given URL.
|
|
35
|
-
* If multiple budgets match based on thier 'path' property,
|
|
36
|
-
* then the last-listed of those budgets is returned.
|
|
37
|
-
* @param {LH.Util.Immutable<Array<LH.Budget>>|null} budgets
|
|
38
|
-
* @param {string|undefined} url
|
|
39
|
-
* @return {LH.Util.Immutable<LH.Budget> | undefined} budget
|
|
40
|
-
*/
|
|
41
|
-
static getMatchingBudget(budgets: LH.Util.Immutable<Array<LH.Budget>> | null, url: string | undefined): LH.Util.Immutable<LH.Budget> | undefined;
|
|
42
|
-
/**
|
|
43
|
-
* Determines whether a URL matches against a robots.txt-style "path".
|
|
44
|
-
* Pattern should use the robots.txt format. E.g. "/*-article.html" or "/". Reference:
|
|
45
|
-
* https://developers.google.com/search/reference/robots_txt#url-matching-based-on-path-values
|
|
46
|
-
* @param {string} url
|
|
47
|
-
* @param {string=} pattern
|
|
48
|
-
* @return {boolean}
|
|
49
|
-
*/
|
|
50
|
-
static urlMatchesPattern(url: string, pattern?: string | undefined): boolean;
|
|
51
|
-
/**
|
|
52
|
-
* @param {Record<string, unknown>} timingBudget
|
|
53
|
-
* @return {LH.Budget.TimingBudget}
|
|
54
|
-
*/
|
|
55
|
-
static validateTimingBudget(timingBudget: Record<string, unknown>): LH.Budget.TimingBudget;
|
|
56
|
-
/**
|
|
57
|
-
* @param {string} hostname
|
|
58
|
-
* @return {string}
|
|
59
|
-
*/
|
|
60
|
-
static validateHostname(hostname: string): string;
|
|
61
|
-
/**
|
|
62
|
-
* @param {unknown} hostnames
|
|
63
|
-
* @return {undefined|Array<string>}
|
|
64
|
-
*/
|
|
65
|
-
static validateHostnames(hostnames: unknown): undefined | Array<string>;
|
|
66
|
-
/**
|
|
67
|
-
* More info on the Budget format:
|
|
68
|
-
* https://github.com/GoogleChrome/lighthouse/issues/6053#issuecomment-428385930
|
|
69
|
-
* @param {unknown} budgetJson
|
|
70
|
-
* @return {Array<LH.Budget>}
|
|
71
|
-
*/
|
|
72
|
-
static initializeBudget(budgetJson: unknown): Array<LH.Budget>;
|
|
73
|
-
}
|
|
74
|
-
//# sourceMappingURL=budget.d.ts.map
|