lighthouse 12.8.2-dev.20251004 → 12.8.2-dev.20251006

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 (126) 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 +6 -6
  5. package/core/audits/redirects.js +1 -0
  6. package/core/audits/server-response-time.d.ts +0 -5
  7. package/core/audits/server-response-time.js +12 -26
  8. package/core/computed/metrics/lcp-breakdown.js +1 -0
  9. package/core/config/default-config.js +20 -63
  10. package/core/config/experimental-config.js +1 -26
  11. package/core/config/filters.js +6 -9
  12. package/core/config/lr-desktop-config.js +0 -1
  13. package/core/config/lr-mobile-config.js +0 -1
  14. package/core/gather/gatherers/trace-elements.js +1 -0
  15. package/core/lib/proto-preprocessor.js +5 -22
  16. package/dist/report/bundle.esm.js +10 -49
  17. package/dist/report/flow.js +12 -51
  18. package/dist/report/standalone.js +11 -50
  19. package/flow-report/src/i18n/i18n.d.ts +4 -6
  20. package/package.json +3 -3
  21. package/report/assets/styles.css +0 -39
  22. package/report/renderer/api.js +0 -1
  23. package/report/renderer/category-renderer.js +6 -0
  24. package/report/renderer/components.js +1 -1
  25. package/report/renderer/dom.d.ts +0 -13
  26. package/report/renderer/dom.js +0 -38
  27. package/report/renderer/performance-category-renderer.d.ts +0 -26
  28. package/report/renderer/performance-category-renderer.js +10 -142
  29. package/report/renderer/report-ui-features.d.ts +0 -1
  30. package/report/renderer/report-ui-features.js +3 -13
  31. package/report/renderer/report-utils.d.ts +2 -3
  32. package/report/renderer/report-utils.js +4 -6
  33. package/report/types/report-renderer.d.ts +0 -6
  34. package/shared/localization/locales/ar-XB.json +0 -330
  35. package/shared/localization/locales/ar.json +0 -330
  36. package/shared/localization/locales/bg.json +0 -330
  37. package/shared/localization/locales/ca.json +0 -330
  38. package/shared/localization/locales/cs.json +0 -330
  39. package/shared/localization/locales/da.json +0 -330
  40. package/shared/localization/locales/de.json +0 -330
  41. package/shared/localization/locales/el.json +0 -330
  42. package/shared/localization/locales/en-GB.json +0 -330
  43. package/shared/localization/locales/en-US.json +26 -275
  44. package/shared/localization/locales/en-XA.json +0 -330
  45. package/shared/localization/locales/en-XL.json +26 -275
  46. package/shared/localization/locales/es-419.json +0 -330
  47. package/shared/localization/locales/es.json +0 -330
  48. package/shared/localization/locales/fi.json +0 -330
  49. package/shared/localization/locales/fil.json +0 -330
  50. package/shared/localization/locales/fr.json +0 -330
  51. package/shared/localization/locales/he.json +0 -330
  52. package/shared/localization/locales/hi.json +0 -330
  53. package/shared/localization/locales/hr.json +0 -330
  54. package/shared/localization/locales/hu.json +0 -330
  55. package/shared/localization/locales/id.json +0 -330
  56. package/shared/localization/locales/it.json +0 -330
  57. package/shared/localization/locales/ja.json +0 -330
  58. package/shared/localization/locales/ko.json +0 -330
  59. package/shared/localization/locales/lt.json +0 -330
  60. package/shared/localization/locales/lv.json +0 -330
  61. package/shared/localization/locales/nl.json +0 -330
  62. package/shared/localization/locales/no.json +0 -330
  63. package/shared/localization/locales/pl.json +0 -330
  64. package/shared/localization/locales/pt-PT.json +0 -330
  65. package/shared/localization/locales/pt.json +0 -330
  66. package/shared/localization/locales/ro.json +0 -330
  67. package/shared/localization/locales/ru.json +0 -330
  68. package/shared/localization/locales/sk.json +0 -330
  69. package/shared/localization/locales/sl.json +0 -330
  70. package/shared/localization/locales/sr-Latn.json +0 -330
  71. package/shared/localization/locales/sr.json +0 -330
  72. package/shared/localization/locales/sv.json +0 -330
  73. package/shared/localization/locales/ta.json +0 -330
  74. package/shared/localization/locales/te.json +0 -330
  75. package/shared/localization/locales/th.json +0 -330
  76. package/shared/localization/locales/tr.json +0 -330
  77. package/shared/localization/locales/uk.json +0 -330
  78. package/shared/localization/locales/vi.json +0 -330
  79. package/shared/localization/locales/zh-HK.json +0 -330
  80. package/shared/localization/locales/zh-TW.json +0 -330
  81. package/shared/localization/locales/zh.json +0 -330
  82. package/types/artifacts.d.ts +1 -0
  83. package/types/audit.d.ts +1 -1
  84. package/types/lhr/settings.d.ts +1 -1
  85. package/core/audits/byte-efficiency/duplicated-javascript.d.ts +0 -45
  86. package/core/audits/byte-efficiency/duplicated-javascript.js +0 -223
  87. package/core/audits/byte-efficiency/efficient-animated-content.d.ts +0 -22
  88. package/core/audits/byte-efficiency/efficient-animated-content.js +0 -93
  89. package/core/audits/byte-efficiency/legacy-javascript.d.ts +0 -28
  90. package/core/audits/byte-efficiency/legacy-javascript.js +0 -144
  91. package/core/audits/byte-efficiency/modern-image-formats.d.ts +0 -38
  92. package/core/audits/byte-efficiency/modern-image-formats.js +0 -187
  93. package/core/audits/byte-efficiency/render-blocking-resources.d.ts +0 -53
  94. package/core/audits/byte-efficiency/render-blocking-resources.js +0 -312
  95. package/core/audits/byte-efficiency/uses-long-cache-ttl.d.ts +0 -59
  96. package/core/audits/byte-efficiency/uses-long-cache-ttl.js +0 -293
  97. package/core/audits/byte-efficiency/uses-optimized-images.d.ts +0 -33
  98. package/core/audits/byte-efficiency/uses-optimized-images.js +0 -146
  99. package/core/audits/byte-efficiency/uses-responsive-images-snapshot.d.ts +0 -16
  100. package/core/audits/byte-efficiency/uses-responsive-images-snapshot.js +0 -106
  101. package/core/audits/byte-efficiency/uses-responsive-images.d.ts +0 -44
  102. package/core/audits/byte-efficiency/uses-responsive-images.js +0 -202
  103. package/core/audits/byte-efficiency/uses-text-compression.d.ts +0 -14
  104. package/core/audits/byte-efficiency/uses-text-compression.js +0 -108
  105. package/core/audits/critical-request-chains.d.ts +0 -44
  106. package/core/audits/critical-request-chains.js +0 -221
  107. package/core/audits/dobetterweb/dom-size.d.ts +0 -32
  108. package/core/audits/dobetterweb/dom-size.js +0 -182
  109. package/core/audits/dobetterweb/uses-http2.d.ts +0 -72
  110. package/core/audits/dobetterweb/uses-http2.js +0 -276
  111. package/core/audits/font-display.d.ts +0 -32
  112. package/core/audits/font-display.js +0 -195
  113. package/core/audits/largest-contentful-paint-element.d.ts +0 -34
  114. package/core/audits/largest-contentful-paint-element.js +0 -181
  115. package/core/audits/lcp-lazy-loaded.d.ts +0 -22
  116. package/core/audits/lcp-lazy-loaded.js +0 -115
  117. package/core/audits/prioritize-lcp-image.d.ts +0 -74
  118. package/core/audits/prioritize-lcp-image.js +0 -297
  119. package/core/audits/third-party-summary.d.ts +0 -78
  120. package/core/audits/third-party-summary.js +0 -236
  121. package/core/audits/uses-rel-preconnect.d.ts +0 -37
  122. package/core/audits/uses-rel-preconnect.js +0 -286
  123. package/core/audits/viewport.d.ts +0 -17
  124. package/core/audits/viewport.js +0 -87
  125. package/core/audits/work-during-interaction.d.ts +0 -81
  126. package/core/audits/work-during-interaction.js +0 -287
@@ -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