lighthouse 10.0.1-dev.20230216 → 10.0.1-dev.20230218
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.
|
@@ -1,29 +1,37 @@
|
|
|
1
1
|
export default PrioritizeLcpImage;
|
|
2
|
+
export type InitiatorType = LH.Crdp.Network.Initiator['type'] | 'redirect' | 'fallbackToMain';
|
|
2
3
|
export type InitiatorPath = Array<{
|
|
3
4
|
url: string;
|
|
4
|
-
initiatorType:
|
|
5
|
+
initiatorType: InitiatorType;
|
|
5
6
|
}>;
|
|
6
7
|
/**
|
|
7
|
-
* @typedef {
|
|
8
|
+
* @typedef {LH.Crdp.Network.Initiator['type']|'redirect'|'fallbackToMain'} InitiatorType
|
|
9
|
+
* @typedef {Array<{url: string, initiatorType: InitiatorType}>} InitiatorPath
|
|
8
10
|
*/
|
|
9
11
|
declare class PrioritizeLcpImage extends Audit {
|
|
10
12
|
/**
|
|
11
13
|
*
|
|
12
14
|
* @param {LH.Artifacts.NetworkRequest} request
|
|
13
15
|
* @param {LH.Artifacts.NetworkRequest} mainResource
|
|
14
|
-
* @param {
|
|
16
|
+
* @param {InitiatorPath} initiatorPath
|
|
15
17
|
* @return {boolean}
|
|
16
18
|
*/
|
|
17
|
-
static shouldPreloadRequest(request: LH.Artifacts.NetworkRequest, mainResource: LH.Artifacts.NetworkRequest, initiatorPath:
|
|
19
|
+
static shouldPreloadRequest(request: LH.Artifacts.NetworkRequest, mainResource: LH.Artifacts.NetworkRequest, initiatorPath: InitiatorPath): boolean;
|
|
18
20
|
/**
|
|
19
21
|
* @param {LH.Gatherer.Simulation.GraphNode} graph
|
|
20
22
|
* @param {NetworkRequest} lcpRecord
|
|
21
|
-
* @return {
|
|
23
|
+
* @return {LH.Gatherer.Simulation.GraphNetworkNode|undefined}
|
|
22
24
|
*/
|
|
23
|
-
static findLCPNode(graph: LH.Gatherer.Simulation.GraphNode, lcpRecord: NetworkRequest):
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
static findLCPNode(graph: LH.Gatherer.Simulation.GraphNode, lcpRecord: NetworkRequest): LH.Gatherer.Simulation.GraphNetworkNode | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* Get the initiator path starting with lcpRecord back to mainResource, inclusive.
|
|
28
|
+
* Navigation redirects *to* the mainResource are not included.
|
|
29
|
+
* Path returned will always be at least [lcpRecord, mainResource].
|
|
30
|
+
* @param {NetworkRequest} lcpRecord
|
|
31
|
+
* @param {NetworkRequest} mainResource
|
|
32
|
+
* @return {InitiatorPath}
|
|
33
|
+
*/
|
|
34
|
+
static getLcpInitiatorPath(lcpRecord: NetworkRequest, mainResource: NetworkRequest): InitiatorPath;
|
|
27
35
|
/**
|
|
28
36
|
* @param {LH.Artifacts.NetworkRequest} mainResource
|
|
29
37
|
* @param {LH.Gatherer.Simulation.GraphNode} graph
|
|
@@ -25,7 +25,8 @@ const UIStrings = {
|
|
|
25
25
|
const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
-
* @typedef {
|
|
28
|
+
* @typedef {LH.Crdp.Network.Initiator['type']|'redirect'|'fallbackToMain'} InitiatorType
|
|
29
|
+
* @typedef {Array<{url: string, initiatorType: InitiatorType}>} InitiatorPath
|
|
29
30
|
*/
|
|
30
31
|
|
|
31
32
|
class PrioritizeLcpImage extends Audit {
|
|
@@ -47,18 +48,16 @@ class PrioritizeLcpImage extends Audit {
|
|
|
47
48
|
*
|
|
48
49
|
* @param {LH.Artifacts.NetworkRequest} request
|
|
49
50
|
* @param {LH.Artifacts.NetworkRequest} mainResource
|
|
50
|
-
* @param {
|
|
51
|
+
* @param {InitiatorPath} initiatorPath
|
|
51
52
|
* @return {boolean}
|
|
52
53
|
*/
|
|
53
54
|
static shouldPreloadRequest(request, mainResource, initiatorPath) {
|
|
54
|
-
const mainResourceDepth = mainResource.redirects ? mainResource.redirects.length : 0;
|
|
55
|
-
|
|
56
55
|
// If it's already preloaded, no need to recommend it.
|
|
57
56
|
if (request.isLinkPreload) return false;
|
|
58
57
|
// It's not a request loaded over the network, don't recommend it.
|
|
59
58
|
if (NetworkRequest.isNonNetworkRequest(request)) return false;
|
|
60
|
-
// It's already discoverable from the main document, don't recommend it.
|
|
61
|
-
if (initiatorPath.length <=
|
|
59
|
+
// It's already discoverable from the main document (a path of [lcpRecord, mainResource]), don't recommend it.
|
|
60
|
+
if (initiatorPath.length <= 2) return false;
|
|
62
61
|
// Finally, return whether or not it belongs to the main frame
|
|
63
62
|
return request.frameId === mainResource.frameId;
|
|
64
63
|
}
|
|
@@ -66,23 +65,57 @@ class PrioritizeLcpImage extends Audit {
|
|
|
66
65
|
/**
|
|
67
66
|
* @param {LH.Gatherer.Simulation.GraphNode} graph
|
|
68
67
|
* @param {NetworkRequest} lcpRecord
|
|
69
|
-
* @return {
|
|
68
|
+
* @return {LH.Gatherer.Simulation.GraphNetworkNode|undefined}
|
|
70
69
|
*/
|
|
71
70
|
static findLCPNode(graph, lcpRecord) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
graph.traverse((node, traversalPath) => {
|
|
75
|
-
if (node.type !== 'network') return;
|
|
71
|
+
for (const {node} of graph.traverseGenerator()) {
|
|
72
|
+
if (node.type !== 'network') continue;
|
|
76
73
|
if (node.record.requestId === lcpRecord.requestId) {
|
|
77
|
-
|
|
78
|
-
path =
|
|
79
|
-
traversalPath.slice(1).filter(initiator => initiator.type === 'network');
|
|
74
|
+
return node;
|
|
80
75
|
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Get the initiator path starting with lcpRecord back to mainResource, inclusive.
|
|
81
|
+
* Navigation redirects *to* the mainResource are not included.
|
|
82
|
+
* Path returned will always be at least [lcpRecord, mainResource].
|
|
83
|
+
* @param {NetworkRequest} lcpRecord
|
|
84
|
+
* @param {NetworkRequest} mainResource
|
|
85
|
+
* @return {InitiatorPath}
|
|
86
|
+
*/
|
|
87
|
+
static getLcpInitiatorPath(lcpRecord, mainResource) {
|
|
88
|
+
/** @type {InitiatorPath} */
|
|
89
|
+
const initiatorPath = [];
|
|
90
|
+
let mainResourceReached = false;
|
|
91
|
+
/** @type {NetworkRequest|undefined} */
|
|
92
|
+
let request = lcpRecord;
|
|
93
|
+
|
|
94
|
+
while (request) {
|
|
95
|
+
mainResourceReached ||= request.requestId === mainResource.requestId;
|
|
96
|
+
|
|
97
|
+
/** @type {InitiatorType} */
|
|
98
|
+
let initiatorType = request.initiator?.type ?? 'other';
|
|
99
|
+
// Initiator type usually comes from redirect, but 'redirect' is used for more informative debugData.
|
|
100
|
+
if (request.initiatorRequest && request.initiatorRequest === request.redirectSource) {
|
|
101
|
+
initiatorType = 'redirect';
|
|
102
|
+
}
|
|
103
|
+
// Sometimes the initiator chain is broken and the best that can be done is stitch
|
|
104
|
+
// back to the main resource. Note this in the initiatorType.
|
|
105
|
+
if (!request.initiatorRequest && !mainResourceReached) {
|
|
106
|
+
initiatorType = 'fallbackToMain';
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
initiatorPath.push({url: request.url, initiatorType});
|
|
110
|
+
|
|
111
|
+
// Can't preload before the main resource, so break off initiator path there.
|
|
112
|
+
if (mainResourceReached) break;
|
|
113
|
+
|
|
114
|
+
// Continue up chain, falling back to mainResource if chain is broken.
|
|
115
|
+
request = request.initiatorRequest || mainResource;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return initiatorPath;
|
|
86
119
|
}
|
|
87
120
|
|
|
88
121
|
/**
|
|
@@ -93,18 +126,14 @@ class PrioritizeLcpImage extends Audit {
|
|
|
93
126
|
*/
|
|
94
127
|
static getLCPNodeToPreload(mainResource, graph, lcpRecord) {
|
|
95
128
|
if (!lcpRecord) return {};
|
|
96
|
-
const
|
|
97
|
-
|
|
129
|
+
const lcpNode = PrioritizeLcpImage.findLCPNode(graph, lcpRecord);
|
|
130
|
+
const initiatorPath = PrioritizeLcpImage.getLcpInitiatorPath(lcpRecord, mainResource);
|
|
131
|
+
if (!lcpNode) return {initiatorPath};
|
|
98
132
|
|
|
99
133
|
// eslint-disable-next-line max-len
|
|
100
|
-
const shouldPreload = PrioritizeLcpImage.shouldPreloadRequest(
|
|
134
|
+
const shouldPreload = PrioritizeLcpImage.shouldPreloadRequest(lcpRecord, mainResource, initiatorPath);
|
|
101
135
|
const lcpNodeToPreload = shouldPreload ? lcpNode : undefined;
|
|
102
136
|
|
|
103
|
-
const initiatorPath = [
|
|
104
|
-
{url: lcpNode.record.url, initiatorType: lcpNode.initiatorType},
|
|
105
|
-
...path.map(n => ({url: n.record.url, initiatorType: n.initiatorType})),
|
|
106
|
-
];
|
|
107
|
-
|
|
108
137
|
return {
|
|
109
138
|
lcpNodeToPreload,
|
|
110
139
|
initiatorPath,
|
|
@@ -276,6 +305,7 @@ class PrioritizeLcpImage extends Audit {
|
|
|
276
305
|
|
|
277
306
|
const lcpRecord = PrioritizeLcpImage.getLcpRecord(trace, processedNavigation, networkRecords);
|
|
278
307
|
const graph = lanternLCP.pessimisticGraph;
|
|
308
|
+
// Note: if moving to LCPAllFrames, mainResource would need to be the LCP frame's main resource.
|
|
279
309
|
const {lcpNodeToPreload, initiatorPath} = PrioritizeLcpImage.getLCPNodeToPreload(mainResource,
|
|
280
310
|
graph, lcpRecord);
|
|
281
311
|
|
package/package.json
CHANGED