lighthouse 11.3.0-dev.20231206 → 11.3.0-dev.20231208

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 (45) hide show
  1. package/core/audits/bf-cache.d.ts +1 -0
  2. package/core/audits/bf-cache.js +11 -1
  3. package/core/audits/bootup-time.js +3 -0
  4. package/core/audits/byte-efficiency/byte-efficiency-audit.js +6 -4
  5. package/core/audits/byte-efficiency/duplicated-javascript.d.ts +0 -6
  6. package/core/audits/byte-efficiency/duplicated-javascript.js +9 -37
  7. package/core/audits/byte-efficiency/legacy-javascript.js +1 -1
  8. package/core/audits/byte-efficiency/unminified-javascript.js +2 -2
  9. package/core/audits/byte-efficiency/unused-javascript.js +10 -10
  10. package/core/audits/layout-shift-elements.js +23 -12
  11. package/core/audits/metrics/cumulative-layout-shift.js +5 -1
  12. package/core/audits/resource-summary.d.ts +11 -0
  13. package/core/audits/resource-summary.js +86 -0
  14. package/core/audits/third-party-cookies.d.ts +22 -0
  15. package/core/audits/third-party-cookies.js +112 -0
  16. package/core/computed/metrics/cumulative-layout-shift.d.ts +13 -1
  17. package/core/computed/metrics/cumulative-layout-shift.js +47 -1
  18. package/core/computed/metrics/lantern-first-contentful-paint.d.ts +50 -16
  19. package/core/computed/metrics/lantern-first-contentful-paint.js +56 -59
  20. package/core/computed/metrics/lantern-first-meaningful-paint.js +10 -12
  21. package/core/computed/metrics/lantern-largest-contentful-paint.js +9 -12
  22. package/core/computed/metrics/lantern-metric.d.ts +2 -2
  23. package/core/computed/metrics/lantern-metric.js +6 -5
  24. package/core/config/default-config.js +4 -0
  25. package/core/config/filters.js +1 -0
  26. package/core/gather/base-artifacts.js +2 -1
  27. package/core/gather/gatherers/css-usage.js +5 -0
  28. package/core/gather/gatherers/trace-elements.d.ts +6 -15
  29. package/core/gather/gatherers/trace-elements.js +15 -71
  30. package/core/lib/i18n/i18n.d.ts +2 -2
  31. package/core/lib/i18n/i18n.js +2 -2
  32. package/core/lib/network-request.js +4 -1
  33. package/core/lib/rect-helpers.d.ts +5 -0
  34. package/core/lib/rect-helpers.js +15 -0
  35. package/core/lib/script-helpers.d.ts +1 -1
  36. package/core/lib/script-helpers.js +1 -1
  37. package/dist/report/bundle.esm.js +3 -3
  38. package/dist/report/flow.js +5 -5
  39. package/dist/report/standalone.js +4 -4
  40. package/package.json +1 -1
  41. package/report/renderer/performance-category-renderer.js +4 -2
  42. package/shared/localization/locales/en-US.json +15 -0
  43. package/shared/localization/locales/en-XL.json +15 -0
  44. package/tsconfig.json +1 -0
  45. package/types/artifacts.d.ts +3 -2
@@ -15,7 +15,6 @@
15
15
  import BaseGatherer from '../base-gatherer.js';
16
16
  import {resolveNodeIdToObjectId} from '../driver/dom.js';
17
17
  import {pageFunctions} from '../../lib/page-functions.js';
18
- import * as RectHelpers from '../../lib/rect-helpers.js';
19
18
  import {Sentry} from '../../lib/sentry.js';
20
19
  import Trace from './trace.js';
21
20
  import {ProcessedTrace} from '../../computed/processed-trace.js';
@@ -25,7 +24,9 @@ import {Responsiveness} from '../../computed/metrics/responsiveness.js';
25
24
  import {CumulativeLayoutShift} from '../../computed/metrics/cumulative-layout-shift.js';
26
25
  import {ExecutionContext} from '../driver/execution-context.js';
27
26
 
28
- /** @typedef {{nodeId: number, score?: number, animations?: {name?: string, failureReasonsMask?: number, unsupportedProperties?: string[]}[], type?: string}} TraceElementData */
27
+ /** @typedef {{nodeId: number, animations?: {name?: string, failureReasonsMask?: number, unsupportedProperties?: string[]}[], type?: string}} TraceElementData */
28
+
29
+ const MAX_LAYOUT_SHIFT_ELEMENTS = 15;
29
30
 
30
31
  /**
31
32
  * @this {HTMLElement}
@@ -63,75 +64,19 @@ class TraceElements extends BaseGatherer {
63
64
  }
64
65
 
65
66
  /**
66
- * @param {Array<number>} rect
67
- * @return {LH.Artifacts.Rect}
68
- */
69
- static traceRectToLHRect(rect) {
70
- const rectArgs = {
71
- x: rect[0],
72
- y: rect[1],
73
- width: rect[2],
74
- height: rect[3],
75
- };
76
- return RectHelpers.addRectTopAndBottom(rectArgs);
77
- }
78
-
79
- /**
80
- * This function finds the top (up to 5) elements that contribute to the CLS score of the page.
81
- * Each layout shift event has a 'score' which is the amount added to the CLS as a result of the given shift(s).
82
- * We calculate the score per element by taking the 'score' of each layout shift event and
83
- * distributing it between all the nodes that were shifted, proportianal to the impact region of
84
- * each shifted element.
85
- * @param {LH.Artifacts.ProcessedTrace} processedTrace
86
- * @return {Array<TraceElementData>}
67
+ * This function finds the top (up to 15) elements that contribute to the CLS score of the page.
68
+ *
69
+ * @param {LH.Trace} trace
70
+ * @param {LH.Gatherer.Context} context
71
+ * @return {Promise<Array<TraceElementData>>}
87
72
  */
88
- static getTopLayoutShiftElements(processedTrace) {
89
- /** @type {Map<number, number>} */
90
- const clsPerNode = new Map();
91
- const shiftEvents = CumulativeLayoutShift.getLayoutShiftEvents(processedTrace);
73
+ static async getTopLayoutShiftElements(trace, context) {
74
+ const {impactByNodeId} = await CumulativeLayoutShift.request(trace, context);
92
75
 
93
- shiftEvents.forEach((event) => {
94
- if (!event || !event.impactedNodes) {
95
- return;
96
- }
97
-
98
- let totalAreaOfImpact = 0;
99
- /** @type {Map<number, number>} */
100
- const pixelsMovedPerNode = new Map();
101
-
102
- event.impactedNodes.forEach(node => {
103
- if (!node.node_id || !node.old_rect || !node.new_rect) {
104
- return;
105
- }
106
-
107
- const oldRect = TraceElements.traceRectToLHRect(node.old_rect);
108
- const newRect = TraceElements.traceRectToLHRect(node.new_rect);
109
- const areaOfImpact = RectHelpers.getRectArea(oldRect) +
110
- RectHelpers.getRectArea(newRect) -
111
- RectHelpers.getRectOverlapArea(oldRect, newRect);
112
-
113
- pixelsMovedPerNode.set(node.node_id, areaOfImpact);
114
- totalAreaOfImpact += areaOfImpact;
115
- });
116
-
117
- for (const [nodeId, pixelsMoved] of pixelsMovedPerNode.entries()) {
118
- let clsContribution = clsPerNode.get(nodeId) || 0;
119
- clsContribution += (pixelsMoved / totalAreaOfImpact) * event.weightedScore;
120
- clsPerNode.set(nodeId, clsContribution);
121
- }
122
- });
123
-
124
- const topFive = [...clsPerNode.entries()]
125
- .sort((a, b) => b[1] - a[1])
126
- .slice(0, 5)
127
- .map(([nodeId, clsContribution]) => {
128
- return {
129
- nodeId: nodeId,
130
- score: clsContribution,
131
- };
132
- });
133
-
134
- return topFive;
76
+ return [...impactByNodeId.entries()]
77
+ .sort((a, b) => b[1] - a[1])
78
+ .slice(0, MAX_LAYOUT_SHIFT_ELEMENTS)
79
+ .map(([nodeId]) => ({nodeId}));
135
80
  }
136
81
 
137
82
  /**
@@ -265,7 +210,7 @@ class TraceElements extends BaseGatherer {
265
210
  const {mainThreadEvents} = processedTrace;
266
211
 
267
212
  const lcpNodeData = await TraceElements.getLcpElement(trace, context);
268
- const clsNodeData = TraceElements.getTopLayoutShiftElements(processedTrace);
213
+ const clsNodeData = await TraceElements.getTopLayoutShiftElements(trace, context);
269
214
  const animatedElementData = await this.getAnimatedElements(mainThreadEvents);
270
215
  const responsivenessElementData = await TraceElements.getResponsivenessElement(trace, context);
271
216
 
@@ -311,7 +256,6 @@ class TraceElements extends BaseGatherer {
311
256
  traceElements.push({
312
257
  traceEventType,
313
258
  ...response.result.value,
314
- score: backendNodeData[i].score,
315
259
  animations: backendNodeData[i].animations,
316
260
  nodeId: backendNodeId,
317
261
  type: backendNodeData[i].type,
@@ -69,9 +69,9 @@ export function lookupLocale(locales?: (string | string[]) | undefined, possible
69
69
  * Returns a function that generates `LH.IcuMessage` objects to localize the
70
70
  * messages in `fileStrings` and the shared `i18n.UIStrings`.
71
71
  * @param {string} filename
72
- * @param {Record<string, string>} fileStrings
72
+ * @param {Record<string, string>=} fileStrings
73
73
  */
74
- export function createIcuMessageFn(filename: string, fileStrings: Record<string, string>): (message: string, values?: Record<string, string | number> | undefined) => LH.IcuMessage;
74
+ export function createIcuMessageFn(filename: string, fileStrings?: Record<string, string> | undefined): (message: string, values?: Record<string, string | number> | undefined) => LH.IcuMessage;
75
75
  /**
76
76
  * Returns true if the given value is a string or an LH.IcuMessage.
77
77
  * @param {unknown} value
@@ -168,9 +168,9 @@ function lookupLocale(locales, possibleLocales) {
168
168
  * Returns a function that generates `LH.IcuMessage` objects to localize the
169
169
  * messages in `fileStrings` and the shared `i18n.UIStrings`.
170
170
  * @param {string} filename
171
- * @param {Record<string, string>} fileStrings
171
+ * @param {Record<string, string>=} fileStrings
172
172
  */
173
- function createIcuMessageFn(filename, fileStrings) {
173
+ function createIcuMessageFn(filename, fileStrings = {}) {
174
174
  if (filename.startsWith('file://')) filename = url.fileURLToPath(filename);
175
175
 
176
176
  // In the common case, `filename` is an absolute path that needs to be transformed
@@ -614,7 +614,10 @@ class NetworkRequest {
614
614
  * @return {boolean}
615
615
  */
616
616
  static isContentEncoded(record) {
617
- return record.responseHeaders.some(item => item.name === 'Content-Encoding');
617
+ // FYI: older devtools logs (like our test fixtures) seems to be lower case, while modern logs
618
+ // are Cased-Like-This.
619
+ const pattern = /^content-encoding$/i;
620
+ return record.responseHeaders.some(item => item.name.match(pattern));
618
621
  }
619
622
 
620
623
  /**
@@ -97,4 +97,9 @@ export function filterOutRectsContainedByOthers(rects: LH.Artifacts.Rect[]): LH.
97
97
  * @return {LH.Artifacts.Rect[]}
98
98
  */
99
99
  export function filterOutTinyRects(rects: LH.Artifacts.Rect[]): LH.Artifacts.Rect[];
100
+ /**
101
+ * @param {Array<number>} rect
102
+ * @return {LH.Artifacts.Rect}
103
+ */
104
+ export function traceRectToLHRect(rect: Array<number>): LH.Artifacts.Rect;
100
105
  //# sourceMappingURL=rect-helpers.d.ts.map
@@ -232,6 +232,20 @@ function allRectsContainedWithinEachOther(rectListA, rectListB) {
232
232
  return true;
233
233
  }
234
234
 
235
+ /**
236
+ * @param {Array<number>} rect
237
+ * @return {LH.Artifacts.Rect}
238
+ */
239
+ function traceRectToLHRect(rect) {
240
+ const rectArgs = {
241
+ x: rect[0],
242
+ y: rect[1],
243
+ width: rect[2],
244
+ height: rect[3],
245
+ };
246
+ return addRectTopAndBottom(rectArgs);
247
+ }
248
+
235
249
  export {
236
250
  rectContainsPoint,
237
251
  rectContains,
@@ -248,4 +262,5 @@ export {
248
262
  allRectsContainedWithinEachOther,
249
263
  filterOutRectsContainedByOthers,
250
264
  filterOutTinyRects,
265
+ traceRectToLHRect,
251
266
  };
@@ -41,6 +41,6 @@ export function estimateTransferSize(networkRecord: LH.Artifacts.NetworkRequest
41
41
  * @param {LH.Artifacts} artifacts
42
42
  * @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
43
43
  */
44
- export function estimateCompressionRatioForContent(compressionRatioByUrl: Map<string, number>, url: string, artifacts: LH.Artifacts, networkRecords: Array<LH.Artifacts.NetworkRequest>): Promise<number>;
44
+ export function estimateCompressionRatioForContent(compressionRatioByUrl: Map<string, number>, url: string, artifacts: LH.Artifacts, networkRecords: Array<LH.Artifacts.NetworkRequest>): number;
45
45
  import { NetworkRequest } from './network-request.js';
46
46
  //# sourceMappingURL=script-helpers.d.ts.map
@@ -137,7 +137,7 @@ function estimateCompressedContentSize(networkRecord, totalBytes, resourceType)
137
137
  * @param {LH.Artifacts} artifacts
138
138
  * @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
139
139
  */
140
- async function estimateCompressionRatioForContent(compressionRatioByUrl, url,
140
+ function estimateCompressionRatioForContent(compressionRatioByUrl, url,
141
141
  artifacts, networkRecords) {
142
142
  let compressionRatio = compressionRatioByUrl.get(url);
143
143
  if (compressionRatio !== undefined) return compressionRatio;