lighthouse 12.0.0-dev.20240611 → 12.0.0-dev.20240613
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/byte-efficiency-audit.d.ts +2 -2
- package/core/audits/byte-efficiency/byte-efficiency-audit.js +2 -2
- package/core/audits/byte-efficiency/render-blocking-resources.d.ts +3 -3
- package/core/audits/byte-efficiency/render-blocking-resources.js +4 -4
- package/core/audits/dobetterweb/uses-http2.d.ts +2 -2
- package/core/audits/dobetterweb/uses-http2.js +2 -2
- package/core/audits/long-tasks.d.ts +1 -1
- package/core/audits/long-tasks.js +1 -1
- package/core/audits/prioritize-lcp-image.d.ts +1 -1
- package/core/computed/document-urls.js +3 -2
- package/core/computed/load-simulator.d.ts +4 -4
- package/core/computed/load-simulator.js +3 -3
- package/core/computed/main-resource.js +3 -2
- package/core/computed/metrics/lantern-first-contentful-paint.d.ts +4 -4
- package/core/computed/metrics/lantern-first-contentful-paint.js +3 -3
- package/core/computed/metrics/lantern-interactive.d.ts +4 -4
- package/core/computed/metrics/lantern-interactive.js +3 -3
- package/core/computed/metrics/lantern-largest-contentful-paint.d.ts +4 -4
- package/core/computed/metrics/lantern-largest-contentful-paint.js +3 -3
- package/core/computed/metrics/lantern-max-potential-fid.d.ts +4 -4
- package/core/computed/metrics/lantern-max-potential-fid.js +3 -3
- package/core/computed/metrics/lantern-metric.d.ts +4 -3
- package/core/computed/metrics/lantern-metric.js +4 -4
- package/core/computed/metrics/lantern-speed-index.d.ts +4 -4
- package/core/computed/metrics/lantern-speed-index.js +3 -3
- package/core/computed/metrics/lantern-total-blocking-time.d.ts +4 -4
- package/core/computed/metrics/lantern-total-blocking-time.js +3 -3
- package/core/computed/metrics/total-blocking-time.js +3 -1
- package/core/computed/network-analysis.js +2 -2
- package/core/computed/page-dependency-graph.d.ts +2 -2
- package/core/computed/page-dependency-graph.js +6 -6
- package/core/computed/tbt-impact-tasks.js +3 -2
- package/core/config/constants.js +1 -1
- package/core/lib/asset-saver.js +2 -2
- package/core/lib/lantern/{base-node.d.ts → BaseNode.d.ts} +7 -9
- package/core/lib/lantern/{base-node.js → BaseNode.js} +6 -6
- package/core/lib/lantern/BaseNode.test.js +385 -0
- package/core/lib/lantern/{cpu-node.d.ts → CpuNode.d.ts} +8 -9
- package/core/lib/lantern/{cpu-node.js → CpuNode.js} +4 -5
- package/core/lib/lantern/{lantern-error.d.ts → LanternError.d.ts} +1 -1
- package/core/lib/lantern/{metric.d.ts → Metric.d.ts} +17 -17
- package/core/lib/lantern/{metric.js → Metric.js} +10 -12
- package/core/lib/lantern/{network-node.d.ts → NetworkNode.d.ts} +4 -5
- package/core/lib/lantern/{network-node.js → NetworkNode.js} +4 -5
- package/core/lib/lantern/{page-dependency-graph.d.ts → PageDependencyGraph.d.ts} +5 -5
- package/core/lib/lantern/{page-dependency-graph.js → PageDependencyGraph.js} +11 -10
- package/core/lib/lantern/PageDependencyGraph.test.js +654 -0
- package/core/lib/lantern/{tbt-utils.d.ts → TBTUtils.d.ts} +1 -1
- package/core/lib/lantern/TBTUtils.test.d.ts +2 -0
- package/core/lib/lantern/TBTUtils.test.js +130 -0
- package/core/lib/lantern/{trace-engine-computation-data.d.ts → TraceEngineComputationData.d.ts} +3 -3
- package/core/lib/lantern/{trace-engine-computation-data.js → TraceEngineComputationData.js} +5 -7
- package/core/lib/lantern/lantern.d.ts +16 -46
- package/core/lib/lantern/lantern.js +16 -40
- package/core/lib/lantern/metrics/{first-contentful-paint.d.ts → FirstContentfulPaint.d.ts} +11 -11
- package/core/lib/lantern/metrics/{first-contentful-paint.js → FirstContentfulPaint.js} +8 -10
- package/core/lib/lantern/metrics/FirstContentfulPaint.test.js +54 -0
- package/core/lib/lantern/metrics/{interactive.d.ts → Interactive.d.ts} +4 -5
- package/core/lib/lantern/metrics/{interactive.js → Interactive.js} +10 -13
- package/core/lib/lantern/metrics/Interactive.test.js +56 -0
- package/core/lib/lantern/metrics/{largest-contentful-paint.d.ts → LargestContentfulPaint.d.ts} +5 -6
- package/core/lib/lantern/metrics/{largest-contentful-paint.js → LargestContentfulPaint.js} +9 -12
- package/core/lib/lantern/metrics/LargestContentfulPaint.test.js +42 -0
- package/core/lib/lantern/metrics/{max-potential-fid.d.ts → MaxPotentialFID.d.ts} +5 -6
- package/core/lib/lantern/metrics/{max-potential-fid.js → MaxPotentialFID.js} +8 -9
- package/core/lib/lantern/metrics/MetricTestUtils.d.ts +19 -0
- package/core/lib/lantern/metrics/MetricTestUtils.js +48 -0
- package/core/lib/lantern/metrics/{speed-index.d.ts → SpeedIndex.d.ts} +5 -6
- package/core/lib/lantern/metrics/{speed-index.js → SpeedIndex.js} +7 -9
- package/core/lib/lantern/metrics/SpeedIndex.test.js +83 -0
- package/core/lib/lantern/metrics/{total-blocking-time.d.ts → TotalBlockingTime.d.ts} +5 -6
- package/core/lib/lantern/metrics/{total-blocking-time.js → TotalBlockingTime.js} +9 -12
- package/core/lib/lantern/metrics/__snapshots__/first-contentful-paint-test.js.snap +11 -0
- package/core/lib/lantern/metrics/__snapshots__/interactive-test.js.snap +17 -0
- package/core/lib/lantern/metrics/metrics.d.ts +9 -0
- package/core/lib/lantern/metrics/metrics.js +16 -0
- package/core/lib/lantern/{simulator/connection-pool.d.ts → simulation/ConnectionPool.d.ts} +5 -5
- package/core/lib/lantern/{simulator/connection-pool.js → simulation/ConnectionPool.js} +3 -3
- package/core/lib/lantern/simulation/ConnectionPool.test.js +195 -0
- package/core/lib/lantern/simulation/Constants.d.ts +52 -0
- package/core/lib/lantern/simulation/Constants.js +48 -0
- package/core/lib/lantern/{simulator/dns-cache.d.ts → simulation/DNSCache.d.ts} +2 -2
- package/core/lib/lantern/{simulator/dns-cache.js → simulation/DNSCache.js} +1 -1
- package/core/lib/lantern/simulation/DNSCache.test.js +72 -0
- package/core/lib/lantern/{simulator/network-analyzer.d.ts → simulation/NetworkAnalyzer.d.ts} +2 -2
- package/core/lib/lantern/{simulator/network-analyzer.js → simulation/NetworkAnalyzer.js} +1 -1
- package/core/lib/lantern/simulation/NetworkAnalyzer.test.js +475 -0
- package/core/lib/lantern/{simulator/simulator-timing-map.d.ts → simulation/SimulationTimingMap.d.ts} +7 -7
- package/core/lib/lantern/{simulator/simulator-timing-map.js → simulation/SimulationTimingMap.js} +5 -6
- package/core/lib/lantern/{simulator/simulator.d.ts → simulation/Simulator.d.ts} +13 -15
- package/core/lib/lantern/{simulator/simulator.js → simulation/Simulator.js} +25 -26
- package/core/lib/lantern/simulation/Simulator.test.js +434 -0
- package/core/lib/lantern/simulation/TCPConnection.test.d.ts +2 -0
- package/core/lib/lantern/simulation/TCPConnection.test.js +374 -0
- package/core/lib/lantern/{simulator/tcp-connection.d.ts → simulation/TcpConnection.d.ts} +2 -2
- package/core/lib/lantern/{simulator/tcp-connection.js → simulation/TcpConnection.js} +1 -1
- package/core/lib/lantern/simulation/simulation.d.ts +21 -0
- package/core/lib/lantern/simulation/simulation.js +28 -0
- package/core/lib/lantern/types/lantern.d.ts +5 -5
- package/core/lib/lantern-trace-saver.d.ts +4 -4
- package/core/lib/lantern-trace-saver.js +2 -2
- package/core/lib/navigation-error.js +3 -3
- package/core/lib/network-recorder.js +2 -2
- package/core/lib/network-request.d.ts +1 -1
- package/core/lib/network-request.js +1 -1
- package/package.json +2 -2
- package/tsconfig.json +10 -8
- package/types/artifacts.d.ts +3 -4
- package/types/gatherer.d.ts +1 -1
- /package/core/lib/lantern/{lantern-error.js → LanternError.js} +0 -0
- /package/core/lib/lantern/{tbt-utils.js → TBTUtils.js} +0 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2024 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import * as Lantern from './lantern.js';
|
|
8
|
+
|
|
9
|
+
const {calculateSumOfBlockingTime} = Lantern.TBTUtils;
|
|
10
|
+
|
|
11
|
+
describe('TotalBlockingTime utils', () => {
|
|
12
|
+
it('reports 0 when no task is longer than 50ms', () => {
|
|
13
|
+
const events = [
|
|
14
|
+
{start: 1000, end: 1050, duration: 50},
|
|
15
|
+
{start: 2000, end: 2010, duration: 10},
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
const fcpTimeMs = 500;
|
|
19
|
+
const interactiveTimeMs = 4000;
|
|
20
|
+
|
|
21
|
+
expect(
|
|
22
|
+
calculateSumOfBlockingTime(events, fcpTimeMs, interactiveTimeMs)
|
|
23
|
+
).toBe(0);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('only looks at tasks within FCP and TTI', () => {
|
|
27
|
+
const events = [
|
|
28
|
+
{start: 1000, end: 1060, duration: 60},
|
|
29
|
+
{start: 2000, end: 2100, duration: 100},
|
|
30
|
+
{start: 2300, end: 2450, duration: 150},
|
|
31
|
+
{start: 2600, end: 2800, duration: 200},
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
const fcpTimeMs = 1500;
|
|
35
|
+
const interactiveTimeMs = 2500;
|
|
36
|
+
|
|
37
|
+
expect(
|
|
38
|
+
calculateSumOfBlockingTime(events, fcpTimeMs, interactiveTimeMs)
|
|
39
|
+
).toBe(150);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('clips before finding blocking regions', () => {
|
|
43
|
+
const fcpTimeMs = 150;
|
|
44
|
+
const interactiveTimeMs = 300;
|
|
45
|
+
|
|
46
|
+
const events = [
|
|
47
|
+
// The clipping is done first, so the task becomes [150, 200] after clipping and contributes
|
|
48
|
+
// 0ms of blocking time. This is in contrast to first calculating the blocking region ([100,
|
|
49
|
+
// 200]) and then clipping at FCP (150ms), which yields 50ms blocking time.
|
|
50
|
+
{start: 50, end: 200, duration: 150},
|
|
51
|
+
// Similarly, the task is first clipped above to be [240, 300], and then contributes 10ms
|
|
52
|
+
// blocking time.
|
|
53
|
+
{start: 240, end: 460, duration: 120},
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
expect(
|
|
57
|
+
calculateSumOfBlockingTime(events, fcpTimeMs, interactiveTimeMs)
|
|
58
|
+
).toBe(10); // 0ms + 10ms.
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// TTI can happen in the middle of a task, for example, if TTI is at FMP which occurs as part
|
|
62
|
+
// of a larger task, or in the lantern case where we use estimate TTI using a different graph
|
|
63
|
+
// from the one used to estimate TBT.
|
|
64
|
+
it('clips properly if TTI falls in the middle of a task', () => {
|
|
65
|
+
const fcpTimeMs = 1000;
|
|
66
|
+
const interactiveTimeMs = 2000;
|
|
67
|
+
|
|
68
|
+
expect(
|
|
69
|
+
calculateSumOfBlockingTime(
|
|
70
|
+
[{start: 1951, end: 2100, duration: 149}],
|
|
71
|
+
fcpTimeMs,
|
|
72
|
+
interactiveTimeMs
|
|
73
|
+
)
|
|
74
|
+
).toBe(0); // Duration after clipping is 49, which is < 50.
|
|
75
|
+
expect(
|
|
76
|
+
calculateSumOfBlockingTime(
|
|
77
|
+
[{start: 1950, end: 2100, duration: 150}],
|
|
78
|
+
fcpTimeMs,
|
|
79
|
+
interactiveTimeMs
|
|
80
|
+
)
|
|
81
|
+
).toBe(0); // Duration after clipping is 50, so time after 50ms is 0ms.
|
|
82
|
+
expect(
|
|
83
|
+
calculateSumOfBlockingTime(
|
|
84
|
+
[{start: 1949, end: 2100, duration: 151}],
|
|
85
|
+
fcpTimeMs,
|
|
86
|
+
interactiveTimeMs
|
|
87
|
+
)
|
|
88
|
+
).toBe(1); // Duration after clipping is 51, so time after 50ms is 1ms.
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('clips properly if FCP falls in the middle of a task', () => {
|
|
92
|
+
const fcpTimeMs = 1000;
|
|
93
|
+
const interactiveTimeMs = 2000;
|
|
94
|
+
|
|
95
|
+
expect(
|
|
96
|
+
calculateSumOfBlockingTime(
|
|
97
|
+
[{start: 900, end: 1049, duration: 149}],
|
|
98
|
+
fcpTimeMs,
|
|
99
|
+
interactiveTimeMs
|
|
100
|
+
)
|
|
101
|
+
).toBe(0); // Duration after clipping is 49, which is < 50.
|
|
102
|
+
expect(
|
|
103
|
+
calculateSumOfBlockingTime(
|
|
104
|
+
[{start: 900, end: 1050, duration: 150}],
|
|
105
|
+
fcpTimeMs,
|
|
106
|
+
interactiveTimeMs
|
|
107
|
+
)
|
|
108
|
+
).toBe(0); // Duration after clipping is 50, so time after 50ms is 0ms.
|
|
109
|
+
expect(
|
|
110
|
+
calculateSumOfBlockingTime(
|
|
111
|
+
[{start: 900, end: 1051, duration: 151}],
|
|
112
|
+
fcpTimeMs,
|
|
113
|
+
interactiveTimeMs
|
|
114
|
+
)
|
|
115
|
+
).toBe(1); // Duration after clipping is 51, so time after 50ms is 1ms.
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// This can happen in the lantern metric case, where we use the optimistic
|
|
119
|
+
// TTI and pessimistic FCP.
|
|
120
|
+
it('returns 0 if interactiveTime is earlier than FCP', () => {
|
|
121
|
+
const fcpTimeMs = 2050;
|
|
122
|
+
const interactiveTimeMs = 1050;
|
|
123
|
+
|
|
124
|
+
const events = [{start: 500, end: 3000, duration: 2500}];
|
|
125
|
+
|
|
126
|
+
expect(
|
|
127
|
+
calculateSumOfBlockingTime(events, fcpTimeMs, interactiveTimeMs)
|
|
128
|
+
).toBe(0);
|
|
129
|
+
});
|
|
130
|
+
});
|
package/core/lib/lantern/{trace-engine-computation-data.d.ts → TraceEngineComputationData.d.ts}
RENAMED
|
@@ -19,7 +19,7 @@ export function createNetworkRequests(trace: Lantern.Trace, traceEngineData: Tra
|
|
|
19
19
|
* @param {TraceEngine.Handlers.Types.TraceParseData} traceEngineData
|
|
20
20
|
* @param {Lantern.Simulation.URL=} URL
|
|
21
21
|
*/
|
|
22
|
-
export function createGraph(requests: Lantern.NetworkRequest[], trace: Lantern.Trace, traceEngineData: TraceEngine.Handlers.Types.TraceParseData, URL?: Lantern.Simulation.URL | undefined): import("./
|
|
22
|
+
export function createGraph(requests: Lantern.NetworkRequest[], trace: Lantern.Trace, traceEngineData: TraceEngine.Handlers.Types.TraceParseData, URL?: Lantern.Simulation.URL | undefined): import("./PageDependencyGraph.js").Node;
|
|
23
23
|
import * as TraceEngine from '@paulirish/trace_engine';
|
|
24
|
-
import * as Lantern from './
|
|
25
|
-
//# sourceMappingURL=
|
|
24
|
+
import * as Lantern from './lantern.js';
|
|
25
|
+
//# sourceMappingURL=TraceEngineComputationData.d.ts.map
|
|
@@ -7,9 +7,7 @@
|
|
|
7
7
|
import * as TraceEngine from '@paulirish/trace_engine';
|
|
8
8
|
import * as Protocol from '@paulirish/trace_engine/generated/protocol.js';
|
|
9
9
|
|
|
10
|
-
import * as Lantern from './
|
|
11
|
-
import {PageDependencyGraph} from './page-dependency-graph.js';
|
|
12
|
-
import {RESOURCE_TYPES} from '../network-request.js';
|
|
10
|
+
import * as Lantern from './lantern.js';
|
|
13
11
|
|
|
14
12
|
/** @typedef {import('@paulirish/trace_engine/models/trace/handlers/PageLoadMetricsHandler.js').MetricName} MetricName */
|
|
15
13
|
/** @typedef {import('@paulirish/trace_engine/models/trace/handlers/PageLoadMetricsHandler.js').MetricScore} MetricScore */
|
|
@@ -232,7 +230,7 @@ function chooseInitiatorRequest(request, requestsByURL) {
|
|
|
232
230
|
return request.redirectSource;
|
|
233
231
|
}
|
|
234
232
|
|
|
235
|
-
const initiatorURL = PageDependencyGraph.getNetworkInitiators(request)[0];
|
|
233
|
+
const initiatorURL = Lantern.PageDependencyGraph.getNetworkInitiators(request)[0];
|
|
236
234
|
let candidates = requestsByURL.get(initiatorURL) || [];
|
|
237
235
|
// The (valid) initiator must come before the initiated request.
|
|
238
236
|
candidates = candidates.filter(c => {
|
|
@@ -243,7 +241,7 @@ function chooseInitiatorRequest(request, requestsByURL) {
|
|
|
243
241
|
// Disambiguate based on prefetch. Prefetch requests have type 'Other' and cannot
|
|
244
242
|
// initiate requests, so we drop them here.
|
|
245
243
|
const nonPrefetchCandidates = candidates.filter(
|
|
246
|
-
cand => cand.resourceType !==
|
|
244
|
+
cand => cand.resourceType !== Lantern.NetworkRequestTypes.Other);
|
|
247
245
|
if (nonPrefetchCandidates.length) {
|
|
248
246
|
candidates = nonPrefetchCandidates;
|
|
249
247
|
}
|
|
@@ -258,7 +256,7 @@ function chooseInitiatorRequest(request, requestsByURL) {
|
|
|
258
256
|
if (candidates.length > 1 && request.initiator.type === 'parser') {
|
|
259
257
|
// Filter to just Documents when initiator type is parser.
|
|
260
258
|
const documentCandidates = candidates.filter(cand =>
|
|
261
|
-
cand.resourceType ===
|
|
259
|
+
cand.resourceType === Lantern.NetworkRequestTypes.Document);
|
|
262
260
|
if (documentCandidates.length) {
|
|
263
261
|
candidates = documentCandidates;
|
|
264
262
|
}
|
|
@@ -458,7 +456,7 @@ function createGraph(requests, trace, traceEngineData, URL) {
|
|
|
458
456
|
URL.mainDocumentUrl = request.url;
|
|
459
457
|
}
|
|
460
458
|
|
|
461
|
-
return PageDependencyGraph.createGraph(mainThreadEvents, requests, URL);
|
|
459
|
+
return Lantern.PageDependencyGraph.createGraph(mainThreadEvents, requests, URL);
|
|
462
460
|
}
|
|
463
461
|
|
|
464
462
|
export {
|
|
@@ -1,50 +1,20 @@
|
|
|
1
|
+
export { BaseNode } from "./BaseNode.js";
|
|
2
|
+
export { CPUNode } from "./CpuNode.js";
|
|
3
|
+
export { LanternError as Error } from "./LanternError.js";
|
|
4
|
+
export { Metric } from "./Metric.js";
|
|
5
|
+
export { NetworkNode } from "./NetworkNode.js";
|
|
6
|
+
export { PageDependencyGraph } from "./PageDependencyGraph.js";
|
|
7
|
+
export * as Metrics from "./metrics/metrics.js";
|
|
8
|
+
export * as Simulation from "./simulation/simulation.js";
|
|
9
|
+
export * as TBTUtils from "./TBTUtils.js";
|
|
10
|
+
export * as TraceEngineComputationData from "./TraceEngineComputationData.js";
|
|
11
|
+
export type NetworkRequest<T = any> = Lantern.NetworkRequest<T>;
|
|
12
|
+
export type ResourcePriority = Lantern.ResourcePriority;
|
|
13
|
+
export type ResourceTiming = Lantern.ResourceTiming;
|
|
14
|
+
export type ResourceType = Lantern.ResourceType;
|
|
15
|
+
export type Trace = Lantern.Trace;
|
|
16
|
+
export type TraceEvent = Lantern.TraceEvent;
|
|
1
17
|
/** @type {Lantern.Util.SelfMap<Lantern.ResourceType>} */
|
|
2
18
|
export const NetworkRequestTypes: Lantern.Util.SelfMap<Lantern.ResourceType>;
|
|
3
|
-
export namespace constants {
|
|
4
|
-
export { throttling };
|
|
5
|
-
}
|
|
6
19
|
import * as Lantern from './types/lantern.js';
|
|
7
|
-
declare namespace throttling {
|
|
8
|
-
export { DEVTOOLS_RTT_ADJUSTMENT_FACTOR };
|
|
9
|
-
export { DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR };
|
|
10
|
-
export namespace mobileSlow4G {
|
|
11
|
-
const rttMs: number;
|
|
12
|
-
const throughputKbps: number;
|
|
13
|
-
const requestLatencyMs: number;
|
|
14
|
-
const downloadThroughputKbps: number;
|
|
15
|
-
const uploadThroughputKbps: number;
|
|
16
|
-
const cpuSlowdownMultiplier: number;
|
|
17
|
-
}
|
|
18
|
-
export namespace mobileRegular3G {
|
|
19
|
-
const rttMs_1: number;
|
|
20
|
-
export { rttMs_1 as rttMs };
|
|
21
|
-
const throughputKbps_1: number;
|
|
22
|
-
export { throughputKbps_1 as throughputKbps };
|
|
23
|
-
const requestLatencyMs_1: number;
|
|
24
|
-
export { requestLatencyMs_1 as requestLatencyMs };
|
|
25
|
-
const downloadThroughputKbps_1: number;
|
|
26
|
-
export { downloadThroughputKbps_1 as downloadThroughputKbps };
|
|
27
|
-
const uploadThroughputKbps_1: number;
|
|
28
|
-
export { uploadThroughputKbps_1 as uploadThroughputKbps };
|
|
29
|
-
const cpuSlowdownMultiplier_1: number;
|
|
30
|
-
export { cpuSlowdownMultiplier_1 as cpuSlowdownMultiplier };
|
|
31
|
-
}
|
|
32
|
-
export namespace desktopDense4G {
|
|
33
|
-
const rttMs_2: number;
|
|
34
|
-
export { rttMs_2 as rttMs };
|
|
35
|
-
const throughputKbps_2: number;
|
|
36
|
-
export { throughputKbps_2 as throughputKbps };
|
|
37
|
-
const cpuSlowdownMultiplier_2: number;
|
|
38
|
-
export { cpuSlowdownMultiplier_2 as cpuSlowdownMultiplier };
|
|
39
|
-
const requestLatencyMs_2: number;
|
|
40
|
-
export { requestLatencyMs_2 as requestLatencyMs };
|
|
41
|
-
const downloadThroughputKbps_2: number;
|
|
42
|
-
export { downloadThroughputKbps_2 as downloadThroughputKbps };
|
|
43
|
-
const uploadThroughputKbps_2: number;
|
|
44
|
-
export { uploadThroughputKbps_2 as uploadThroughputKbps };
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
declare const DEVTOOLS_RTT_ADJUSTMENT_FACTOR: 3.75;
|
|
48
|
-
declare const DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR: 0.9;
|
|
49
|
-
export {};
|
|
50
20
|
//# sourceMappingURL=lantern.d.ts.map
|
|
@@ -28,48 +28,24 @@ const NetworkRequestTypes = {
|
|
|
28
28
|
Prefetch: 'Prefetch',
|
|
29
29
|
};
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
export {BaseNode} from './BaseNode.js';
|
|
32
|
+
export {CPUNode} from './CpuNode.js';
|
|
33
|
+
export {LanternError as Error} from './LanternError.js';
|
|
34
|
+
export {Metric} from './Metric.js';
|
|
35
|
+
export {NetworkNode} from './NetworkNode.js';
|
|
36
|
+
export {PageDependencyGraph} from './PageDependencyGraph.js';
|
|
37
|
+
export * as Metrics from './metrics/metrics.js';
|
|
38
|
+
export * as Simulation from './simulation/simulation.js';
|
|
39
|
+
export * as TBTUtils from './TBTUtils.js';
|
|
40
|
+
export * as TraceEngineComputationData from './TraceEngineComputationData.js';
|
|
33
41
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
rttMs: 150,
|
|
41
|
-
throughputKbps: 1.6 * 1024,
|
|
42
|
-
requestLatencyMs: 150 * DEVTOOLS_RTT_ADJUSTMENT_FACTOR,
|
|
43
|
-
downloadThroughputKbps: 1.6 * 1024 * DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR,
|
|
44
|
-
uploadThroughputKbps: 750 * DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR,
|
|
45
|
-
cpuSlowdownMultiplier: 4,
|
|
46
|
-
},
|
|
47
|
-
// These values partially align with WebPageTest's definition of "Regular 3G".
|
|
48
|
-
// These values are meant to roughly align with Chrome UX report's 3G definition which are based
|
|
49
|
-
// on HTTP RTT of 300-1400ms and downlink throughput of <700kbps.
|
|
50
|
-
mobileRegular3G: {
|
|
51
|
-
rttMs: 300,
|
|
52
|
-
throughputKbps: 700,
|
|
53
|
-
requestLatencyMs: 300 * DEVTOOLS_RTT_ADJUSTMENT_FACTOR,
|
|
54
|
-
downloadThroughputKbps: 700 * DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR,
|
|
55
|
-
uploadThroughputKbps: 700 * DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR,
|
|
56
|
-
cpuSlowdownMultiplier: 4,
|
|
57
|
-
},
|
|
58
|
-
// Using a "broadband" connection type
|
|
59
|
-
// Corresponds to "Dense 4G 25th percentile" in https://docs.google.com/document/d/1Ft1Bnq9-t4jK5egLSOc28IL4TvR-Tt0se_1faTA4KTY/edit#heading=h.bb7nfy2x9e5v
|
|
60
|
-
desktopDense4G: {
|
|
61
|
-
rttMs: 40,
|
|
62
|
-
throughputKbps: 10 * 1024,
|
|
63
|
-
cpuSlowdownMultiplier: 1,
|
|
64
|
-
requestLatencyMs: 0, // 0 means unset
|
|
65
|
-
downloadThroughputKbps: 0,
|
|
66
|
-
uploadThroughputKbps: 0,
|
|
67
|
-
},
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
const constants = {throttling};
|
|
42
|
+
/** @template [T=any] @typedef {Lantern.NetworkRequest<T>} NetworkRequest */
|
|
43
|
+
/** @typedef {Lantern.ResourcePriority} ResourcePriority */
|
|
44
|
+
/** @typedef {Lantern.ResourceTiming} ResourceTiming */
|
|
45
|
+
/** @typedef {Lantern.ResourceType} ResourceType */
|
|
46
|
+
/** @typedef {Lantern.Trace} Trace */
|
|
47
|
+
/** @typedef {Lantern.TraceEvent} TraceEvent */
|
|
71
48
|
|
|
72
49
|
export {
|
|
73
50
|
NetworkRequestTypes,
|
|
74
|
-
constants,
|
|
75
51
|
};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
export type Node = import('../
|
|
2
|
-
export type NetworkNode<T> = import('../
|
|
3
|
-
export type CpuNode = import('../
|
|
4
|
-
/** @typedef {import('../
|
|
5
|
-
/** @template T @typedef {import('../
|
|
6
|
-
/** @typedef {import('../
|
|
7
|
-
export class FirstContentfulPaint extends Metric {
|
|
1
|
+
export type Node = import('../BaseNode.js').Node;
|
|
2
|
+
export type NetworkNode<T> = import('../NetworkNode.js').NetworkNode<T>;
|
|
3
|
+
export type CpuNode = import('../CpuNode.js').CPUNode;
|
|
4
|
+
/** @typedef {import('../BaseNode.js').Node} Node */
|
|
5
|
+
/** @template T @typedef {import('../NetworkNode.js').NetworkNode<T>} NetworkNode */
|
|
6
|
+
/** @typedef {import('../CpuNode.js').CPUNode} CpuNode */
|
|
7
|
+
export class FirstContentfulPaint extends Lantern.Metric {
|
|
8
8
|
/**
|
|
9
9
|
* @template T
|
|
10
10
|
* @typedef FirstPaintBasedGraphOpts
|
|
@@ -37,7 +37,7 @@ export class FirstContentfulPaint extends Metric {
|
|
|
37
37
|
* The function that determines
|
|
38
38
|
* which resources should be considered *possibly* render-blocking.
|
|
39
39
|
*/
|
|
40
|
-
treatNodeAsRenderBlocking: (arg0:
|
|
40
|
+
treatNodeAsRenderBlocking: (arg0: Lantern.NetworkNode<T>) => boolean;
|
|
41
41
|
/**
|
|
42
42
|
* The function that
|
|
43
43
|
* determines which CPU nodes should also be included in our blocking node IDs set,
|
|
@@ -66,7 +66,7 @@ export class FirstContentfulPaint extends Metric {
|
|
|
66
66
|
* The function that determines
|
|
67
67
|
* which resources should be considered *possibly* render-blocking.
|
|
68
68
|
*/
|
|
69
|
-
treatNodeAsRenderBlocking: (arg0:
|
|
69
|
+
treatNodeAsRenderBlocking: (arg0: Lantern.NetworkNode<T_1>) => boolean;
|
|
70
70
|
/**
|
|
71
71
|
* The function that
|
|
72
72
|
* determines which CPU nodes should also be included in our blocking node IDs set,
|
|
@@ -75,5 +75,5 @@ export class FirstContentfulPaint extends Metric {
|
|
|
75
75
|
additionalCpuNodesToTreatAsRenderBlocking?: ((arg0: CpuNode) => boolean) | undefined;
|
|
76
76
|
}): Node;
|
|
77
77
|
}
|
|
78
|
-
import
|
|
79
|
-
//# sourceMappingURL=
|
|
78
|
+
import * as Lantern from '../lantern.js';
|
|
79
|
+
//# sourceMappingURL=FirstContentfulPaint.d.ts.map
|
|
@@ -4,15 +4,13 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import * as Lantern from '../
|
|
8
|
-
import {Metric} from '../metric.js';
|
|
9
|
-
import {BaseNode} from '../base-node.js';
|
|
7
|
+
import * as Lantern from '../lantern.js';
|
|
10
8
|
|
|
11
|
-
/** @typedef {import('../
|
|
12
|
-
/** @template T @typedef {import('../
|
|
13
|
-
/** @typedef {import('../
|
|
9
|
+
/** @typedef {import('../BaseNode.js').Node} Node */
|
|
10
|
+
/** @template T @typedef {import('../NetworkNode.js').NetworkNode<T>} NetworkNode */
|
|
11
|
+
/** @typedef {import('../CpuNode.js').CPUNode} CpuNode */
|
|
14
12
|
|
|
15
|
-
class FirstContentfulPaint extends Metric {
|
|
13
|
+
class FirstContentfulPaint extends Lantern.Metric {
|
|
16
14
|
/**
|
|
17
15
|
* @return {Lantern.Simulation.MetricCoefficients}
|
|
18
16
|
*/
|
|
@@ -57,7 +55,7 @@ class FirstContentfulPaint extends Metric {
|
|
|
57
55
|
/** @type {Array<CpuNode>} */
|
|
58
56
|
const cpuNodes = [];
|
|
59
57
|
graph.traverse(node => {
|
|
60
|
-
if (node.type === BaseNode.TYPES.CPU) {
|
|
58
|
+
if (node.type === Lantern.BaseNode.TYPES.CPU) {
|
|
61
59
|
// A task is *possibly* render blocking if it *started* before cutoffTimestamp.
|
|
62
60
|
// We use startTime here because the paint event can be *inside* the task that was render blocking.
|
|
63
61
|
if (node.startTime <= cutoffTimestamp) cpuNodes.push(node);
|
|
@@ -75,7 +73,7 @@ class FirstContentfulPaint extends Metric {
|
|
|
75
73
|
cpuNodes.sort((a, b) => a.startTime - b.startTime);
|
|
76
74
|
|
|
77
75
|
// A script is *possibly* render blocking if it finished loading before cutoffTimestamp.
|
|
78
|
-
const possiblyRenderBlockingScriptUrls = Metric.getScriptUrls(graph, node => {
|
|
76
|
+
const possiblyRenderBlockingScriptUrls = Lantern.Metric.getScriptUrls(graph, node => {
|
|
79
77
|
// The optimistic LCP treatNodeAsRenderBlocking fn wants to exclude some images in the graph,
|
|
80
78
|
// but here it only receives scripts to evaluate. It's a no-op in this case, but it will
|
|
81
79
|
// matter below in the getFirstPaintBasedGraph clone operation.
|
|
@@ -147,7 +145,7 @@ class FirstContentfulPaint extends Metric {
|
|
|
147
145
|
const {definitelyNotRenderBlockingScriptUrls, renderBlockingCpuNodeIds} = rbData;
|
|
148
146
|
|
|
149
147
|
return dependencyGraph.cloneWithRelationships(node => {
|
|
150
|
-
if (node.type === BaseNode.TYPES.NETWORK) {
|
|
148
|
+
if (node.type === Lantern.BaseNode.TYPES.NETWORK) {
|
|
151
149
|
// Exclude all nodes that ended after cutoffTimestamp (except for the main document which we always consider necessary)
|
|
152
150
|
// endTime is negative if request does not finish, make sure startTime isn't after cutoffTimestamp in this case.
|
|
153
151
|
const endedAfterPaint = node.endTime > cutoffTimestamp || node.startTime > cutoffTimestamp;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2024 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import assert from 'assert/strict';
|
|
8
|
+
|
|
9
|
+
import * as Lantern from '../lantern.js';
|
|
10
|
+
import {readJson} from '../../../test/test-utils.js';
|
|
11
|
+
import {getComputationDataFromFixture} from './MetricTestUtils.js';
|
|
12
|
+
|
|
13
|
+
const {FirstContentfulPaint} = Lantern.Metrics;
|
|
14
|
+
|
|
15
|
+
const trace = readJson('../../../fixtures/artifacts/progressive-app/trace.json', import.meta);
|
|
16
|
+
|
|
17
|
+
describe('Metrics: Lantern FCP', () => {
|
|
18
|
+
it('should compute predicted value', async () => {
|
|
19
|
+
const data = await getComputationDataFromFixture({trace});
|
|
20
|
+
const result = await FirstContentfulPaint.compute(data);
|
|
21
|
+
|
|
22
|
+
expect({
|
|
23
|
+
timing: Math.round(result.timing),
|
|
24
|
+
optimistic: Math.round(result.optimisticEstimate.timeInMs),
|
|
25
|
+
pessimistic: Math.round(result.pessimisticEstimate.timeInMs),
|
|
26
|
+
optimisticNodeTimings: result.optimisticEstimate.nodeTimings.size,
|
|
27
|
+
pessimisticNodeTimings: result.pessimisticEstimate.nodeTimings.size,
|
|
28
|
+
}).toMatchSnapshot();
|
|
29
|
+
assert.ok(result.optimisticGraph, 'should have created optimistic graph');
|
|
30
|
+
assert.ok(result.pessimisticGraph, 'should have created pessimistic graph');
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('should handle negative request networkEndTime', async () => {
|
|
34
|
+
const data = await getComputationDataFromFixture({trace});
|
|
35
|
+
data.graph.request.networkEndTime = -1;
|
|
36
|
+
const result = await FirstContentfulPaint.compute(data);
|
|
37
|
+
|
|
38
|
+
const optimisticNodes = [];
|
|
39
|
+
result.optimisticGraph.traverse(node => {
|
|
40
|
+
if (node.type === 'network') {
|
|
41
|
+
optimisticNodes.push(node);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
expect(optimisticNodes.map(node => node.request.url)).toEqual(['https://squoosh.app/']);
|
|
45
|
+
|
|
46
|
+
const pessimisticNodes = [];
|
|
47
|
+
result.pessimisticGraph.traverse(node => {
|
|
48
|
+
if (node.type === 'network') {
|
|
49
|
+
pessimisticNodes.push(node);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
expect(pessimisticNodes.map(node => node.request.url)).toEqual(['https://squoosh.app/']);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export type Node = import('../
|
|
2
|
-
export class Interactive extends Metric {
|
|
1
|
+
export type Node = import('../BaseNode.js').Node;
|
|
2
|
+
export class Interactive extends Lantern.Metric {
|
|
3
3
|
/**
|
|
4
4
|
* @param {Node} dependencyGraph
|
|
5
5
|
* @return {Node}
|
|
@@ -16,6 +16,5 @@ export class Interactive extends Metric {
|
|
|
16
16
|
*/
|
|
17
17
|
static getLastLongTaskEndTime(nodeTimings: Lantern.Simulation.Result['nodeTimings'], duration?: number): number;
|
|
18
18
|
}
|
|
19
|
-
import
|
|
20
|
-
|
|
21
|
-
//# sourceMappingURL=interactive.d.ts.map
|
|
19
|
+
import * as Lantern from '../lantern.js';
|
|
20
|
+
//# sourceMappingURL=Interactive.d.ts.map
|
|
@@ -4,17 +4,14 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import * as Lantern from '../
|
|
8
|
-
import {Metric} from '../metric.js';
|
|
9
|
-
import {BaseNode} from '../base-node.js';
|
|
10
|
-
import {NetworkRequestTypes} from '../lantern.js';
|
|
7
|
+
import * as Lantern from '../lantern.js';
|
|
11
8
|
|
|
12
|
-
/** @typedef {import('../
|
|
9
|
+
/** @typedef {import('../BaseNode.js').Node} Node */
|
|
13
10
|
|
|
14
11
|
// Any CPU task of 20 ms or more will end up being a critical long task on mobile
|
|
15
12
|
const CRITICAL_LONG_TASK_THRESHOLD = 20;
|
|
16
13
|
|
|
17
|
-
class Interactive extends Metric {
|
|
14
|
+
class Interactive extends Lantern.Metric {
|
|
18
15
|
/**
|
|
19
16
|
* @return {Lantern.Simulation.MetricCoefficients}
|
|
20
17
|
*/
|
|
@@ -36,13 +33,13 @@ class Interactive extends Metric {
|
|
|
36
33
|
|
|
37
34
|
return dependencyGraph.cloneWithRelationships(node => {
|
|
38
35
|
// Include everything that might be a long task
|
|
39
|
-
if (node.type === BaseNode.TYPES.CPU) {
|
|
36
|
+
if (node.type === Lantern.BaseNode.TYPES.CPU) {
|
|
40
37
|
return node.duration > minimumCpuTaskDuration;
|
|
41
38
|
}
|
|
42
39
|
|
|
43
40
|
// Include all scripts and high priority requests, exclude all images
|
|
44
|
-
const isImage = node.request.resourceType === NetworkRequestTypes.Image;
|
|
45
|
-
const isScript = node.request.resourceType === NetworkRequestTypes.Script;
|
|
41
|
+
const isImage = node.request.resourceType === Lantern.NetworkRequestTypes.Image;
|
|
42
|
+
const isScript = node.request.resourceType === Lantern.NetworkRequestTypes.Script;
|
|
46
43
|
return (
|
|
47
44
|
!isImage &&
|
|
48
45
|
(isScript ||
|
|
@@ -62,7 +59,7 @@ class Interactive extends Metric {
|
|
|
62
59
|
|
|
63
60
|
/**
|
|
64
61
|
* @param {Lantern.Simulation.Result} simulationResult
|
|
65
|
-
* @param {import('../
|
|
62
|
+
* @param {import('../Metric.js').Extras} extras
|
|
66
63
|
* @return {Lantern.Simulation.Result}
|
|
67
64
|
*/
|
|
68
65
|
static getEstimateFromSimulation(simulationResult, extras) {
|
|
@@ -80,8 +77,8 @@ class Interactive extends Metric {
|
|
|
80
77
|
|
|
81
78
|
/**
|
|
82
79
|
* @param {Lantern.Simulation.MetricComputationDataInput} data
|
|
83
|
-
* @param {Omit<import('../
|
|
84
|
-
* @return {Promise<Lantern.
|
|
80
|
+
* @param {Omit<import('../Metric.js').Extras, 'optimistic'>=} extras
|
|
81
|
+
* @return {Promise<Lantern.Metrics.Result>}
|
|
85
82
|
*/
|
|
86
83
|
static async compute(data, extras) {
|
|
87
84
|
const lcpResult = extras?.lcpResult;
|
|
@@ -101,7 +98,7 @@ class Interactive extends Metric {
|
|
|
101
98
|
static getLastLongTaskEndTime(nodeTimings, duration = 50) {
|
|
102
99
|
return Array.from(nodeTimings.entries())
|
|
103
100
|
.filter(([node, timing]) => {
|
|
104
|
-
if (node.type !== BaseNode.TYPES.CPU) return false;
|
|
101
|
+
if (node.type !== Lantern.BaseNode.TYPES.CPU) return false;
|
|
105
102
|
return timing.duration > duration;
|
|
106
103
|
})
|
|
107
104
|
.map(([_, timing]) => timing.endTime)
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2024 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import assert from 'assert/strict';
|
|
8
|
+
|
|
9
|
+
import * as Lantern from '../lantern.js';
|
|
10
|
+
import {getComputationDataFromFixture} from './MetricTestUtils.js';
|
|
11
|
+
import {readJson} from '../../../test/test-utils.js';
|
|
12
|
+
|
|
13
|
+
const {Interactive, FirstContentfulPaint, LargestContentfulPaint} = Lantern.Metrics;
|
|
14
|
+
|
|
15
|
+
const trace = readJson('../../../fixtures/artifacts/progressive-app/trace.json', import.meta);
|
|
16
|
+
const iframeTrace = readJson('../../../fixtures/artifacts/iframe/trace.json', import.meta);
|
|
17
|
+
|
|
18
|
+
describe('Metrics: Lantern TTI', () => {
|
|
19
|
+
it('should compute predicted value', async () => {
|
|
20
|
+
const data = await getComputationDataFromFixture({trace});
|
|
21
|
+
const result = await Interactive.compute(data, {
|
|
22
|
+
lcpResult: await LargestContentfulPaint.compute(data, {
|
|
23
|
+
fcpResult: await FirstContentfulPaint.compute(data),
|
|
24
|
+
}),
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
expect({
|
|
28
|
+
timing: Math.round(result.timing),
|
|
29
|
+
optimistic: Math.round(result.optimisticEstimate.timeInMs),
|
|
30
|
+
pessimistic: Math.round(result.pessimisticEstimate.timeInMs),
|
|
31
|
+
}).toMatchSnapshot();
|
|
32
|
+
assert.equal(result.optimisticEstimate.nodeTimings.size, 14);
|
|
33
|
+
assert.equal(result.pessimisticEstimate.nodeTimings.size, 31);
|
|
34
|
+
assert.ok(result.optimisticGraph, 'should have created optimistic graph');
|
|
35
|
+
assert.ok(result.pessimisticGraph, 'should have created pessimistic graph');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should compute predicted value on iframes with substantial layout', async () => {
|
|
39
|
+
const data = await getComputationDataFromFixture({
|
|
40
|
+
trace: iframeTrace,
|
|
41
|
+
});
|
|
42
|
+
const result = await Interactive.compute(data, {
|
|
43
|
+
lcpResult: await LargestContentfulPaint.compute(data, {
|
|
44
|
+
fcpResult: await FirstContentfulPaint.compute(data),
|
|
45
|
+
}),
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
expect({
|
|
49
|
+
timing: Math.round(result.timing),
|
|
50
|
+
optimistic: Math.round(result.optimisticEstimate.timeInMs),
|
|
51
|
+
pessimistic: Math.round(result.pessimisticEstimate.timeInMs),
|
|
52
|
+
}).toMatchSnapshot();
|
|
53
|
+
assert.ok(result.optimisticGraph, 'should have created optimistic graph');
|
|
54
|
+
assert.ok(result.pessimisticGraph, 'should have created pessimistic graph');
|
|
55
|
+
});
|
|
56
|
+
});
|
package/core/lib/lantern/metrics/{largest-contentful-paint.d.ts → LargestContentfulPaint.d.ts}
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export type Node = import('../
|
|
2
|
-
/** @typedef {import('../
|
|
3
|
-
export class LargestContentfulPaint extends Metric {
|
|
1
|
+
export type Node = import('../BaseNode.js').Node;
|
|
2
|
+
/** @typedef {import('../BaseNode.js').Node} Node */
|
|
3
|
+
export class LargestContentfulPaint extends Lantern.Metric {
|
|
4
4
|
/**
|
|
5
5
|
* Low priority image nodes are usually offscreen and very unlikely to be the
|
|
6
6
|
* resource that is required for LCP. Our LCP graphs include everything except for these images.
|
|
@@ -15,6 +15,5 @@ export class LargestContentfulPaint extends Metric {
|
|
|
15
15
|
*/
|
|
16
16
|
static getEstimateFromSimulation(simulationResult: Lantern.Simulation.Result): Lantern.Simulation.Result;
|
|
17
17
|
}
|
|
18
|
-
import
|
|
19
|
-
|
|
20
|
-
//# sourceMappingURL=largest-contentful-paint.d.ts.map
|
|
18
|
+
import * as Lantern from '../lantern.js';
|
|
19
|
+
//# sourceMappingURL=LargestContentfulPaint.d.ts.map
|