lighthouse 9.5.0-dev.20230125 → 9.5.0-dev.20230127
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/core/audits/byte-efficiency/legacy-javascript.js +1 -2
- package/core/audits/preload-lcp-image.d.ts +12 -3
- package/core/audits/preload-lcp-image.js +32 -13
- package/core/config/constants.d.ts +2 -2
- package/core/config/constants.js +2 -2
- package/core/config/metrics-to-audits.js +1 -0
- package/core/gather/gatherers/trace-elements.js +1 -1
- package/dist/report/bundle.esm.js +113 -22
- package/dist/report/flow.js +13 -13
- package/dist/report/standalone.js +6 -6
- package/package.json +1 -1
- package/report/assets/styles.css +1 -1
- package/report/renderer/components.js +1 -1
- package/report/renderer/details-renderer.js +15 -2
- package/report/renderer/report-ui-features.js +25 -19
- package/report/renderer/report-utils.d.ts +13 -0
- package/report/renderer/report-utils.js +72 -0
- package/report/test/generator/report-generator-test.js +2 -2
- package/report/test/renderer/performance-category-renderer-test.js +2 -2
- package/report/test/renderer/report-ui-features-test.js +299 -72
- package/report/test/renderer/report-utils-test.js +51 -0
- package/types/artifacts.d.ts +2 -0
|
@@ -222,7 +222,6 @@ class LegacyJavascript extends ByteEfficiencyAudit {
|
|
|
222
222
|
['String.fromCodePoint', 'es6.string.from-code-point'],
|
|
223
223
|
['String.raw', 'es6.string.raw'],
|
|
224
224
|
['String.prototype.repeat', 'es6.string.repeat'],
|
|
225
|
-
['Array.prototype.includes', 'es7.array.includes'],
|
|
226
225
|
['Object.entries', 'es7.object.entries'],
|
|
227
226
|
['Object.getOwnPropertyDescriptors', 'es7.object.get-own-property-descriptors'],
|
|
228
227
|
['Object.values', 'es7.object.values'],
|
|
@@ -266,7 +265,7 @@ class LegacyJavascript extends ByteEfficiencyAudit {
|
|
|
266
265
|
},
|
|
267
266
|
{
|
|
268
267
|
name: '@babel/plugin-transform-regenerator',
|
|
269
|
-
expression: /regeneratorRuntime
|
|
268
|
+
expression: /regeneratorRuntime\(?\)?\.a?wrap/.source,
|
|
270
269
|
// Example of this transform: https://gist.github.com/connorjclark/af8bccfff377ac44efc104a79bc75da2
|
|
271
270
|
// `regeneratorRuntime.awrap` is generated for every usage of `await`, and adds ~80 bytes each.
|
|
272
271
|
estimateBytes: result => result.count * 80,
|
|
@@ -27,14 +27,22 @@ declare class PreloadLCPImageAudit extends Audit {
|
|
|
27
27
|
/**
|
|
28
28
|
* @param {LH.Artifacts.NetworkRequest} mainResource
|
|
29
29
|
* @param {LH.Gatherer.Simulation.GraphNode} graph
|
|
30
|
-
* @param {
|
|
31
|
-
* @param {Array<LH.Artifacts.ImageElement>} imageElements
|
|
30
|
+
* @param {string | undefined} lcpUrl
|
|
32
31
|
* @return {{lcpNodeToPreload?: LH.Gatherer.Simulation.GraphNetworkNode, initiatorPath?: InitiatorPath}}
|
|
33
32
|
*/
|
|
34
|
-
static getLCPNodeToPreload(mainResource: LH.Artifacts.NetworkRequest, graph: LH.Gatherer.Simulation.GraphNode,
|
|
33
|
+
static getLCPNodeToPreload(mainResource: LH.Artifacts.NetworkRequest, graph: LH.Gatherer.Simulation.GraphNode, lcpUrl: string | undefined): {
|
|
35
34
|
lcpNodeToPreload?: import("../lib/dependency-graph/network-node.js").NetworkNode | undefined;
|
|
36
35
|
initiatorPath?: InitiatorPath | undefined;
|
|
37
36
|
};
|
|
37
|
+
/**
|
|
38
|
+
* Match the LCP event with the paint event to get the URL of the image actually painted.
|
|
39
|
+
* This could differ from the `ImageElement` associated with the nodeId if e.g. the LCP
|
|
40
|
+
* was a pseudo-element associated with a node containing a smaller background-image.
|
|
41
|
+
* @param {LH.Trace} trace
|
|
42
|
+
* @param {LH.Artifacts.ProcessedNavigation} processedNavigation
|
|
43
|
+
* @return {string | undefined}
|
|
44
|
+
*/
|
|
45
|
+
static getLcpUrl(trace: LH.Trace, processedNavigation: LH.Artifacts.ProcessedNavigation): string | undefined;
|
|
38
46
|
/**
|
|
39
47
|
* Computes the estimated effect of preloading the LCP image.
|
|
40
48
|
* @param {LH.Artifacts.TraceElement} lcpElement
|
|
@@ -64,4 +72,5 @@ export namespace UIStrings {
|
|
|
64
72
|
}
|
|
65
73
|
import { Audit } from "./audit.js";
|
|
66
74
|
import { NetworkRequest } from "../lib/network-request.js";
|
|
75
|
+
import { ProcessedNavigation } from "../computed/processed-navigation.js";
|
|
67
76
|
//# sourceMappingURL=preload-lcp-image.d.ts.map
|
|
@@ -11,6 +11,7 @@ import {MainResource} from '../computed/main-resource.js';
|
|
|
11
11
|
import {LanternLargestContentfulPaint} from '../computed/metrics/lantern-largest-contentful-paint.js';
|
|
12
12
|
import {LoadSimulator} from '../computed/load-simulator.js';
|
|
13
13
|
import {ByteEfficiencyAudit} from './byte-efficiency/byte-efficiency-audit.js';
|
|
14
|
+
import {ProcessedNavigation} from '../computed/processed-navigation.js';
|
|
14
15
|
|
|
15
16
|
const UIStrings = {
|
|
16
17
|
/** Title of a lighthouse audit that tells a user to preload an image in order to improve their LCP time. */
|
|
@@ -36,8 +37,7 @@ class PreloadLCPImageAudit extends Audit {
|
|
|
36
37
|
title: str_(UIStrings.title),
|
|
37
38
|
description: str_(UIStrings.description),
|
|
38
39
|
supportedModes: ['navigation'],
|
|
39
|
-
requiredArtifacts: ['traces', 'devtoolsLogs', 'GatherContext', 'URL', 'TraceElements',
|
|
40
|
-
'ImageElements'],
|
|
40
|
+
requiredArtifacts: ['traces', 'devtoolsLogs', 'GatherContext', 'URL', 'TraceElements'],
|
|
41
41
|
scoreDisplayMode: Audit.SCORING_MODES.NUMERIC,
|
|
42
42
|
};
|
|
43
43
|
}
|
|
@@ -87,17 +87,11 @@ class PreloadLCPImageAudit extends Audit {
|
|
|
87
87
|
/**
|
|
88
88
|
* @param {LH.Artifacts.NetworkRequest} mainResource
|
|
89
89
|
* @param {LH.Gatherer.Simulation.GraphNode} graph
|
|
90
|
-
* @param {
|
|
91
|
-
* @param {Array<LH.Artifacts.ImageElement>} imageElements
|
|
90
|
+
* @param {string | undefined} lcpUrl
|
|
92
91
|
* @return {{lcpNodeToPreload?: LH.Gatherer.Simulation.GraphNetworkNode, initiatorPath?: InitiatorPath}}
|
|
93
92
|
*/
|
|
94
|
-
static getLCPNodeToPreload(mainResource, graph,
|
|
95
|
-
|
|
96
|
-
return elem.node.devtoolsNodePath === lcpElement.node.devtoolsNodePath;
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
if (!lcpImageElement) return {};
|
|
100
|
-
const lcpUrl = lcpImageElement.src;
|
|
93
|
+
static getLCPNodeToPreload(mainResource, graph, lcpUrl) {
|
|
94
|
+
if (!lcpUrl) return {};
|
|
101
95
|
const {lcpNode, path} = PreloadLCPImageAudit.findLCPNode(graph, lcpUrl);
|
|
102
96
|
if (!lcpNode || !path) return {};
|
|
103
97
|
|
|
@@ -116,6 +110,29 @@ class PreloadLCPImageAudit extends Audit {
|
|
|
116
110
|
};
|
|
117
111
|
}
|
|
118
112
|
|
|
113
|
+
/**
|
|
114
|
+
* Match the LCP event with the paint event to get the URL of the image actually painted.
|
|
115
|
+
* This could differ from the `ImageElement` associated with the nodeId if e.g. the LCP
|
|
116
|
+
* was a pseudo-element associated with a node containing a smaller background-image.
|
|
117
|
+
* @param {LH.Trace} trace
|
|
118
|
+
* @param {LH.Artifacts.ProcessedNavigation} processedNavigation
|
|
119
|
+
* @return {string | undefined}
|
|
120
|
+
*/
|
|
121
|
+
static getLcpUrl(trace, processedNavigation) {
|
|
122
|
+
const lcpEvent = processedNavigation.largestContentfulPaintAllFramesEvt;
|
|
123
|
+
if (!lcpEvent) return;
|
|
124
|
+
|
|
125
|
+
const lcpImagePaintEvent = trace.traceEvents.filter(e => {
|
|
126
|
+
return e.name === 'LargestImagePaint::Candidate' &&
|
|
127
|
+
e.args.frame === lcpEvent.args.frame &&
|
|
128
|
+
e.args.data?.DOMNodeId === lcpEvent.args.data?.nodeId &&
|
|
129
|
+
e.args.data?.size === lcpEvent.args.data?.size;
|
|
130
|
+
// Get last candidate, in case there was more than one.
|
|
131
|
+
}).sort((a, b) => b.ts - a.ts)[0];
|
|
132
|
+
|
|
133
|
+
return lcpImagePaintEvent?.args.data?.imageUrl;
|
|
134
|
+
}
|
|
135
|
+
|
|
119
136
|
/**
|
|
120
137
|
* Computes the estimated effect of preloading the LCP image.
|
|
121
138
|
* @param {LH.Artifacts.TraceElement} lcpElement
|
|
@@ -223,15 +240,17 @@ class PreloadLCPImageAudit extends Audit {
|
|
|
223
240
|
return {score: null, notApplicable: true};
|
|
224
241
|
}
|
|
225
242
|
|
|
226
|
-
const [mainResource, lanternLCP, simulator] = await Promise.all([
|
|
243
|
+
const [processedNavigation, mainResource, lanternLCP, simulator] = await Promise.all([
|
|
244
|
+
ProcessedNavigation.request(trace, context),
|
|
227
245
|
MainResource.request({devtoolsLog, URL}, context),
|
|
228
246
|
LanternLargestContentfulPaint.request(metricData, context),
|
|
229
247
|
LoadSimulator.request({devtoolsLog, settings: context.settings}, context),
|
|
230
248
|
]);
|
|
231
249
|
|
|
250
|
+
const lcpUrl = PreloadLCPImageAudit.getLcpUrl(trace, processedNavigation);
|
|
232
251
|
const graph = lanternLCP.pessimisticGraph;
|
|
233
252
|
// eslint-disable-next-line max-len
|
|
234
|
-
const {lcpNodeToPreload, initiatorPath} = PreloadLCPImageAudit.getLCPNodeToPreload(mainResource, graph,
|
|
253
|
+
const {lcpNodeToPreload, initiatorPath} = PreloadLCPImageAudit.getLCPNodeToPreload(mainResource, graph, lcpUrl);
|
|
235
254
|
|
|
236
255
|
const {results, wastedMs} =
|
|
237
256
|
PreloadLCPImageAudit.computeWasteWithGraph(lcpElement, lcpNodeToPreload, graph, simulator);
|
|
@@ -80,7 +80,7 @@ declare const MOTOG4_EMULATION_METRICS: Required<LH.SharedFlagsSettings['screenE
|
|
|
80
80
|
* @type {Required<LH.SharedFlagsSettings['screenEmulation']>}
|
|
81
81
|
*/
|
|
82
82
|
declare const DESKTOP_EMULATION_METRICS: Required<LH.SharedFlagsSettings['screenEmulation']>;
|
|
83
|
-
declare const MOTOG4_USERAGENT: "Mozilla/5.0 (Linux; Android 7.0; Moto G (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/
|
|
84
|
-
declare const DESKTOP_USERAGENT: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/
|
|
83
|
+
declare const MOTOG4_USERAGENT: "Mozilla/5.0 (Linux; Android 7.0; Moto G (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Mobile Safari/537.36";
|
|
84
|
+
declare const DESKTOP_USERAGENT: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36";
|
|
85
85
|
export {};
|
|
86
86
|
//# sourceMappingURL=constants.d.ts.map
|
package/core/config/constants.js
CHANGED
|
@@ -81,8 +81,8 @@ const screenEmulationMetrics = {
|
|
|
81
81
|
};
|
|
82
82
|
|
|
83
83
|
|
|
84
|
-
const MOTOG4_USERAGENT = 'Mozilla/5.0 (Linux; Android 7.0; Moto G (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/
|
|
85
|
-
const DESKTOP_USERAGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/
|
|
84
|
+
const MOTOG4_USERAGENT = 'Mozilla/5.0 (Linux; Android 7.0; Moto G (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Mobile Safari/537.36'; // eslint-disable-line max-len
|
|
85
|
+
const DESKTOP_USERAGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36'; // eslint-disable-line max-len
|
|
86
86
|
|
|
87
87
|
const userAgents = {
|
|
88
88
|
mobile: MOTOG4_USERAGENT,
|
|
@@ -231,7 +231,7 @@ class TraceElements extends FRGatherer {
|
|
|
231
231
|
}
|
|
232
232
|
|
|
233
233
|
// These should exist, but trace types are loose.
|
|
234
|
-
const lcpData = processedNavigation.
|
|
234
|
+
const lcpData = processedNavigation.largestContentfulPaintAllFramesEvt?.args?.data;
|
|
235
235
|
if (lcpData?.nodeId === undefined || !lcpData.type) return;
|
|
236
236
|
|
|
237
237
|
return {
|