lighthouse 11.7.0-dev.20240415 → 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.
Files changed (109) hide show
  1. package/cli/bin.js +0 -7
  2. package/cli/cli-flags.d.ts +1 -5
  3. package/cli/cli-flags.js +1 -5
  4. package/cli/test/smokehouse/config/exclusions.js +2 -0
  5. package/cli/test/smokehouse/core-tests.js +2 -2
  6. package/core/audits/byte-efficiency/render-blocking-resources.js +3 -1
  7. package/core/audits/byte-efficiency/unminified-css.js +2 -2
  8. package/core/audits/byte-efficiency/unused-css-rules.js +3 -1
  9. package/core/audits/font-display.js +2 -2
  10. package/core/audits/resource-summary.d.ts +2 -0
  11. package/core/audits/resource-summary.js +5 -4
  12. package/core/audits/seo/link-text.js +12 -0
  13. package/core/computed/page-dependency-graph.js +1 -6
  14. package/core/computed/resource-summary.d.ts +10 -12
  15. package/core/computed/resource-summary.js +12 -19
  16. package/core/computed/unused-css.d.ts +3 -1
  17. package/core/computed/unused-css.js +6 -5
  18. package/core/config/config-helpers.js +0 -4
  19. package/core/config/constants.js +0 -1
  20. package/core/config/default-config.js +1 -14
  21. package/core/gather/driver/navigation.js +4 -1
  22. package/core/gather/driver/prepare.js +1 -1
  23. package/core/gather/driver/target-manager.js +3 -2
  24. package/core/gather/driver.d.ts +12 -0
  25. package/core/gather/driver.js +26 -0
  26. package/core/gather/gatherers/css-usage.d.ts +0 -21
  27. package/core/gather/gatherers/css-usage.js +9 -119
  28. package/core/gather/gatherers/stylesheets.d.ts +26 -0
  29. package/core/gather/gatherers/stylesheets.js +138 -0
  30. package/core/gather/navigation-runner.js +3 -1
  31. package/core/gather/session.js +2 -1
  32. package/core/lib/emulation.js +2 -2
  33. package/core/lib/i18n/i18n.d.ts +0 -1
  34. package/core/lib/i18n/i18n.js +0 -2
  35. package/core/lib/lh-error.d.ts +9 -0
  36. package/core/lib/lh-error.js +10 -0
  37. package/core/lib/navigation-error.js +3 -0
  38. package/core/runner.js +0 -1
  39. package/dist/report/bundle.esm.js +2 -19
  40. package/dist/report/flow.js +5 -22
  41. package/dist/report/standalone.js +3 -20
  42. package/package.json +3 -3
  43. package/readme.md +2 -2
  44. package/report/assets/styles.css +0 -17
  45. package/report/renderer/components.js +1 -1
  46. package/report/renderer/dom.d.ts +1 -1
  47. package/report/renderer/dom.js +1 -1
  48. package/report/renderer/performance-category-renderer.js +0 -21
  49. package/shared/localization/locales/ar-XB.json +61 -91
  50. package/shared/localization/locales/ar.json +61 -91
  51. package/shared/localization/locales/bg.json +61 -91
  52. package/shared/localization/locales/ca.json +61 -91
  53. package/shared/localization/locales/cs.json +61 -91
  54. package/shared/localization/locales/da.json +61 -91
  55. package/shared/localization/locales/de.json +61 -91
  56. package/shared/localization/locales/el.json +61 -91
  57. package/shared/localization/locales/en-GB.json +61 -91
  58. package/shared/localization/locales/en-US.json +3 -30
  59. package/shared/localization/locales/en-XA.json +61 -91
  60. package/shared/localization/locales/en-XL.json +3 -30
  61. package/shared/localization/locales/es-419.json +61 -91
  62. package/shared/localization/locales/es.json +61 -91
  63. package/shared/localization/locales/fi.json +61 -91
  64. package/shared/localization/locales/fil.json +60 -90
  65. package/shared/localization/locales/fr.json +61 -91
  66. package/shared/localization/locales/he.json +61 -91
  67. package/shared/localization/locales/hi.json +61 -91
  68. package/shared/localization/locales/hr.json +62 -92
  69. package/shared/localization/locales/hu.json +61 -91
  70. package/shared/localization/locales/id.json +61 -91
  71. package/shared/localization/locales/it.json +61 -91
  72. package/shared/localization/locales/ja.json +61 -91
  73. package/shared/localization/locales/ko.json +61 -91
  74. package/shared/localization/locales/lt.json +61 -91
  75. package/shared/localization/locales/lv.json +61 -91
  76. package/shared/localization/locales/nl.json +61 -91
  77. package/shared/localization/locales/no.json +61 -91
  78. package/shared/localization/locales/pl.json +60 -90
  79. package/shared/localization/locales/pt-PT.json +61 -91
  80. package/shared/localization/locales/pt.json +63 -93
  81. package/shared/localization/locales/ro.json +61 -91
  82. package/shared/localization/locales/ru.json +61 -91
  83. package/shared/localization/locales/sk.json +61 -91
  84. package/shared/localization/locales/sl.json +61 -91
  85. package/shared/localization/locales/sr-Latn.json +61 -91
  86. package/shared/localization/locales/sr.json +61 -91
  87. package/shared/localization/locales/sv.json +61 -91
  88. package/shared/localization/locales/ta.json +60 -90
  89. package/shared/localization/locales/te.json +61 -91
  90. package/shared/localization/locales/th.json +61 -91
  91. package/shared/localization/locales/tr.json +61 -91
  92. package/shared/localization/locales/uk.json +61 -91
  93. package/shared/localization/locales/vi.json +60 -90
  94. package/shared/localization/locales/zh-HK.json +61 -91
  95. package/shared/localization/locales/zh-TW.json +60 -90
  96. package/shared/localization/locales/zh.json +61 -91
  97. package/tsconfig.json +0 -1
  98. package/types/artifacts.d.ts +3 -1
  99. package/types/externs.d.ts +0 -2
  100. package/types/gatherer.d.ts +2 -0
  101. package/types/lh.d.ts +0 -2
  102. package/types/lhr/settings.d.ts +0 -4
  103. package/core/audits/performance-budget.d.ts +0 -39
  104. package/core/audits/performance-budget.js +0 -154
  105. package/core/audits/timing-budget.d.ts +0 -43
  106. package/core/audits/timing-budget.js +0 -175
  107. package/core/config/budget.d.ts +0 -74
  108. package/core/config/budget.js +0 -340
  109. 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",
@@ -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: {rules: Crdp.CSS.RuleUsage[], stylesheets: Artifacts.CSSStyleSheetInfo[]};
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). */
@@ -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[];
@@ -49,6 +49,8 @@ declare module Gatherer {
49
49
  off(event: 'protocolevent', callback: (payload: Protocol.RawEventMessage) => void): void
50
50
  };
51
51
  networkMonitor: NetworkMonitor;
52
+ listenForCrashes: (() => void);
53
+ fatalRejection: {promise: Promise<never>, rej: (reason: Error) => void}
52
54
  }
53
55
 
54
56
  interface Context<TDependencies extends DependencyKey = DefaultDependenciesKey> {
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;
@@ -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};
@@ -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