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
|
@@ -4,14 +4,11 @@
|
|
|
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 {FirstContentfulPaint} from './first-contentful-paint.js';
|
|
10
|
-
import {LanternError} from '../lantern-error.js';
|
|
7
|
+
import * as Lantern from '../lantern.js';
|
|
11
8
|
|
|
12
|
-
/** @typedef {import('../
|
|
9
|
+
/** @typedef {import('../BaseNode.js').Node} Node */
|
|
13
10
|
|
|
14
|
-
class LargestContentfulPaint extends Metric {
|
|
11
|
+
class LargestContentfulPaint extends Lantern.Metric {
|
|
15
12
|
/**
|
|
16
13
|
* @return {Lantern.Simulation.MetricCoefficients}
|
|
17
14
|
*/
|
|
@@ -45,10 +42,10 @@ class LargestContentfulPaint extends Metric {
|
|
|
45
42
|
static getOptimisticGraph(dependencyGraph, processedNavigation) {
|
|
46
43
|
const lcp = processedNavigation.timestamps.largestContentfulPaint;
|
|
47
44
|
if (!lcp) {
|
|
48
|
-
throw new
|
|
45
|
+
throw new Lantern.Error('NO_LCP');
|
|
49
46
|
}
|
|
50
47
|
|
|
51
|
-
return FirstContentfulPaint.getFirstPaintBasedGraph(dependencyGraph, {
|
|
48
|
+
return Lantern.Metrics.FirstContentfulPaint.getFirstPaintBasedGraph(dependencyGraph, {
|
|
52
49
|
cutoffTimestamp: lcp,
|
|
53
50
|
treatNodeAsRenderBlocking: LargestContentfulPaint.isNotLowPriorityImageNode,
|
|
54
51
|
});
|
|
@@ -62,10 +59,10 @@ class LargestContentfulPaint extends Metric {
|
|
|
62
59
|
static getPessimisticGraph(dependencyGraph, processedNavigation) {
|
|
63
60
|
const lcp = processedNavigation.timestamps.largestContentfulPaint;
|
|
64
61
|
if (!lcp) {
|
|
65
|
-
throw new
|
|
62
|
+
throw new Lantern.Error('NO_LCP');
|
|
66
63
|
}
|
|
67
64
|
|
|
68
|
-
return FirstContentfulPaint.getFirstPaintBasedGraph(dependencyGraph, {
|
|
65
|
+
return Lantern.Metrics.FirstContentfulPaint.getFirstPaintBasedGraph(dependencyGraph, {
|
|
69
66
|
cutoffTimestamp: lcp,
|
|
70
67
|
treatNodeAsRenderBlocking: _ => true,
|
|
71
68
|
// For pessimistic LCP we'll include *all* layout nodes
|
|
@@ -90,8 +87,8 @@ class LargestContentfulPaint extends Metric {
|
|
|
90
87
|
|
|
91
88
|
/**
|
|
92
89
|
* @param {Lantern.Simulation.MetricComputationDataInput} data
|
|
93
|
-
* @param {Omit<import('../
|
|
94
|
-
* @return {Promise<Lantern.
|
|
90
|
+
* @param {Omit<import('../Metric.js').Extras, 'optimistic'>=} extras
|
|
91
|
+
* @return {Promise<Lantern.Metrics.Result>}
|
|
95
92
|
*/
|
|
96
93
|
static async compute(data, extras) {
|
|
97
94
|
const fcpResult = extras?.fcpResult;
|
|
@@ -0,0 +1,42 @@
|
|
|
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 {FirstContentfulPaint, LargestContentfulPaint} = Lantern.Metrics;
|
|
14
|
+
|
|
15
|
+
const trace = readJson('../../../fixtures/artifacts/paul/trace.json', import.meta);
|
|
16
|
+
|
|
17
|
+
describe('Metrics: Lantern LCP', () => {
|
|
18
|
+
it('should compute predicted value', async () => {
|
|
19
|
+
const data = await getComputationDataFromFixture({trace});
|
|
20
|
+
const result = await LargestContentfulPaint.compute(data, {
|
|
21
|
+
fcpResult: await FirstContentfulPaint.compute(data),
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
expect({
|
|
25
|
+
timing: Math.round(result.timing),
|
|
26
|
+
optimistic: Math.round(result.optimisticEstimate.timeInMs),
|
|
27
|
+
pessimistic: Math.round(result.pessimisticEstimate.timeInMs),
|
|
28
|
+
optimisticNodeTimings: result.optimisticEstimate.nodeTimings.size,
|
|
29
|
+
pessimisticNodeTimings: result.pessimisticEstimate.nodeTimings.size}).
|
|
30
|
+
toMatchInlineSnapshot(`
|
|
31
|
+
Object {
|
|
32
|
+
"optimistic": 1457,
|
|
33
|
+
"optimisticNodeTimings": 8,
|
|
34
|
+
"pessimistic": 1616,
|
|
35
|
+
"pessimisticNodeTimings": 9,
|
|
36
|
+
"timing": 1536,
|
|
37
|
+
}
|
|
38
|
+
`);
|
|
39
|
+
assert.ok(result.optimisticGraph, 'should have created optimistic graph');
|
|
40
|
+
assert.ok(result.pessimisticGraph, 'should have created pessimistic graph');
|
|
41
|
+
});
|
|
42
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export type Node = import('../
|
|
2
|
-
/** @typedef {import('../
|
|
3
|
-
export class MaxPotentialFID extends Metric {
|
|
1
|
+
export type Node = import('../BaseNode.js').Node;
|
|
2
|
+
/** @typedef {import('../BaseNode.js').Node} Node */
|
|
3
|
+
export class MaxPotentialFID extends Lantern.Metric {
|
|
4
4
|
/**
|
|
5
5
|
* @param {Node} dependencyGraph
|
|
6
6
|
* @return {Node}
|
|
@@ -20,6 +20,5 @@ export class MaxPotentialFID extends Metric {
|
|
|
20
20
|
duration: number;
|
|
21
21
|
}>;
|
|
22
22
|
}
|
|
23
|
-
import
|
|
24
|
-
|
|
25
|
-
//# sourceMappingURL=max-potential-fid.d.ts.map
|
|
23
|
+
import * as Lantern from '../lantern.js';
|
|
24
|
+
//# sourceMappingURL=MaxPotentialFID.d.ts.map
|
|
@@ -4,13 +4,11 @@
|
|
|
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('../
|
|
9
|
+
/** @typedef {import('../BaseNode.js').Node} Node */
|
|
12
10
|
|
|
13
|
-
class MaxPotentialFID extends Metric {
|
|
11
|
+
class MaxPotentialFID extends Lantern.Metric {
|
|
14
12
|
/**
|
|
15
13
|
* @return {Lantern.Simulation.MetricCoefficients}
|
|
16
14
|
*/
|
|
@@ -40,7 +38,7 @@ class MaxPotentialFID extends Metric {
|
|
|
40
38
|
|
|
41
39
|
/**
|
|
42
40
|
* @param {Lantern.Simulation.Result} simulation
|
|
43
|
-
* @param {import('../
|
|
41
|
+
* @param {import('../Metric.js').Extras} extras
|
|
44
42
|
* @return {Lantern.Simulation.Result}
|
|
45
43
|
*/
|
|
46
44
|
static getEstimateFromSimulation(simulation, extras) {
|
|
@@ -65,8 +63,8 @@ class MaxPotentialFID extends Metric {
|
|
|
65
63
|
|
|
66
64
|
/**
|
|
67
65
|
* @param {Lantern.Simulation.MetricComputationDataInput} data
|
|
68
|
-
* @param {Omit<import('../
|
|
69
|
-
* @return {Promise<Lantern.
|
|
66
|
+
* @param {Omit<import('../Metric.js').Extras, 'optimistic'>=} extras
|
|
67
|
+
* @return {Promise<Lantern.Metrics.Result>}
|
|
70
68
|
*/
|
|
71
69
|
static compute(data, extras) {
|
|
72
70
|
const fcpResult = extras?.fcpResult;
|
|
@@ -84,7 +82,8 @@ class MaxPotentialFID extends Metric {
|
|
|
84
82
|
*/
|
|
85
83
|
static getTimingsAfterFCP(nodeTimings, fcpTimeInMs) {
|
|
86
84
|
return Array.from(nodeTimings.entries())
|
|
87
|
-
.filter(([node, timing]) =>
|
|
85
|
+
.filter(([node, timing]) =>
|
|
86
|
+
node.type === Lantern.BaseNode.TYPES.CPU && timing.endTime > fcpTimeInMs)
|
|
88
87
|
.map(([_, timing]) => timing);
|
|
89
88
|
}
|
|
90
89
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {TraceEngine.Types.TraceEvents.TraceEventData[]} traceEvents
|
|
3
|
+
*/
|
|
4
|
+
export function runTraceEngine(traceEvents: TraceEngine.Types.TraceEvents.TraceEventData[]): Promise<TraceEngine.Handlers.Types.EnabledHandlerDataWithMeta<typeof TraceEngine.Handlers.ModelHandlers>>;
|
|
5
|
+
/**
|
|
6
|
+
* @param {{trace: Lantern.Trace, settings?: Lantern.Simulation.Settings, URL?: Lantern.Simulation.URL}} opts
|
|
7
|
+
*/
|
|
8
|
+
export function getComputationDataFromFixture({ trace, settings, URL }: {
|
|
9
|
+
trace: Lantern.Trace;
|
|
10
|
+
settings?: Lantern.Simulation.Settings;
|
|
11
|
+
URL?: Lantern.Simulation.URL;
|
|
12
|
+
}): Promise<{
|
|
13
|
+
simulator: Lantern.Simulation.Simulator<any>;
|
|
14
|
+
graph: import("../PageDependencyGraph.js").Node;
|
|
15
|
+
processedNavigation: import("../types/lantern.js").Simulation.ProcessedNavigation;
|
|
16
|
+
}>;
|
|
17
|
+
import * as TraceEngine from '@paulirish/trace_engine';
|
|
18
|
+
import * as Lantern from '../lantern.js';
|
|
19
|
+
//# sourceMappingURL=MetricTestUtils.d.ts.map
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2024 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import * as TraceEngine from '@paulirish/trace_engine';
|
|
8
|
+
|
|
9
|
+
import * as Lantern from '../lantern.js';
|
|
10
|
+
import {polyfillDOMRect} from '../../polyfill-dom-rect.js';
|
|
11
|
+
|
|
12
|
+
polyfillDOMRect();
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @param {TraceEngine.Types.TraceEvents.TraceEventData[]} traceEvents
|
|
16
|
+
*/
|
|
17
|
+
async function runTraceEngine(traceEvents) {
|
|
18
|
+
const processor = TraceEngine.Processor.TraceProcessor.createWithAllHandlers();
|
|
19
|
+
await processor.parse(traceEvents);
|
|
20
|
+
if (!processor.traceParsedData) throw new Error('No data');
|
|
21
|
+
return processor.traceParsedData;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @param {{trace: Lantern.Trace, settings?: Lantern.Simulation.Settings, URL?: Lantern.Simulation.URL}} opts
|
|
26
|
+
*/
|
|
27
|
+
async function getComputationDataFromFixture({trace, settings, URL}) {
|
|
28
|
+
settings = settings ?? /** @type {Lantern.Simulation.Settings} */({});
|
|
29
|
+
if (!settings.throttlingMethod) settings.throttlingMethod = 'simulate';
|
|
30
|
+
const traceEngineData = await runTraceEngine(
|
|
31
|
+
/** @type {TraceEngine.Types.TraceEvents.TraceEventData[]} */ (trace.traceEvents)
|
|
32
|
+
);
|
|
33
|
+
const requests =
|
|
34
|
+
Lantern.TraceEngineComputationData.createNetworkRequests(trace, traceEngineData);
|
|
35
|
+
const networkAnalysis = Lantern.Simulation.NetworkAnalyzer.analyze(requests);
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
simulator: Lantern.Simulation.Simulator.createSimulator({...settings, networkAnalysis}),
|
|
39
|
+
graph: Lantern.TraceEngineComputationData.createGraph(requests, trace, traceEngineData, URL),
|
|
40
|
+
processedNavigation:
|
|
41
|
+
Lantern.TraceEngineComputationData.createProcessedNavigation(traceEngineData),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export {
|
|
46
|
+
runTraceEngine,
|
|
47
|
+
getComputationDataFromFixture,
|
|
48
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export type Node = import('../
|
|
2
|
-
/** @typedef {import('../
|
|
3
|
-
export class SpeedIndex extends Metric {
|
|
1
|
+
export type Node = import('../BaseNode.js').Node;
|
|
2
|
+
/** @typedef {import('../BaseNode.js').Node} Node */
|
|
3
|
+
export class SpeedIndex extends Lantern.Metric {
|
|
4
4
|
/**
|
|
5
5
|
* @param {Node} dependencyGraph
|
|
6
6
|
* @return {Node}
|
|
@@ -28,6 +28,5 @@ export class SpeedIndex extends Metric {
|
|
|
28
28
|
*/
|
|
29
29
|
static computeLayoutBasedSpeedIndex(nodeTimings: Lantern.Simulation.Result['nodeTimings'], fcpTimeInMs: number): number;
|
|
30
30
|
}
|
|
31
|
-
import
|
|
32
|
-
|
|
33
|
-
//# sourceMappingURL=speed-index.d.ts.map
|
|
31
|
+
import * as Lantern from '../lantern.js';
|
|
32
|
+
//# sourceMappingURL=SpeedIndex.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
9
|
const mobileSlow4GRtt = 150;
|
|
12
10
|
|
|
13
|
-
/** @typedef {import('../
|
|
11
|
+
/** @typedef {import('../BaseNode.js').Node} Node */
|
|
14
12
|
|
|
15
|
-
class SpeedIndex extends Metric {
|
|
13
|
+
class SpeedIndex extends Lantern.Metric {
|
|
16
14
|
/**
|
|
17
15
|
* @return {Lantern.Simulation.MetricCoefficients}
|
|
18
16
|
*/
|
|
@@ -71,7 +69,7 @@ class SpeedIndex extends Metric {
|
|
|
71
69
|
|
|
72
70
|
/**
|
|
73
71
|
* @param {Lantern.Simulation.Result} simulationResult
|
|
74
|
-
* @param {import('../
|
|
72
|
+
* @param {import('../Metric.js').Extras} extras
|
|
75
73
|
* @return {Lantern.Simulation.Result}
|
|
76
74
|
*/
|
|
77
75
|
static getEstimateFromSimulation(simulationResult, extras) {
|
|
@@ -90,8 +88,8 @@ class SpeedIndex extends Metric {
|
|
|
90
88
|
|
|
91
89
|
/**
|
|
92
90
|
* @param {Lantern.Simulation.MetricComputationDataInput} data
|
|
93
|
-
* @param {Omit<import('../
|
|
94
|
-
* @return {Promise<Lantern.
|
|
91
|
+
* @param {Omit<import('../Metric.js').Extras, 'optimistic'>=} extras
|
|
92
|
+
* @return {Promise<Lantern.Metrics.Result>}
|
|
95
93
|
*/
|
|
96
94
|
static async compute(data, extras) {
|
|
97
95
|
const fcpResult = extras?.fcpResult;
|
|
@@ -123,7 +121,7 @@ class SpeedIndex extends Metric {
|
|
|
123
121
|
/** @type {Array<{time: number, weight: number}>} */
|
|
124
122
|
const layoutWeights = [];
|
|
125
123
|
for (const [node, timing] of nodeTimings.entries()) {
|
|
126
|
-
if (node.type !== BaseNode.TYPES.CPU) continue;
|
|
124
|
+
if (node.type !== Lantern.BaseNode.TYPES.CPU) continue;
|
|
127
125
|
|
|
128
126
|
if (node.childEvents.some(x => x.name === 'Layout')) {
|
|
129
127
|
const timingWeight = Math.max(Math.log2(timing.endTime - timing.startTime), 0);
|
|
@@ -0,0 +1,83 @@
|
|
|
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
|
+
import {readJson} from '../../../test/test-utils.js';
|
|
9
|
+
import {getComputationDataFromFixture} from './MetricTestUtils.js';
|
|
10
|
+
|
|
11
|
+
const {SpeedIndex, FirstContentfulPaint} = Lantern.Metrics;
|
|
12
|
+
|
|
13
|
+
const trace = readJson('../../../fixtures/artifacts/progressive-app/trace.json', import.meta);
|
|
14
|
+
|
|
15
|
+
const defaultThrottling = Lantern.Simulation.Constants.throttling.mobileSlow4G;
|
|
16
|
+
|
|
17
|
+
describe('Metrics: Lantern Speed Index', () => {
|
|
18
|
+
it('should compute predicted value', async () => {
|
|
19
|
+
const data = await getComputationDataFromFixture({trace});
|
|
20
|
+
// TODO: observedSpeedIndex is from the Speedline library, and is used for optimistic
|
|
21
|
+
// mode. At the moment callers must pass the result into Lantern.
|
|
22
|
+
const observedSpeedIndex = 379.04474997520487;
|
|
23
|
+
const result = await SpeedIndex.compute(data, {
|
|
24
|
+
fcpResult: await FirstContentfulPaint.compute(data),
|
|
25
|
+
observedSpeedIndex,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
expect({
|
|
29
|
+
timing: Math.round(result.timing),
|
|
30
|
+
optimistic: Math.round(result.optimisticEstimate.timeInMs),
|
|
31
|
+
pessimistic: Math.round(result.pessimisticEstimate.timeInMs)}).
|
|
32
|
+
toMatchInlineSnapshot(`
|
|
33
|
+
Object {
|
|
34
|
+
"optimistic": 379,
|
|
35
|
+
"pessimistic": 1122,
|
|
36
|
+
"timing": 1107,
|
|
37
|
+
}
|
|
38
|
+
`);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('should compute predicted value for different settings', async () => {
|
|
42
|
+
const settings = {throttlingMethod: 'simulate', throttling: {...defaultThrottling, rttMs: 300}};
|
|
43
|
+
const data = await getComputationDataFromFixture({trace, settings});
|
|
44
|
+
const observedSpeedIndex = 379.04474997520487;
|
|
45
|
+
const result = await SpeedIndex.compute(data, {
|
|
46
|
+
fcpResult: await FirstContentfulPaint.compute(data),
|
|
47
|
+
observedSpeedIndex,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
expect({
|
|
51
|
+
timing: Math.round(result.timing),
|
|
52
|
+
optimistic: Math.round(result.optimisticEstimate.timeInMs),
|
|
53
|
+
pessimistic: Math.round(result.pessimisticEstimate.timeInMs)}).
|
|
54
|
+
toMatchInlineSnapshot(`
|
|
55
|
+
Object {
|
|
56
|
+
"optimistic": 379,
|
|
57
|
+
"pessimistic": 2022,
|
|
58
|
+
"timing": 2007,
|
|
59
|
+
}
|
|
60
|
+
`);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('should not scale coefficients at default', async () => {
|
|
64
|
+
const result = SpeedIndex.getScaledCoefficients(defaultThrottling.rttMs);
|
|
65
|
+
expect(result).toEqual(SpeedIndex.COEFFICIENTS);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('should scale coefficients back', async () => {
|
|
69
|
+
const result = SpeedIndex.getScaledCoefficients(5);
|
|
70
|
+
expect(result).toEqual({intercept: 0, pessimistic: 0.5, optimistic: 0.5});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('should scale coefficients forward', async () => {
|
|
74
|
+
const result = SpeedIndex.getScaledCoefficients(300);
|
|
75
|
+
expect(result).toMatchInlineSnapshot(`
|
|
76
|
+
Object {
|
|
77
|
+
"intercept": 0,
|
|
78
|
+
"optimistic": 2.525,
|
|
79
|
+
"pessimistic": 0.275,
|
|
80
|
+
}
|
|
81
|
+
`);
|
|
82
|
+
});
|
|
83
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export type Node = import('../
|
|
2
|
-
/** @typedef {import('../
|
|
3
|
-
export class TotalBlockingTime extends Metric {
|
|
1
|
+
export type Node = import('../BaseNode.js').Node;
|
|
2
|
+
/** @typedef {import('../BaseNode.js').Node} Node */
|
|
3
|
+
export class TotalBlockingTime extends Lantern.Metric {
|
|
4
4
|
/**
|
|
5
5
|
* @param {Node} dependencyGraph
|
|
6
6
|
* @return {Node}
|
|
@@ -21,6 +21,5 @@ export class TotalBlockingTime extends Metric {
|
|
|
21
21
|
duration: number;
|
|
22
22
|
}[];
|
|
23
23
|
}
|
|
24
|
-
import
|
|
25
|
-
|
|
26
|
-
//# sourceMappingURL=total-blocking-time.d.ts.map
|
|
24
|
+
import * as Lantern from '../lantern.js';
|
|
25
|
+
//# sourceMappingURL=TotalBlockingTime.d.ts.map
|
|
@@ -4,14 +4,11 @@
|
|
|
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 {BLOCKING_TIME_THRESHOLD, calculateSumOfBlockingTime} from '../tbt-utils.js';
|
|
7
|
+
import * as Lantern from '../lantern.js';
|
|
11
8
|
|
|
12
|
-
/** @typedef {import('../
|
|
9
|
+
/** @typedef {import('../BaseNode.js').Node} Node */
|
|
13
10
|
|
|
14
|
-
class TotalBlockingTime extends Metric {
|
|
11
|
+
class TotalBlockingTime extends Lantern.Metric {
|
|
15
12
|
/**
|
|
16
13
|
* @return {Lantern.Simulation.MetricCoefficients}
|
|
17
14
|
*/
|
|
@@ -41,7 +38,7 @@ class TotalBlockingTime extends Metric {
|
|
|
41
38
|
|
|
42
39
|
/**
|
|
43
40
|
* @param {Lantern.Simulation.Result} simulation
|
|
44
|
-
* @param {import('../
|
|
41
|
+
* @param {import('../Metric.js').Extras} extras
|
|
45
42
|
* @return {Lantern.Simulation.Result}
|
|
46
43
|
*/
|
|
47
44
|
static getEstimateFromSimulation(simulation, extras) {
|
|
@@ -64,7 +61,7 @@ class TotalBlockingTime extends Metric {
|
|
|
64
61
|
? extras.interactiveResult.optimisticEstimate.timeInMs
|
|
65
62
|
: extras.interactiveResult.pessimisticEstimate.timeInMs;
|
|
66
63
|
|
|
67
|
-
const minDurationMs = BLOCKING_TIME_THRESHOLD;
|
|
64
|
+
const minDurationMs = Lantern.TBTUtils.BLOCKING_TIME_THRESHOLD;
|
|
68
65
|
|
|
69
66
|
const events = TotalBlockingTime.getTopLevelEvents(
|
|
70
67
|
simulation.nodeTimings,
|
|
@@ -72,7 +69,7 @@ class TotalBlockingTime extends Metric {
|
|
|
72
69
|
);
|
|
73
70
|
|
|
74
71
|
return {
|
|
75
|
-
timeInMs: calculateSumOfBlockingTime(
|
|
72
|
+
timeInMs: Lantern.TBTUtils.calculateSumOfBlockingTime(
|
|
76
73
|
events,
|
|
77
74
|
fcpTimeInMs,
|
|
78
75
|
interactiveTimeMs
|
|
@@ -83,8 +80,8 @@ class TotalBlockingTime extends Metric {
|
|
|
83
80
|
|
|
84
81
|
/**
|
|
85
82
|
* @param {Lantern.Simulation.MetricComputationDataInput} data
|
|
86
|
-
* @param {Omit<import('../
|
|
87
|
-
* @return {Promise<Lantern.
|
|
83
|
+
* @param {Omit<import('../Metric.js').Extras, 'optimistic'>=} extras
|
|
84
|
+
* @return {Promise<Lantern.Metrics.Result>}
|
|
88
85
|
*/
|
|
89
86
|
static async compute(data, extras) {
|
|
90
87
|
const fcpResult = extras?.fcpResult;
|
|
@@ -110,7 +107,7 @@ class TotalBlockingTime extends Metric {
|
|
|
110
107
|
const events = [];
|
|
111
108
|
|
|
112
109
|
for (const [node, timing] of nodeTimings.entries()) {
|
|
113
|
-
if (node.type !== BaseNode.TYPES.CPU) continue;
|
|
110
|
+
if (node.type !== Lantern.BaseNode.TYPES.CPU) continue;
|
|
114
111
|
// Filtering out events below minimum duration.
|
|
115
112
|
if (timing.duration < minDurationMs) continue;
|
|
116
113
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`Metrics: Lantern FCP should compute predicted value 1`] = `
|
|
4
|
+
Object {
|
|
5
|
+
"optimistic": 1107,
|
|
6
|
+
"optimisticNodeTimings": 4,
|
|
7
|
+
"pessimistic": 1107,
|
|
8
|
+
"pessimisticNodeTimings": 4,
|
|
9
|
+
"timing": 1107,
|
|
10
|
+
}
|
|
11
|
+
`;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`Metrics: Lantern TTI should compute predicted value 1`] = `
|
|
4
|
+
Object {
|
|
5
|
+
"optimistic": 1107,
|
|
6
|
+
"pessimistic": 1134,
|
|
7
|
+
"timing": 1122,
|
|
8
|
+
}
|
|
9
|
+
`;
|
|
10
|
+
|
|
11
|
+
exports[`Metrics: Lantern TTI should compute predicted value on iframes with substantial layout 1`] = `
|
|
12
|
+
Object {
|
|
13
|
+
"optimistic": 2372,
|
|
14
|
+
"pessimistic": 2386,
|
|
15
|
+
"timing": 2379,
|
|
16
|
+
}
|
|
17
|
+
`;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { FirstContentfulPaint } from "./FirstContentfulPaint.js";
|
|
2
|
+
export { Interactive } from "./Interactive.js";
|
|
3
|
+
export { LargestContentfulPaint } from "./LargestContentfulPaint.js";
|
|
4
|
+
export { MaxPotentialFID } from "./MaxPotentialFID.js";
|
|
5
|
+
export { SpeedIndex } from "./SpeedIndex.js";
|
|
6
|
+
export { TotalBlockingTime } from "./TotalBlockingTime.js";
|
|
7
|
+
export type Result<T = any> = Lantern.MetricResult<T>;
|
|
8
|
+
import * as Lantern from '../types/lantern.js';
|
|
9
|
+
//# sourceMappingURL=metrics.d.ts.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2024 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import * as Lantern from '../types/lantern.js';
|
|
8
|
+
|
|
9
|
+
export {FirstContentfulPaint} from './FirstContentfulPaint.js';
|
|
10
|
+
export {Interactive} from './Interactive.js';
|
|
11
|
+
export {LargestContentfulPaint} from './LargestContentfulPaint.js';
|
|
12
|
+
export {MaxPotentialFID} from './MaxPotentialFID.js';
|
|
13
|
+
export {SpeedIndex} from './SpeedIndex.js';
|
|
14
|
+
export {TotalBlockingTime} from './TotalBlockingTime.js';
|
|
15
|
+
|
|
16
|
+
/** @template [T=any] @typedef {Lantern.MetricResult<T>} Result */
|
|
@@ -4,7 +4,7 @@ export class ConnectionPool {
|
|
|
4
4
|
* @param {Required<Lantern.Simulation.Options>} options
|
|
5
5
|
*/
|
|
6
6
|
constructor(records: Lantern.NetworkRequest[], options: Required<Lantern.Simulation.Options>);
|
|
7
|
-
_options: Required<
|
|
7
|
+
_options: Required<import("../types/lantern.js").Simulation.Options>;
|
|
8
8
|
_records: Lantern.NetworkRequest<any>[];
|
|
9
9
|
/** @type {Map<string, TcpConnection[]>} */
|
|
10
10
|
_connectionsByOrigin: Map<string, TcpConnection[]>;
|
|
@@ -20,7 +20,7 @@ export class ConnectionPool {
|
|
|
20
20
|
/**
|
|
21
21
|
* @param {Array<TcpConnection>} connections
|
|
22
22
|
*/
|
|
23
|
-
_findAvailableConnectionWithLargestCongestionWindow(connections: Array<TcpConnection>): TcpConnection | null;
|
|
23
|
+
_findAvailableConnectionWithLargestCongestionWindow(connections: Array<TcpConnection>): Lantern.Simulation.TcpConnection | null;
|
|
24
24
|
/**
|
|
25
25
|
* This method finds an available connection to the origin specified by the network request or null
|
|
26
26
|
* if no connection was available. If returned, connection will not be available for other network
|
|
@@ -43,6 +43,6 @@ export class ConnectionPool {
|
|
|
43
43
|
*/
|
|
44
44
|
release(request: Lantern.NetworkRequest): void;
|
|
45
45
|
}
|
|
46
|
-
import * as Lantern from '../
|
|
47
|
-
import { TcpConnection } from './
|
|
48
|
-
//# sourceMappingURL=
|
|
46
|
+
import * as Lantern from '../lantern.js';
|
|
47
|
+
import { TcpConnection } from './TcpConnection.js';
|
|
48
|
+
//# sourceMappingURL=ConnectionPool.d.ts.map
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import * as Lantern from '../
|
|
8
|
-
import {NetworkAnalyzer} from './
|
|
9
|
-
import {TcpConnection} from './
|
|
7
|
+
import * as Lantern from '../lantern.js';
|
|
8
|
+
import {NetworkAnalyzer} from './NetworkAnalyzer.js';
|
|
9
|
+
import {TcpConnection} from './TcpConnection.js';
|
|
10
10
|
|
|
11
11
|
const DEFAULT_SERVER_RESPONSE_TIME = 30;
|
|
12
12
|
const TLS_SCHEMES = ['https', 'wss'];
|