lighthouse 12.8.2-dev.20251005 → 12.8.2-dev.20251007

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 (142) hide show
  1. package/cli/test/smokehouse/config/exclusions.js +0 -2
  2. package/core/audits/audit.js +0 -1
  3. package/core/audits/insights/cls-culprits-insight.js +1 -1
  4. package/core/audits/insights/dom-size-insight.js +11 -7
  5. package/core/audits/insights/insight-audit.d.ts +4 -2
  6. package/core/audits/insights/insight-audit.js +22 -3
  7. package/core/audits/predictive-perf.js +2 -2
  8. package/core/audits/seo/crawlable-anchors.js +2 -3
  9. package/core/audits/server-response-time.d.ts +0 -5
  10. package/core/audits/server-response-time.js +12 -26
  11. package/core/computed/metrics/lcp-breakdown.d.ts +10 -5
  12. package/core/computed/metrics/lcp-breakdown.js +50 -22
  13. package/core/computed/metrics/time-to-first-byte.js +33 -10
  14. package/core/computed/metrics/timing-summary.js +3 -2
  15. package/core/config/default-config.js +20 -63
  16. package/core/config/experimental-config.js +1 -26
  17. package/core/config/filters.js +6 -9
  18. package/core/config/lr-desktop-config.js +0 -1
  19. package/core/config/lr-mobile-config.js +0 -1
  20. package/core/gather/gatherers/anchor-elements.js +8 -24
  21. package/core/gather/gatherers/inspector-issues.js +1 -28
  22. package/core/gather/gatherers/trace-elements.d.ts +0 -9
  23. package/core/gather/gatherers/trace-elements.js +0 -35
  24. package/core/lib/network-request.d.ts +0 -7
  25. package/core/lib/network-request.js +0 -16
  26. package/core/lib/proto-preprocessor.js +5 -22
  27. package/dist/report/bundle.esm.js +10 -49
  28. package/dist/report/flow.js +12 -51
  29. package/dist/report/standalone.js +11 -50
  30. package/flow-report/src/i18n/i18n.d.ts +4 -6
  31. package/package.json +4 -5
  32. package/report/assets/styles.css +0 -39
  33. package/report/renderer/api.js +0 -1
  34. package/report/renderer/category-renderer.js +6 -0
  35. package/report/renderer/components.js +1 -1
  36. package/report/renderer/dom.d.ts +0 -13
  37. package/report/renderer/dom.js +0 -38
  38. package/report/renderer/performance-category-renderer.d.ts +0 -26
  39. package/report/renderer/performance-category-renderer.js +10 -142
  40. package/report/renderer/report-ui-features.d.ts +0 -1
  41. package/report/renderer/report-ui-features.js +3 -13
  42. package/report/renderer/report-utils.d.ts +2 -3
  43. package/report/renderer/report-utils.js +4 -6
  44. package/report/types/report-renderer.d.ts +0 -6
  45. package/shared/localization/locales/ar-XB.json +20 -341
  46. package/shared/localization/locales/ar.json +20 -341
  47. package/shared/localization/locales/bg.json +9 -330
  48. package/shared/localization/locales/ca.json +9 -330
  49. package/shared/localization/locales/cs.json +9 -330
  50. package/shared/localization/locales/da.json +9 -330
  51. package/shared/localization/locales/de.json +9 -330
  52. package/shared/localization/locales/el.json +9 -330
  53. package/shared/localization/locales/en-GB.json +9 -330
  54. package/shared/localization/locales/en-US.json +44 -293
  55. package/shared/localization/locales/en-XA.json +0 -330
  56. package/shared/localization/locales/en-XL.json +44 -293
  57. package/shared/localization/locales/es-419.json +9 -330
  58. package/shared/localization/locales/es.json +9 -330
  59. package/shared/localization/locales/fi.json +9 -330
  60. package/shared/localization/locales/fil.json +9 -330
  61. package/shared/localization/locales/fr.json +9 -330
  62. package/shared/localization/locales/he.json +31 -352
  63. package/shared/localization/locales/hi.json +9 -330
  64. package/shared/localization/locales/hr.json +9 -330
  65. package/shared/localization/locales/hu.json +9 -330
  66. package/shared/localization/locales/id.json +9 -330
  67. package/shared/localization/locales/it.json +9 -330
  68. package/shared/localization/locales/ja.json +9 -330
  69. package/shared/localization/locales/ko.json +10 -331
  70. package/shared/localization/locales/lt.json +9 -330
  71. package/shared/localization/locales/lv.json +10 -331
  72. package/shared/localization/locales/nl.json +9 -330
  73. package/shared/localization/locales/no.json +9 -330
  74. package/shared/localization/locales/pl.json +9 -330
  75. package/shared/localization/locales/pt-PT.json +9 -330
  76. package/shared/localization/locales/pt.json +9 -330
  77. package/shared/localization/locales/ro.json +10 -331
  78. package/shared/localization/locales/ru.json +9 -330
  79. package/shared/localization/locales/sk.json +9 -330
  80. package/shared/localization/locales/sl.json +9 -330
  81. package/shared/localization/locales/sr-Latn.json +9 -330
  82. package/shared/localization/locales/sr.json +9 -330
  83. package/shared/localization/locales/sv.json +9 -330
  84. package/shared/localization/locales/ta.json +9 -330
  85. package/shared/localization/locales/te.json +10 -331
  86. package/shared/localization/locales/th.json +9 -330
  87. package/shared/localization/locales/tr.json +9 -330
  88. package/shared/localization/locales/uk.json +9 -330
  89. package/shared/localization/locales/vi.json +9 -330
  90. package/shared/localization/locales/zh-HK.json +9 -330
  91. package/shared/localization/locales/zh-TW.json +10 -331
  92. package/shared/localization/locales/zh.json +9 -330
  93. package/types/artifacts.d.ts +5 -6
  94. package/types/audit.d.ts +1 -1
  95. package/types/lhr/settings.d.ts +1 -1
  96. package/core/audits/byte-efficiency/duplicated-javascript.d.ts +0 -45
  97. package/core/audits/byte-efficiency/duplicated-javascript.js +0 -223
  98. package/core/audits/byte-efficiency/efficient-animated-content.d.ts +0 -22
  99. package/core/audits/byte-efficiency/efficient-animated-content.js +0 -93
  100. package/core/audits/byte-efficiency/legacy-javascript.d.ts +0 -28
  101. package/core/audits/byte-efficiency/legacy-javascript.js +0 -144
  102. package/core/audits/byte-efficiency/modern-image-formats.d.ts +0 -38
  103. package/core/audits/byte-efficiency/modern-image-formats.js +0 -187
  104. package/core/audits/byte-efficiency/render-blocking-resources.d.ts +0 -53
  105. package/core/audits/byte-efficiency/render-blocking-resources.js +0 -312
  106. package/core/audits/byte-efficiency/uses-long-cache-ttl.d.ts +0 -59
  107. package/core/audits/byte-efficiency/uses-long-cache-ttl.js +0 -293
  108. package/core/audits/byte-efficiency/uses-optimized-images.d.ts +0 -33
  109. package/core/audits/byte-efficiency/uses-optimized-images.js +0 -146
  110. package/core/audits/byte-efficiency/uses-responsive-images-snapshot.d.ts +0 -16
  111. package/core/audits/byte-efficiency/uses-responsive-images-snapshot.js +0 -106
  112. package/core/audits/byte-efficiency/uses-responsive-images.d.ts +0 -44
  113. package/core/audits/byte-efficiency/uses-responsive-images.js +0 -202
  114. package/core/audits/byte-efficiency/uses-text-compression.d.ts +0 -14
  115. package/core/audits/byte-efficiency/uses-text-compression.js +0 -108
  116. package/core/audits/critical-request-chains.d.ts +0 -44
  117. package/core/audits/critical-request-chains.js +0 -221
  118. package/core/audits/dobetterweb/dom-size.d.ts +0 -32
  119. package/core/audits/dobetterweb/dom-size.js +0 -182
  120. package/core/audits/dobetterweb/uses-http2.d.ts +0 -72
  121. package/core/audits/dobetterweb/uses-http2.js +0 -276
  122. package/core/audits/font-display.d.ts +0 -32
  123. package/core/audits/font-display.js +0 -195
  124. package/core/audits/largest-contentful-paint-element.d.ts +0 -34
  125. package/core/audits/largest-contentful-paint-element.js +0 -181
  126. package/core/audits/lcp-lazy-loaded.d.ts +0 -22
  127. package/core/audits/lcp-lazy-loaded.js +0 -115
  128. package/core/audits/prioritize-lcp-image.d.ts +0 -74
  129. package/core/audits/prioritize-lcp-image.js +0 -297
  130. package/core/audits/third-party-summary.d.ts +0 -78
  131. package/core/audits/third-party-summary.js +0 -236
  132. package/core/audits/uses-rel-preconnect.d.ts +0 -37
  133. package/core/audits/uses-rel-preconnect.js +0 -286
  134. package/core/audits/viewport.d.ts +0 -17
  135. package/core/audits/viewport.js +0 -87
  136. package/core/audits/work-during-interaction.d.ts +0 -81
  137. package/core/audits/work-during-interaction.js +0 -287
  138. package/core/computed/critical-request-chains.d.ts +0 -42
  139. package/core/computed/critical-request-chains.js +0 -143
  140. package/core/computed/viewport-meta.d.ts +0 -37
  141. package/core/computed/viewport-meta.js +0 -71
  142. package/types/internal/metaviewport-parser.d.ts +0 -13
@@ -1,182 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright 2017 Google LLC
4
- * SPDX-License-Identifier: Apache-2.0
5
- */
6
-
7
- /**
8
- * @fileoverview Audits a page to see how the size of DOM it creates. Stats like
9
- * tree depth, # children, and total elements are returned. The score is calculated
10
- * based solely on the total number of elements found on the page.
11
- */
12
-
13
-
14
- import {Audit} from '../audit.js';
15
- import * as i18n from '../../lib/i18n/i18n.js';
16
- import {TBTImpactTasks} from '../../computed/tbt-impact-tasks.js';
17
-
18
- const UIStrings = {
19
- /** Title of a diagnostic audit that provides detail on the size of the web page's DOM. The size of a DOM is characterized by the total number of DOM elements and greatest DOM depth. This descriptive title is shown to users when the amount is acceptable and no user action is required. */
20
- title: 'Avoids an excessive DOM size',
21
- /** Title of a diagnostic audit that provides detail on the size of the web page's DOM. The size of a DOM is characterized by the total number of DOM elements and greatest DOM depth. This imperative title is shown to users when there is a significant amount of execution time that could be reduced. */
22
- failureTitle: 'Avoid an excessive DOM size',
23
- /** Description of a Lighthouse audit that tells the user *why* they should reduce the size of the web page's DOM. The size of a DOM is characterized by the total number of DOM elements and greatest DOM depth. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
24
- description: 'A large DOM will increase memory usage, cause longer ' +
25
- '[style calculations](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations), ' +
26
- 'and produce costly [layout reflows](https://developers.google.com/speed/articles/reflow). [Learn how to avoid an excessive DOM size](https://developer.chrome.com/docs/lighthouse/performance/dom-size/).',
27
- /** Table column header for the type of statistic. These statistics describe how big the DOM is (count of DOM elements, children, depth). */
28
- columnStatistic: 'Statistic',
29
- /** Table column header for the observed value of the DOM statistic. */
30
- columnValue: 'Value',
31
- /** [ICU Syntax] Label for an audit identifying the number of DOM elements found in the page. */
32
- displayValue: `{itemCount, plural,
33
- =1 {1 element}
34
- other {# elements}
35
- }`,
36
- /** Label for the total number of DOM elements found in the page. */
37
- statisticDOMElements: 'Total DOM Elements',
38
- /** Label for the numeric value of the maximum depth in the page's DOM tree. */
39
- statisticDOMDepth: 'Maximum DOM Depth',
40
- /** Label for the numeric value of the maximum number of children any DOM element in the page has. The element described will have the most children in the page. */
41
- statisticDOMWidth: 'Maximum Child Elements',
42
- };
43
-
44
- const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
45
-
46
- class DOMSize extends Audit {
47
- /**
48
- * @return {LH.Audit.Meta}
49
- */
50
- static get meta() {
51
- return {
52
- id: 'dom-size',
53
- title: str_(UIStrings.title),
54
- failureTitle: str_(UIStrings.failureTitle),
55
- description: str_(UIStrings.description),
56
- scoreDisplayMode: Audit.SCORING_MODES.METRIC_SAVINGS,
57
- guidanceLevel: 1,
58
- requiredArtifacts: ['DOMStats', 'URL', 'GatherContext'],
59
- __internalOptionalArtifacts: ['Trace', 'DevtoolsLog', 'SourceMaps'],
60
- };
61
- }
62
-
63
- /**
64
- * @return {LH.Audit.ScoreOptions}
65
- */
66
- static get defaultOptions() {
67
- return {
68
- // https://bigquery.cloud.google.com/table/httparchive:lighthouse.2018_04_01_mobile?pli=1
69
- // see https://www.desmos.com/calculator/tsunbwqt3f
70
- p10: 818,
71
- median: 1400,
72
- };
73
- }
74
-
75
- /**
76
- * @param {LH.Artifacts} artifacts
77
- * @param {LH.Audit.Context} context
78
- * @return {Promise<number|undefined>}
79
- */
80
- static async computeTbtImpact(artifacts, context) {
81
- let tbtImpact = 0;
82
-
83
- // We still want to surface this audit in snapshot mode, but since we don't compute TBT
84
- // the impact should always be undefined.
85
- const {GatherContext, DevtoolsLog, Trace} = artifacts;
86
- if (GatherContext.gatherMode !== 'navigation') {
87
- return undefined;
88
- }
89
-
90
- // Since the artifacts are optional, it's still possible for them to be missing in navigation mode.
91
- // Navigation mode does compute TBT so we should surface a numerical savings of 0.
92
- if (!DevtoolsLog || !Trace) {
93
- return 0;
94
- }
95
-
96
- const metricComputationData = Audit.makeMetricComputationDataInput(artifacts, context);
97
-
98
- try {
99
- // The TBT impact of style/layout tasks is correlated to the DOM size.
100
- // Even in situations where the page forces a style recalc, the DOM size is partially to blame
101
- // for any time spent blocking the main thread.
102
- //
103
- // `tbtImpact` should be exactly 0 for small DOMs since `selfTbtImpact` accounts for the blocking
104
- // time and not the main thread time.
105
- const tbtImpactTasks = await TBTImpactTasks.request(metricComputationData, context);
106
- for (const task of tbtImpactTasks) {
107
- if (task.group.id !== 'styleLayout') continue;
108
- tbtImpact += task.selfTbtImpact;
109
- }
110
- } catch {}
111
-
112
- return Math.round(tbtImpact);
113
- }
114
-
115
-
116
- /**
117
- * @param {LH.Artifacts} artifacts
118
- * @param {LH.Audit.Context} context
119
- * @return {Promise<LH.Audit.Product>}
120
- */
121
- static async audit(artifacts, context) {
122
- const stats = artifacts.DOMStats;
123
-
124
- const score = Audit.computeLogNormalScore(
125
- {p10: context.options.p10, median: context.options.median},
126
- stats.totalBodyElements
127
- );
128
-
129
- /** @type {LH.Audit.Details.Table['headings']} */
130
- const headings = [
131
- {key: 'statistic', valueType: 'text', label: str_(UIStrings.columnStatistic)},
132
- {key: 'node', valueType: 'node', label: str_(i18n.UIStrings.columnElement)},
133
- {key: 'value', valueType: 'numeric', label: str_(UIStrings.columnValue)},
134
- ];
135
-
136
- /** @type {LH.Audit.Details.Table['items']} */
137
- const items = [
138
- {
139
- statistic: str_(UIStrings.statisticDOMElements),
140
- value: {
141
- type: 'numeric',
142
- granularity: 1,
143
- value: stats.totalBodyElements,
144
- },
145
- },
146
- {
147
- node: Audit.makeNodeItem(stats.depth),
148
- statistic: str_(UIStrings.statisticDOMDepth),
149
- value: {
150
- type: 'numeric',
151
- granularity: 1,
152
- value: stats.depth.max,
153
- },
154
- },
155
- {
156
- node: Audit.makeNodeItem(stats.width),
157
- statistic: str_(UIStrings.statisticDOMWidth),
158
- value: {
159
- type: 'numeric',
160
- granularity: 1,
161
- value: stats.width.max,
162
- },
163
- },
164
- ];
165
-
166
- const tbtImpact = await this.computeTbtImpact(artifacts, context);
167
-
168
- return {
169
- score,
170
- numericValue: stats.totalBodyElements,
171
- numericUnit: 'element',
172
- displayValue: str_(UIStrings.displayValue, {itemCount: stats.totalBodyElements}),
173
- details: Audit.makeTableDetails(headings, items),
174
- metricSavings: {
175
- TBT: tbtImpact,
176
- },
177
- };
178
- }
179
- }
180
-
181
- export default DOMSize;
182
- export {UIStrings};
@@ -1,72 +0,0 @@
1
- export default UsesHTTP2Audit;
2
- declare class UsesHTTP2Audit extends Audit {
3
- /**
4
- * Computes the estimated effect of all results being converted to http/2 on the provided graph.
5
- *
6
- * @param {Array<{url: string}>} results
7
- * @param {LH.Gatherer.Simulation.GraphNode} graph
8
- * @param {LH.Gatherer.Simulation.Simulator} simulator
9
- * @param {{label?: string}=} options
10
- * @return {{savings: number, simulationBefore: LH.Gatherer.Simulation.Result, simulationAfter: LH.Gatherer.Simulation.Result}}
11
- */
12
- static computeWasteWithGraph(results: Array<{
13
- url: string;
14
- }>, graph: LH.Gatherer.Simulation.GraphNode, simulator: LH.Gatherer.Simulation.Simulator, options?: {
15
- label?: string;
16
- } | undefined): {
17
- savings: number;
18
- simulationBefore: LH.Gatherer.Simulation.Result;
19
- simulationAfter: LH.Gatherer.Simulation.Result;
20
- };
21
- /**
22
- * Determines whether a network request is a "static resource" that would benefit from H2 multiplexing.
23
- * XHRs, tracking pixels, etc generally don't benefit as much because they aren't requested en-masse
24
- * for the same origin at the exact same time.
25
- *
26
- * @param {LH.Artifacts.NetworkRequest} networkRequest
27
- * @param {LH.Artifacts.EntityClassification} classifiedEntities
28
- * @return {boolean}
29
- */
30
- static isMultiplexableStaticAsset(networkRequest: LH.Artifacts.NetworkRequest, classifiedEntities: LH.Artifacts.EntityClassification): boolean;
31
- /**
32
- * Determine the set of resources that aren't HTTP/2 but should be.
33
- * We're a little conservative about what we surface for a few reasons:
34
- *
35
- * - The simulator approximation of HTTP/2 is a little more generous than reality.
36
- * - There's a bit of debate surrounding HTTP/2 due to its worse performance in environments with high packet loss.**
37
- * - It's something that you'd have absolutely zero control over with a third-party (can't defer to fix it for example).
38
- *
39
- * Therefore, we only surface requests that were...
40
- *
41
- * - Served over HTTP/1.1 or earlier
42
- * - Served over an origin that serves at least 6 static asset requests
43
- * (if there aren't more requests than browser's max/host, multiplexing isn't as big a deal)
44
- * - Not served on localhost (h2 is a pain to deal with locally & and CI)
45
- *
46
- * ** = https://news.ycombinator.com/item?id=19086639
47
- * https://www.twilio.com/blog/2017/10/http2-issues.html
48
- * https://www.cachefly.com/http-2-is-not-a-magic-bullet/
49
- *
50
- * @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
51
- * @param {LH.Artifacts.EntityClassification} classifiedEntities
52
- * @return {Array<{url: string, protocol: string}>}
53
- */
54
- static determineNonHttp2Resources(networkRecords: Array<LH.Artifacts.NetworkRequest>, classifiedEntities: LH.Artifacts.EntityClassification): Array<{
55
- url: string;
56
- protocol: string;
57
- }>;
58
- /**
59
- * @param {LH.Artifacts} artifacts
60
- * @param {LH.Audit.Context} context
61
- * @return {Promise<LH.Audit.Product>}
62
- */
63
- static audit(artifacts: LH.Artifacts, context: LH.Audit.Context): Promise<LH.Audit.Product>;
64
- }
65
- export namespace UIStrings {
66
- let title: string;
67
- let description: string;
68
- let displayValue: string;
69
- let columnProtocol: string;
70
- }
71
- import { Audit } from '../audit.js';
72
- //# sourceMappingURL=uses-http2.d.ts.map
@@ -1,276 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright 2016 Google LLC
4
- * SPDX-License-Identifier: Apache-2.0
5
- */
6
-
7
- /**
8
- * @fileoverview Audit a page to ensure that resource loaded over its own
9
- * origin are over the http/2 protocol.
10
- */
11
-
12
- import {Audit} from '../audit.js';
13
- import {EntityClassification} from '../../computed/entity-classification.js';
14
- import UrlUtils from '../../lib/url-utils.js';
15
- import {NetworkRequest} from '../../lib/network-request.js';
16
- import {NetworkRecords} from '../../computed/network-records.js';
17
- import {LoadSimulator} from '../../computed/load-simulator.js';
18
- import {LanternLargestContentfulPaint} from '../../computed/metrics/lantern-largest-contentful-paint.js';
19
- import {LanternFirstContentfulPaint} from '../../computed/metrics/lantern-first-contentful-paint.js';
20
- import * as i18n from '../../lib/i18n/i18n.js';
21
-
22
- const UIStrings = {
23
- /** Imperative title of a Lighthouse audit that tells the user to enable HTTP/2. This is displayed in a list of audit titles that Lighthouse generates. */
24
- title: 'Use HTTP/2',
25
- /** Description of a Lighthouse audit that tells the user why they should use HTTP/2. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
26
- description: 'HTTP/2 offers many benefits over HTTP/1.1, including binary headers and ' +
27
- 'multiplexing. [Learn more about HTTP/2](https://developer.chrome.com/docs/lighthouse/best-practices/uses-http2/).',
28
- /** [ICU Syntax] Label identifying the number of network requests that were not served with HTTP/2. */
29
- displayValue: `{itemCount, plural,
30
- =1 {1 request not served via HTTP/2}
31
- other {# requests not served via HTTP/2}
32
- }`,
33
- /** Label for a column in a data table; entries in the column will be the HTTP Protocol used to make a network request. */
34
- columnProtocol: 'Protocol',
35
- };
36
-
37
- const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
38
-
39
- /** @type {Set<LH.Artifacts.NetworkRequest['resourceType']>} */
40
- const STATIC_RESOURCE_TYPES = new Set([
41
- NetworkRequest.TYPES.Document,
42
- NetworkRequest.TYPES.Font,
43
- NetworkRequest.TYPES.Image,
44
- NetworkRequest.TYPES.Stylesheet,
45
- NetworkRequest.TYPES.Script,
46
- NetworkRequest.TYPES.Media,
47
- ]);
48
-
49
- class UsesHTTP2Audit extends Audit {
50
- /**
51
- * @return {LH.Audit.Meta}
52
- */
53
- static get meta() {
54
- return {
55
- id: 'uses-http2',
56
- title: str_(UIStrings.title),
57
- description: str_(UIStrings.description),
58
- scoreDisplayMode: Audit.SCORING_MODES.METRIC_SAVINGS,
59
- guidanceLevel: 3,
60
- supportedModes: ['timespan', 'navigation'],
61
- requiredArtifacts: ['URL', 'DevtoolsLog', 'Trace', 'GatherContext', 'SourceMaps'],
62
- };
63
- }
64
-
65
- /**
66
- * Computes the estimated effect of all results being converted to http/2 on the provided graph.
67
- *
68
- * @param {Array<{url: string}>} results
69
- * @param {LH.Gatherer.Simulation.GraphNode} graph
70
- * @param {LH.Gatherer.Simulation.Simulator} simulator
71
- * @param {{label?: string}=} options
72
- * @return {{savings: number, simulationBefore: LH.Gatherer.Simulation.Result, simulationAfter: LH.Gatherer.Simulation.Result}}
73
- */
74
- static computeWasteWithGraph(results, graph, simulator, options) {
75
- options = Object.assign({label: ''}, options);
76
- const beforeLabel = `${this.meta.id}-${options.label}-before`;
77
- const afterLabel = `${this.meta.id}-${options.label}-after`;
78
-
79
- const urlsToChange = new Set(results.map(result => result.url));
80
- const simulationBefore = simulator.simulate(graph, {label: beforeLabel});
81
-
82
- // Update all the protocols to reflect implementing our recommendations
83
- /** @type {Map<string, string>} */
84
- const originalProtocols = new Map();
85
- graph.traverse(node => {
86
- if (node.type !== 'network') return;
87
- if (!urlsToChange.has(node.request.url)) return;
88
-
89
- originalProtocols.set(node.request.requestId, node.request.protocol);
90
- node.request.protocol = 'h2';
91
- });
92
-
93
- const simulationAfter = simulator.simulate(graph, {label: afterLabel});
94
-
95
- // Restore the original protocol after we've done our simulation
96
- graph.traverse(node => {
97
- if (node.type !== 'network') return;
98
- const originalProtocol = originalProtocols.get(node.request.requestId);
99
- if (originalProtocol === undefined) return;
100
- node.request.protocol = originalProtocol;
101
- });
102
-
103
- const savings = simulationBefore.timeInMs - simulationAfter.timeInMs;
104
-
105
- return {
106
- // Round waste to nearest 10ms
107
- savings: Math.round(Math.max(savings, 0) / 10) * 10,
108
- simulationBefore,
109
- simulationAfter,
110
- };
111
- }
112
-
113
- /**
114
- * Determines whether a network request is a "static resource" that would benefit from H2 multiplexing.
115
- * XHRs, tracking pixels, etc generally don't benefit as much because they aren't requested en-masse
116
- * for the same origin at the exact same time.
117
- *
118
- * @param {LH.Artifacts.NetworkRequest} networkRequest
119
- * @param {LH.Artifacts.EntityClassification} classifiedEntities
120
- * @return {boolean}
121
- */
122
- static isMultiplexableStaticAsset(networkRequest, classifiedEntities) {
123
- if (!STATIC_RESOURCE_TYPES.has(networkRequest.resourceType)) return false;
124
-
125
- // Resources from third-parties that are less than 100 bytes are usually tracking pixels, not actual resources.
126
- // They can masquerade as static types though (gifs, documents, etc)
127
- if (networkRequest.resourceSize < 100) {
128
- const entity = classifiedEntities.entityByUrl.get(networkRequest.url);
129
- if (entity) {
130
- // Third-party assets are multiplexable in their first-party context.
131
- if (classifiedEntities.firstParty?.name === entity.name) return true;
132
- // Skip recognizable third-parties' requests.
133
- if (!entity.isUnrecognized) return false;
134
- }
135
- }
136
-
137
- return true;
138
- }
139
-
140
- /**
141
- * Determine the set of resources that aren't HTTP/2 but should be.
142
- * We're a little conservative about what we surface for a few reasons:
143
- *
144
- * - The simulator approximation of HTTP/2 is a little more generous than reality.
145
- * - There's a bit of debate surrounding HTTP/2 due to its worse performance in environments with high packet loss.**
146
- * - It's something that you'd have absolutely zero control over with a third-party (can't defer to fix it for example).
147
- *
148
- * Therefore, we only surface requests that were...
149
- *
150
- * - Served over HTTP/1.1 or earlier
151
- * - Served over an origin that serves at least 6 static asset requests
152
- * (if there aren't more requests than browser's max/host, multiplexing isn't as big a deal)
153
- * - Not served on localhost (h2 is a pain to deal with locally & and CI)
154
- *
155
- * ** = https://news.ycombinator.com/item?id=19086639
156
- * https://www.twilio.com/blog/2017/10/http2-issues.html
157
- * https://www.cachefly.com/http-2-is-not-a-magic-bullet/
158
- *
159
- * @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
160
- * @param {LH.Artifacts.EntityClassification} classifiedEntities
161
- * @return {Array<{url: string, protocol: string}>}
162
- */
163
- static determineNonHttp2Resources(networkRecords, classifiedEntities) {
164
- /** @type {Array<{url: string, protocol: string}>} */
165
- const nonHttp2Resources = [];
166
-
167
- /** @type {Set<string>} */
168
- const seenURLs = new Set();
169
- /** @type {Map<string, Array<LH.Artifacts.NetworkRequest>>} */
170
- const groupedByOrigin = new Map();
171
- for (const record of networkRecords) {
172
- if (!UsesHTTP2Audit.isMultiplexableStaticAsset(record, classifiedEntities)) continue;
173
- if (UrlUtils.isLikeLocalhost(record.parsedURL.host)) continue;
174
- const existing = groupedByOrigin.get(record.parsedURL.securityOrigin) || [];
175
- existing.push(record);
176
- groupedByOrigin.set(record.parsedURL.securityOrigin, existing);
177
- }
178
-
179
- for (const record of networkRecords) {
180
- // Skip duplicates.
181
- if (seenURLs.has(record.url)) continue;
182
- // Check if record is not served through the service worker, servicer worker uses http/1.1 as a protocol.
183
- // These can generate false positives (bug: https://github.com/GoogleChrome/lighthouse/issues/7158).
184
- if (record.fetchedViaServiceWorker) continue;
185
- // Test the protocol to see if it was http/1.1.
186
- const isOldHttp = /HTTP\/[01][.\d]?/i.test(record.protocol);
187
- if (!isOldHttp) continue;
188
- // Check if the origin has enough requests to bother flagging.
189
- const group = groupedByOrigin.get(record.parsedURL.securityOrigin) || [];
190
- if (group.length < 6) continue;
191
-
192
- seenURLs.add(record.url);
193
- nonHttp2Resources.push({protocol: record.protocol, url: record.url});
194
- }
195
-
196
- return nonHttp2Resources;
197
- }
198
-
199
- /**
200
- * @param {LH.Artifacts} artifacts
201
- * @param {LH.Audit.Context} context
202
- * @return {Promise<LH.Audit.Product>}
203
- */
204
- static async audit(artifacts, context) {
205
- const devtoolsLog = artifacts.DevtoolsLog;
206
- const URL = artifacts.URL;
207
- const networkRecords = await NetworkRecords.request(devtoolsLog, context);
208
- const classifiedEntities = await EntityClassification.request({URL, devtoolsLog}, context);
209
- const resources = UsesHTTP2Audit.determineNonHttp2Resources(networkRecords, classifiedEntities);
210
-
211
- let displayValue;
212
- if (resources.length > 0) {
213
- displayValue = str_(UIStrings.displayValue, {itemCount: resources.length});
214
- }
215
-
216
- // TODO: Compute actual savings for timespan mode.
217
- if (artifacts.GatherContext.gatherMode === 'timespan') {
218
- /** @type {LH.Audit.Details.Table['headings']} */
219
- const headings = [
220
- {key: 'url', valueType: 'url', label: str_(i18n.UIStrings.columnURL)},
221
- {key: 'protocol', valueType: 'text', label: str_(UIStrings.columnProtocol)},
222
- ];
223
-
224
- const details = Audit.makeTableDetails(headings, resources);
225
-
226
- return {
227
- displayValue,
228
- score: resources.length ? 0 : 1,
229
- details,
230
- };
231
- }
232
-
233
- const settings = context?.settings || {};
234
- const simulatorOptions = {
235
- devtoolsLog,
236
- settings,
237
- };
238
- const simulator = await LoadSimulator.request(simulatorOptions, context);
239
- const metricComputationInput = Audit.makeMetricComputationDataInput(artifacts, context);
240
-
241
- const {
242
- pessimisticGraph: fcpGraph,
243
- } = await LanternFirstContentfulPaint.request(metricComputationInput, context);
244
- const {
245
- pessimisticGraph: lcpGraph,
246
- } = await LanternLargestContentfulPaint.request(metricComputationInput, context);
247
-
248
- const wasteFcp =
249
- UsesHTTP2Audit.computeWasteWithGraph(resources,
250
- fcpGraph, simulator, {label: 'fcp'});
251
- const wasteLcp =
252
- UsesHTTP2Audit.computeWasteWithGraph(resources,
253
- lcpGraph, simulator, {label: 'lcp'});
254
-
255
- /** @type {LH.Audit.Details.Opportunity['headings']} */
256
- const headings = [
257
- {key: 'url', valueType: 'url', label: str_(i18n.UIStrings.columnURL)},
258
- {key: 'protocol', valueType: 'text', label: str_(UIStrings.columnProtocol)},
259
- ];
260
-
261
- const details = Audit.makeOpportunityDetails(headings, resources,
262
- {overallSavingsMs: wasteLcp.savings});
263
-
264
- return {
265
- displayValue,
266
- numericValue: wasteLcp.savings,
267
- numericUnit: 'millisecond',
268
- score: resources.length ? 0 : 1,
269
- details,
270
- metricSavings: {LCP: wasteLcp.savings, FCP: wasteFcp.savings},
271
- };
272
- }
273
- }
274
-
275
- export default UsesHTTP2Audit;
276
- export {UIStrings};
@@ -1,32 +0,0 @@
1
- export default FontDisplay;
2
- declare class FontDisplay extends Audit {
3
- /**
4
- * @param {LH.Artifacts} artifacts
5
- * @param {RegExp} passingFontDisplayRegex
6
- * @return {{passingURLs: Set<string>, failingURLs: Set<string>}}
7
- */
8
- static findFontDisplayDeclarations(artifacts: LH.Artifacts, passingFontDisplayRegex: RegExp): {
9
- passingURLs: Set<string>;
10
- failingURLs: Set<string>;
11
- };
12
- /**
13
- * Some pages load many fonts we can't check, so dedupe on origin.
14
- * @param {Array<string>} warningUrls
15
- * @return {Array<LH.IcuMessage>}
16
- */
17
- static getWarningsForFontUrls(warningUrls: Array<string>): Array<LH.IcuMessage>;
18
- /**
19
- * @param {LH.Artifacts} artifacts
20
- * @param {LH.Audit.Context} context
21
- * @return {Promise<LH.Audit.Product>}
22
- */
23
- static audit(artifacts: LH.Artifacts, context: LH.Audit.Context): Promise<LH.Audit.Product>;
24
- }
25
- export namespace UIStrings {
26
- let title: string;
27
- let failureTitle: string;
28
- let description: string;
29
- let undeclaredFontOriginWarning: string;
30
- }
31
- import { Audit } from './audit.js';
32
- //# sourceMappingURL=font-display.d.ts.map