lighthouse 11.3.0-dev.20231207 → 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.
- package/core/audits/bootup-time.js +3 -0
- package/core/audits/byte-efficiency/byte-efficiency-audit.js +6 -4
- package/core/audits/layout-shift-elements.js +23 -12
- package/core/audits/metrics/cumulative-layout-shift.js +5 -1
- package/core/audits/third-party-cookies.d.ts +22 -0
- package/core/audits/third-party-cookies.js +112 -0
- package/core/computed/metrics/cumulative-layout-shift.d.ts +13 -1
- package/core/computed/metrics/cumulative-layout-shift.js +47 -1
- package/core/computed/metrics/lantern-first-contentful-paint.d.ts +50 -16
- package/core/computed/metrics/lantern-first-contentful-paint.js +56 -59
- package/core/computed/metrics/lantern-first-meaningful-paint.js +10 -12
- package/core/computed/metrics/lantern-largest-contentful-paint.js +9 -12
- package/core/computed/metrics/lantern-metric.d.ts +2 -2
- package/core/computed/metrics/lantern-metric.js +6 -5
- package/core/config/default-config.js +2 -0
- package/core/gather/gatherers/css-usage.js +5 -0
- package/core/gather/gatherers/trace-elements.d.ts +6 -15
- package/core/gather/gatherers/trace-elements.js +15 -71
- package/core/lib/rect-helpers.d.ts +5 -0
- package/core/lib/rect-helpers.js +15 -0
- package/dist/report/bundle.esm.js +3 -3
- package/dist/report/flow.js +5 -5
- package/dist/report/standalone.js +4 -4
- package/package.json +1 -1
- package/report/renderer/performance-category-renderer.js +4 -2
- package/shared/localization/locales/en-US.json +12 -0
- package/shared/localization/locales/en-XL.json +12 -0
- package/tsconfig.json +1 -0
- package/types/artifacts.d.ts +1 -2
|
@@ -109,6 +109,9 @@ class BootupTime extends Audit {
|
|
|
109
109
|
settings.throttling.cpuSlowdownMultiplier : 1;
|
|
110
110
|
|
|
111
111
|
const executionTimings = getExecutionTimingsByURL(tasks, networkRecords);
|
|
112
|
+
// Exclude our own tasks.
|
|
113
|
+
executionTimings.delete('_lighthouse-eval.js');
|
|
114
|
+
|
|
112
115
|
const tbtImpact = await this.getTbtImpact(artifacts, context);
|
|
113
116
|
|
|
114
117
|
let hadExcessiveChromeExtension = false;
|
|
@@ -206,10 +206,10 @@ class ByteEfficiencyAudit extends Audit {
|
|
|
206
206
|
if (metricComputationInput.gatherContext.gatherMode === 'navigation') {
|
|
207
207
|
const graph = await PageDependencyGraph.request(metricComputationInput, context);
|
|
208
208
|
const {
|
|
209
|
-
|
|
209
|
+
optimisticGraph: optimisticFCPGraph,
|
|
210
210
|
} = await LanternFirstContentfulPaint.request(metricComputationInput, context);
|
|
211
211
|
const {
|
|
212
|
-
|
|
212
|
+
optimisticGraph: optimisticLCPGraph,
|
|
213
213
|
} = await LanternLargestContentfulPaint.request(metricComputationInput, context);
|
|
214
214
|
|
|
215
215
|
wastedMs = this.computeWasteWithTTIGraph(results, graph, simulator, {
|
|
@@ -218,17 +218,19 @@ class ByteEfficiencyAudit extends Audit {
|
|
|
218
218
|
|
|
219
219
|
const {savings: fcpSavings} = this.computeWasteWithGraph(
|
|
220
220
|
results,
|
|
221
|
-
|
|
221
|
+
optimisticFCPGraph,
|
|
222
222
|
simulator,
|
|
223
223
|
{providedWastedBytesByUrl: result.wastedBytesByUrl, label: 'fcp'}
|
|
224
224
|
);
|
|
225
|
+
// Note: LCP's optimistic graph sometimes unexpectedly yields higher savings than the pessimistic graph.
|
|
225
226
|
const {savings: lcpGraphSavings} = this.computeWasteWithGraph(
|
|
226
227
|
results,
|
|
227
|
-
|
|
228
|
+
optimisticLCPGraph,
|
|
228
229
|
simulator,
|
|
229
230
|
{providedWastedBytesByUrl: result.wastedBytesByUrl, label: 'lcp'}
|
|
230
231
|
);
|
|
231
232
|
|
|
233
|
+
|
|
232
234
|
// The LCP graph can underestimate the LCP savings if there is potential savings on the LCP record itself.
|
|
233
235
|
let lcpRecordSavings = 0;
|
|
234
236
|
const lcpRecord = await LCPImageRecord.request(metricComputationInput, context);
|
|
@@ -40,15 +40,28 @@ class LayoutShiftElements extends Audit {
|
|
|
40
40
|
* @return {Promise<LH.Audit.Product>}
|
|
41
41
|
*/
|
|
42
42
|
static async audit(artifacts, context) {
|
|
43
|
-
const
|
|
44
|
-
.
|
|
43
|
+
const {cumulativeLayoutShift: clsSavings, impactByNodeId} =
|
|
44
|
+
await CumulativeLayoutShiftComputed.request(artifacts.traces[Audit.DEFAULT_PASS], context);
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
/** @type {Array<{node: LH.Audit.Details.ItemValue, score: number}>} */
|
|
47
|
+
const clsElementData = artifacts.TraceElements
|
|
48
|
+
.filter(element => element.traceEventType === 'layout-shift')
|
|
49
|
+
.map(element => ({
|
|
48
50
|
node: Audit.makeNodeItem(element.node),
|
|
49
|
-
score: element.
|
|
50
|
-
};
|
|
51
|
-
|
|
51
|
+
score: impactByNodeId.get(element.nodeId) || 0,
|
|
52
|
+
}));
|
|
53
|
+
|
|
54
|
+
if (clsElementData.length < impactByNodeId.size) {
|
|
55
|
+
const elementDataImpact = clsElementData.reduce((sum, {score}) => sum += score || 0, 0);
|
|
56
|
+
const remainingImpact = Math.max(clsSavings - elementDataImpact, 0);
|
|
57
|
+
clsElementData.push({
|
|
58
|
+
node: {
|
|
59
|
+
type: 'code',
|
|
60
|
+
value: str_(i18n.UIStrings.otherResourceType),
|
|
61
|
+
},
|
|
62
|
+
score: remainingImpact,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
52
65
|
|
|
53
66
|
/** @type {LH.Audit.Details.Table['headings']} */
|
|
54
67
|
const headings = [
|
|
@@ -58,15 +71,13 @@ class LayoutShiftElements extends Audit {
|
|
|
58
71
|
];
|
|
59
72
|
|
|
60
73
|
const details = Audit.makeTableDetails(headings, clsElementData);
|
|
74
|
+
|
|
61
75
|
let displayValue;
|
|
62
|
-
if (
|
|
76
|
+
if (impactByNodeId.size > 0) {
|
|
63
77
|
displayValue = str_(i18n.UIStrings.displayValueElementsFound,
|
|
64
|
-
{nodeCount:
|
|
78
|
+
{nodeCount: impactByNodeId.size});
|
|
65
79
|
}
|
|
66
80
|
|
|
67
|
-
const {cumulativeLayoutShift: clsSavings} =
|
|
68
|
-
await CumulativeLayoutShiftComputed.request(artifacts.traces[Audit.DEFAULT_PASS], context);
|
|
69
|
-
|
|
70
81
|
const passed = clsSavings <= CumulativeLayoutShift.defaultOptions.p10;
|
|
71
82
|
|
|
72
83
|
return {
|
|
@@ -54,7 +54,11 @@ class CumulativeLayoutShift extends Audit {
|
|
|
54
54
|
*/
|
|
55
55
|
static async audit(artifacts, context) {
|
|
56
56
|
const trace = artifacts.traces[Audit.DEFAULT_PASS];
|
|
57
|
-
|
|
57
|
+
|
|
58
|
+
// impactByNodeId is unused but we don't want it on debug data
|
|
59
|
+
// eslint-disable-next-line no-unused-vars
|
|
60
|
+
const {cumulativeLayoutShift, impactByNodeId, ...rest} =
|
|
61
|
+
await ComputedCLS.request(trace, context);
|
|
58
62
|
|
|
59
63
|
/** @type {LH.Audit.Details.DebugData} */
|
|
60
64
|
const details = {
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export default ThirdPartyCookies;
|
|
2
|
+
declare class ThirdPartyCookies extends Audit {
|
|
3
|
+
/**
|
|
4
|
+
* https://source.chromium.org/chromium/chromium/src/+/d2fcd4ba302baeabf4b96d8fa9fdb7a215736c31:third_party/devtools-frontend/src/front_end/models/issues_manager/CookieIssue.ts;l=62-69
|
|
5
|
+
* @param {LH.Crdp.Audits.CookieIssueDetails} cookieIssue
|
|
6
|
+
* @return {string}
|
|
7
|
+
*/
|
|
8
|
+
static getCookieId(cookieIssue: LH.Crdp.Audits.CookieIssueDetails): string;
|
|
9
|
+
/**
|
|
10
|
+
* @param {LH.Artifacts} artifacts
|
|
11
|
+
* @return {Promise<LH.Audit.Product>}
|
|
12
|
+
*/
|
|
13
|
+
static audit(artifacts: LH.Artifacts): Promise<LH.Audit.Product>;
|
|
14
|
+
}
|
|
15
|
+
export namespace UIStrings {
|
|
16
|
+
const title: string;
|
|
17
|
+
const failureTitle: string;
|
|
18
|
+
const description: string;
|
|
19
|
+
const displayValue: string;
|
|
20
|
+
}
|
|
21
|
+
import { Audit } from './audit.js';
|
|
22
|
+
//# sourceMappingURL=third-party-cookies.d.ts.map
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2023 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @fileoverview Audits a page to determine if it is using third party cookies.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import {Audit} from './audit.js';
|
|
12
|
+
import * as i18n from '../lib/i18n/i18n.js';
|
|
13
|
+
|
|
14
|
+
/* eslint-disable max-len */
|
|
15
|
+
const UIStrings = {
|
|
16
|
+
/** Title of a Lighthouse audit that provides detail on the use of third party cookies. This descriptive title is shown to users when the page does not use third party cookies. */
|
|
17
|
+
title: 'Avoids third-party cookies',
|
|
18
|
+
/** Title of a Lighthouse audit that provides detail on the use of third party cookies. This descriptive title is shown to users when the page uses third party cookies. */
|
|
19
|
+
failureTitle: 'Uses third-party cookies',
|
|
20
|
+
/** Description of a Lighthouse audit that tells the user why they should not use third party cookies on their page. 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. */
|
|
21
|
+
description: 'Support for third-party cookies will be removed in a future version of Chrome. [Learn more about phasing out third-party cookies](https://developer.chrome.com/en/docs/privacy-sandbox/third-party-cookie-phase-out/).',
|
|
22
|
+
/** [ICU Syntax] Label for the audit identifying the number of third-party cookies. */
|
|
23
|
+
displayValue: `{itemCount, plural,
|
|
24
|
+
=1 {1 cookie found}
|
|
25
|
+
other {# cookies found}
|
|
26
|
+
}`,
|
|
27
|
+
};
|
|
28
|
+
/* eslint-enable max-len */
|
|
29
|
+
|
|
30
|
+
const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
|
|
31
|
+
|
|
32
|
+
class ThirdPartyCookies extends Audit {
|
|
33
|
+
/**
|
|
34
|
+
* @return {LH.Audit.Meta}
|
|
35
|
+
*/
|
|
36
|
+
static get meta() {
|
|
37
|
+
return {
|
|
38
|
+
id: 'third-party-cookies',
|
|
39
|
+
title: str_(UIStrings.title),
|
|
40
|
+
failureTitle: str_(UIStrings.failureTitle),
|
|
41
|
+
description: str_(UIStrings.description),
|
|
42
|
+
requiredArtifacts: ['InspectorIssues'],
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* https://source.chromium.org/chromium/chromium/src/+/d2fcd4ba302baeabf4b96d8fa9fdb7a215736c31:third_party/devtools-frontend/src/front_end/models/issues_manager/CookieIssue.ts;l=62-69
|
|
48
|
+
* @param {LH.Crdp.Audits.CookieIssueDetails} cookieIssue
|
|
49
|
+
* @return {string}
|
|
50
|
+
*/
|
|
51
|
+
static getCookieId(cookieIssue) {
|
|
52
|
+
if (!cookieIssue.cookie) {
|
|
53
|
+
return cookieIssue.rawCookieLine ?? 'no-cookie-info';
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const {domain, path, name} = cookieIssue.cookie;
|
|
57
|
+
const cookieId = `${domain};${path};${name}`;
|
|
58
|
+
return cookieId;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* @param {LH.Artifacts} artifacts
|
|
63
|
+
* @return {Promise<LH.Audit.Product>}
|
|
64
|
+
*/
|
|
65
|
+
static async audit(artifacts) {
|
|
66
|
+
/** @type {Set<string>} */
|
|
67
|
+
const seenCookies = new Set();
|
|
68
|
+
|
|
69
|
+
/** @type {LH.Audit.Details.TableItem[]} */
|
|
70
|
+
const items = [];
|
|
71
|
+
for (const issue of artifacts.InspectorIssues.cookieIssue) {
|
|
72
|
+
const isPhaseoutWarn = issue.cookieWarningReasons.includes('WarnThirdPartyPhaseout');
|
|
73
|
+
const isPhaseoutExclude = issue.cookieExclusionReasons.includes('ExcludeThirdPartyPhaseout');
|
|
74
|
+
if (!isPhaseoutWarn && !isPhaseoutExclude) continue;
|
|
75
|
+
|
|
76
|
+
// According to JSDOC for `issue.cookie`, if `cookie` is undefined then `rawCookieLine`
|
|
77
|
+
// should be set and no valid cookie could be created. It should be safe to skip in this case.
|
|
78
|
+
const name = issue.cookie?.name || issue.rawCookieLine;
|
|
79
|
+
if (!name) continue;
|
|
80
|
+
|
|
81
|
+
const cookieId = this.getCookieId(issue);
|
|
82
|
+
if (seenCookies.has(cookieId)) continue;
|
|
83
|
+
seenCookies.add(cookieId);
|
|
84
|
+
|
|
85
|
+
items.push({
|
|
86
|
+
name,
|
|
87
|
+
url: issue.cookieUrl,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** @type {LH.Audit.Details.Table['headings']} */
|
|
92
|
+
const headings = [
|
|
93
|
+
{key: 'name', valueType: 'text', label: str_(i18n.UIStrings.columnName)},
|
|
94
|
+
{key: 'url', valueType: 'url', label: str_(i18n.UIStrings.columnURL)},
|
|
95
|
+
];
|
|
96
|
+
const details = Audit.makeTableDetails(headings, items);
|
|
97
|
+
|
|
98
|
+
let displayValue;
|
|
99
|
+
if (items.length > 0) {
|
|
100
|
+
displayValue = str_(UIStrings.displayValue, {itemCount: items.length});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
score: items.length ? 0 : 1,
|
|
105
|
+
displayValue,
|
|
106
|
+
details,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export default ThirdPartyCookies;
|
|
112
|
+
export {UIStrings};
|
|
@@ -11,6 +11,7 @@ declare const CumulativeLayoutShiftComputed: typeof CumulativeLayoutShift & {
|
|
|
11
11
|
}>) => Promise<{
|
|
12
12
|
cumulativeLayoutShift: number;
|
|
13
13
|
cumulativeLayoutShiftMainFrame: number;
|
|
14
|
+
impactByNodeId: Map<number, number>;
|
|
14
15
|
}>;
|
|
15
16
|
};
|
|
16
17
|
declare class CumulativeLayoutShift {
|
|
@@ -23,6 +24,16 @@ declare class CumulativeLayoutShift {
|
|
|
23
24
|
* @return {Array<LayoutShiftEvent>}
|
|
24
25
|
*/
|
|
25
26
|
static getLayoutShiftEvents(processedTrace: LH.Artifacts.ProcessedTrace): Array<LayoutShiftEvent>;
|
|
27
|
+
/**
|
|
28
|
+
* Each layout shift event has a 'score' which is the amount added to the CLS as a result of the given shift(s).
|
|
29
|
+
* We calculate the score per element by taking the 'score' of each layout shift event and
|
|
30
|
+
* distributing it between all the nodes that were shifted, proportianal to the impact region of
|
|
31
|
+
* each shifted element.
|
|
32
|
+
*
|
|
33
|
+
* @param {LayoutShiftEvent[]} layoutShiftEvents
|
|
34
|
+
* @return {Map<number, number>}
|
|
35
|
+
*/
|
|
36
|
+
static getImpactByNodeId(layoutShiftEvents: LayoutShiftEvent[]): Map<number, number>;
|
|
26
37
|
/**
|
|
27
38
|
* Calculates cumulative layout shifts per cluster (session) of LayoutShift
|
|
28
39
|
* events -- where a new cluster is created when there's a gap of more than
|
|
@@ -35,11 +46,12 @@ declare class CumulativeLayoutShift {
|
|
|
35
46
|
/**
|
|
36
47
|
* @param {LH.Trace} trace
|
|
37
48
|
* @param {LH.Artifacts.ComputedContext} context
|
|
38
|
-
* @return {Promise<{cumulativeLayoutShift: number, cumulativeLayoutShiftMainFrame: number}>}
|
|
49
|
+
* @return {Promise<{cumulativeLayoutShift: number, cumulativeLayoutShiftMainFrame: number, impactByNodeId: Map<number, number>}>}
|
|
39
50
|
*/
|
|
40
51
|
static compute_(trace: LH.Trace, context: LH.Artifacts.ComputedContext): Promise<{
|
|
41
52
|
cumulativeLayoutShift: number;
|
|
42
53
|
cumulativeLayoutShiftMainFrame: number;
|
|
54
|
+
impactByNodeId: Map<number, number>;
|
|
43
55
|
}>;
|
|
44
56
|
}
|
|
45
57
|
import { ProcessedTrace } from '../processed-trace.js';
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import {makeComputedArtifact} from '../computed-artifact.js';
|
|
8
8
|
import {ProcessedTrace} from '../processed-trace.js';
|
|
9
|
+
import * as RectHelpers from '../../lib/rect-helpers.js';
|
|
9
10
|
|
|
10
11
|
/** @typedef {{ts: number, isMainFrame: boolean, weightedScore: number, impactedNodes?: LH.Artifacts.TraceImpactedNode[]}} LayoutShiftEvent */
|
|
11
12
|
|
|
@@ -72,6 +73,49 @@ class CumulativeLayoutShift {
|
|
|
72
73
|
return layoutShiftEvents;
|
|
73
74
|
}
|
|
74
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Each layout shift event has a 'score' which is the amount added to the CLS as a result of the given shift(s).
|
|
78
|
+
* We calculate the score per element by taking the 'score' of each layout shift event and
|
|
79
|
+
* distributing it between all the nodes that were shifted, proportianal to the impact region of
|
|
80
|
+
* each shifted element.
|
|
81
|
+
*
|
|
82
|
+
* @param {LayoutShiftEvent[]} layoutShiftEvents
|
|
83
|
+
* @return {Map<number, number>}
|
|
84
|
+
*/
|
|
85
|
+
static getImpactByNodeId(layoutShiftEvents) {
|
|
86
|
+
/** @type {Map<number, number>} */
|
|
87
|
+
const impactByNodeId = new Map();
|
|
88
|
+
|
|
89
|
+
for (const event of layoutShiftEvents) {
|
|
90
|
+
if (!event.impactedNodes) continue;
|
|
91
|
+
|
|
92
|
+
let totalAreaOfImpact = 0;
|
|
93
|
+
/** @type {Map<number, number>} */
|
|
94
|
+
const pixelsMovedPerNode = new Map();
|
|
95
|
+
|
|
96
|
+
for (const node of event.impactedNodes) {
|
|
97
|
+
if (!node.node_id || !node.old_rect || !node.new_rect) continue;
|
|
98
|
+
|
|
99
|
+
const oldRect = RectHelpers.traceRectToLHRect(node.old_rect);
|
|
100
|
+
const newRect = RectHelpers.traceRectToLHRect(node.new_rect);
|
|
101
|
+
const areaOfImpact = RectHelpers.getRectArea(oldRect) +
|
|
102
|
+
RectHelpers.getRectArea(newRect) -
|
|
103
|
+
RectHelpers.getRectOverlapArea(oldRect, newRect);
|
|
104
|
+
|
|
105
|
+
pixelsMovedPerNode.set(node.node_id, areaOfImpact);
|
|
106
|
+
totalAreaOfImpact += areaOfImpact;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
for (const [nodeId, pixelsMoved] of pixelsMovedPerNode.entries()) {
|
|
110
|
+
let clsContribution = impactByNodeId.get(nodeId) || 0;
|
|
111
|
+
clsContribution += (pixelsMoved / totalAreaOfImpact) * event.weightedScore;
|
|
112
|
+
impactByNodeId.set(nodeId, clsContribution);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return impactByNodeId;
|
|
117
|
+
}
|
|
118
|
+
|
|
75
119
|
/**
|
|
76
120
|
* Calculates cumulative layout shifts per cluster (session) of LayoutShift
|
|
77
121
|
* events -- where a new cluster is created when there's a gap of more than
|
|
@@ -104,18 +148,20 @@ class CumulativeLayoutShift {
|
|
|
104
148
|
/**
|
|
105
149
|
* @param {LH.Trace} trace
|
|
106
150
|
* @param {LH.Artifacts.ComputedContext} context
|
|
107
|
-
* @return {Promise<{cumulativeLayoutShift: number, cumulativeLayoutShiftMainFrame: number}>}
|
|
151
|
+
* @return {Promise<{cumulativeLayoutShift: number, cumulativeLayoutShiftMainFrame: number, impactByNodeId: Map<number, number>}>}
|
|
108
152
|
*/
|
|
109
153
|
static async compute_(trace, context) {
|
|
110
154
|
const processedTrace = await ProcessedTrace.request(trace, context);
|
|
111
155
|
|
|
112
156
|
const allFrameShiftEvents =
|
|
113
157
|
CumulativeLayoutShift.getLayoutShiftEvents(processedTrace);
|
|
158
|
+
const impactByNodeId = CumulativeLayoutShift.getImpactByNodeId(allFrameShiftEvents);
|
|
114
159
|
const mainFrameShiftEvents = allFrameShiftEvents.filter(e => e.isMainFrame);
|
|
115
160
|
|
|
116
161
|
return {
|
|
117
162
|
cumulativeLayoutShift: CumulativeLayoutShift.calculate(allFrameShiftEvents),
|
|
118
163
|
cumulativeLayoutShiftMainFrame: CumulativeLayoutShift.calculate(mainFrameShiftEvents),
|
|
164
|
+
impactByNodeId,
|
|
119
165
|
};
|
|
120
166
|
}
|
|
121
167
|
}
|
|
@@ -11,6 +11,16 @@ declare const LanternFirstContentfulPaintComputed: typeof LanternFirstContentful
|
|
|
11
11
|
/** @typedef {import('../../lib/dependency-graph/cpu-node').CPUNode} CPUNode */
|
|
12
12
|
/** @typedef {import('../../lib/dependency-graph/network-node').NetworkNode} NetworkNode */
|
|
13
13
|
declare class LanternFirstContentfulPaint extends LanternMetric {
|
|
14
|
+
/**
|
|
15
|
+
* @typedef FirstPaintBasedGraphOpts
|
|
16
|
+
* @property {number} cutoffTimestamp The timestamp used to filter out tasks that occured after
|
|
17
|
+
* our paint of interest. Typically this is First Contentful Paint or First Meaningful Paint.
|
|
18
|
+
* @property {function(NetworkNode):boolean} treatNodeAsRenderBlocking The function that determines
|
|
19
|
+
* which resources should be considered *possibly* render-blocking.
|
|
20
|
+
* @property {(function(CPUNode):boolean)=} additionalCpuNodesToTreatAsRenderBlocking The function that
|
|
21
|
+
* determines which CPU nodes should also be included in our blocking node IDs set,
|
|
22
|
+
* beyond what getRenderBlockingNodeData() already includes.
|
|
23
|
+
*/
|
|
14
24
|
/**
|
|
15
25
|
* This function computes the set of URLs that *appeared* to be render-blocking based on our filter,
|
|
16
26
|
* *but definitely were not* render-blocking based on the timing of their EvaluateScript task.
|
|
@@ -18,31 +28,55 @@ declare class LanternFirstContentfulPaint extends LanternMetric {
|
|
|
18
28
|
* given timestamp.
|
|
19
29
|
*
|
|
20
30
|
* @param {Node} graph
|
|
21
|
-
* @param {
|
|
22
|
-
*
|
|
23
|
-
* @param {function(NetworkNode):boolean} blockingScriptFilter The function that determines which scripts
|
|
24
|
-
* should be considered *possibly* render-blocking.
|
|
25
|
-
* @param {(function(CPUNode):boolean)=} extraBlockingCpuNodesToIncludeFilter The function that determines which CPU nodes
|
|
26
|
-
* should also be included in our blocking node IDs set.
|
|
27
|
-
* @return {{definitelyNotRenderBlockingScriptUrls: Set<string>, blockingCpuNodeIds: Set<string>}}
|
|
31
|
+
* @param {FirstPaintBasedGraphOpts} opts
|
|
32
|
+
* @return {{definitelyNotRenderBlockingScriptUrls: Set<string>, renderBlockingCpuNodeIds: Set<string>}}
|
|
28
33
|
*/
|
|
29
|
-
static
|
|
34
|
+
static getRenderBlockingNodeData(graph: Node, { cutoffTimestamp, treatNodeAsRenderBlocking, additionalCpuNodesToTreatAsRenderBlocking }: {
|
|
35
|
+
/**
|
|
36
|
+
* The timestamp used to filter out tasks that occured after
|
|
37
|
+
* our paint of interest. Typically this is First Contentful Paint or First Meaningful Paint.
|
|
38
|
+
*/
|
|
39
|
+
cutoffTimestamp: number;
|
|
40
|
+
/**
|
|
41
|
+
* The function that determines
|
|
42
|
+
* which resources should be considered *possibly* render-blocking.
|
|
43
|
+
*/
|
|
44
|
+
treatNodeAsRenderBlocking: (arg0: NetworkNode) => boolean;
|
|
45
|
+
/**
|
|
46
|
+
* The function that
|
|
47
|
+
* determines which CPU nodes should also be included in our blocking node IDs set,
|
|
48
|
+
* beyond what getRenderBlockingNodeData() already includes.
|
|
49
|
+
*/
|
|
50
|
+
additionalCpuNodesToTreatAsRenderBlocking?: ((arg0: CPUNode) => boolean) | undefined;
|
|
51
|
+
}): {
|
|
30
52
|
definitelyNotRenderBlockingScriptUrls: Set<string>;
|
|
31
|
-
|
|
53
|
+
renderBlockingCpuNodeIds: Set<string>;
|
|
32
54
|
};
|
|
33
55
|
/**
|
|
34
56
|
* This function computes the graph required for the first paint of interest.
|
|
35
57
|
*
|
|
36
58
|
* @param {Node} dependencyGraph
|
|
37
|
-
* @param {
|
|
38
|
-
* paint of interest. Typically this is First Contentful Paint or First Meaningful Paint.
|
|
39
|
-
* @param {function(NetworkNode):boolean} blockingResourcesFilter The function that determines which resources
|
|
40
|
-
* should be considered *possibly* render-blocking.
|
|
41
|
-
* @param {(function(CPUNode):boolean)=} extraBlockingCpuNodesToIncludeFilter The function that determines which CPU nodes
|
|
42
|
-
* should also be included in our blocking node IDs set.
|
|
59
|
+
* @param {FirstPaintBasedGraphOpts} opts
|
|
43
60
|
* @return {Node}
|
|
44
61
|
*/
|
|
45
|
-
static getFirstPaintBasedGraph(dependencyGraph: Node,
|
|
62
|
+
static getFirstPaintBasedGraph(dependencyGraph: Node, { cutoffTimestamp, treatNodeAsRenderBlocking, additionalCpuNodesToTreatAsRenderBlocking }: {
|
|
63
|
+
/**
|
|
64
|
+
* The timestamp used to filter out tasks that occured after
|
|
65
|
+
* our paint of interest. Typically this is First Contentful Paint or First Meaningful Paint.
|
|
66
|
+
*/
|
|
67
|
+
cutoffTimestamp: number;
|
|
68
|
+
/**
|
|
69
|
+
* The function that determines
|
|
70
|
+
* which resources should be considered *possibly* render-blocking.
|
|
71
|
+
*/
|
|
72
|
+
treatNodeAsRenderBlocking: (arg0: NetworkNode) => boolean;
|
|
73
|
+
/**
|
|
74
|
+
* The function that
|
|
75
|
+
* determines which CPU nodes should also be included in our blocking node IDs set,
|
|
76
|
+
* beyond what getRenderBlockingNodeData() already includes.
|
|
77
|
+
*/
|
|
78
|
+
additionalCpuNodesToTreatAsRenderBlocking?: ((arg0: CPUNode) => boolean) | undefined;
|
|
79
|
+
}): Node;
|
|
46
80
|
}
|
|
47
81
|
import { LanternMetric } from './lantern-metric.js';
|
|
48
82
|
//# sourceMappingURL=lantern-first-contentful-paint.d.ts.map
|