lighthouse 11.6.0-dev.20240306 → 11.6.0-dev.20240307

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.
Files changed (37) hide show
  1. package/core/computed/load-simulator.d.ts +0 -2
  2. package/core/computed/load-simulator.js +2 -3
  3. package/core/computed/metrics/lantern-first-contentful-paint.d.ts +12 -0
  4. package/core/computed/metrics/lantern-first-meaningful-paint.d.ts +12 -0
  5. package/core/computed/metrics/lantern-interactive.d.ts +6 -0
  6. package/core/computed/metrics/lantern-interactive.js +1 -1
  7. package/core/computed/metrics/lantern-largest-contentful-paint.d.ts +12 -0
  8. package/core/computed/metrics/lantern-max-potential-fid.d.ts +6 -0
  9. package/core/computed/metrics/lantern-max-potential-fid.js +1 -1
  10. package/core/computed/metrics/lantern-metric.d.ts +4 -64
  11. package/core/computed/metrics/lantern-metric.js +6 -124
  12. package/core/computed/metrics/lantern-speed-index.d.ts +6 -0
  13. package/core/computed/metrics/lantern-speed-index.js +1 -1
  14. package/core/computed/metrics/lantern-total-blocking-time.d.ts +6 -0
  15. package/core/computed/metrics/lantern-total-blocking-time.js +1 -1
  16. package/core/lib/lantern/metric.d.ts +71 -0
  17. package/core/lib/lantern/metric.js +143 -0
  18. package/core/lib/lantern/network-node.d.ts +5 -5
  19. package/core/lib/lantern/network-node.js +3 -4
  20. package/core/lib/lantern/page-dependency-graph.d.ts +7 -7
  21. package/core/lib/lantern/page-dependency-graph.js +4 -4
  22. package/core/lib/lantern/simulator/connection-pool.d.ts +14 -15
  23. package/core/lib/lantern/simulator/connection-pool.js +7 -9
  24. package/core/lib/lantern/simulator/dns-cache.d.ts +5 -11
  25. package/core/lib/lantern/simulator/dns-cache.js +3 -3
  26. package/core/lib/lantern/simulator/network-analyzer.d.ts +30 -30
  27. package/core/lib/lantern/simulator/network-analyzer.js +14 -15
  28. package/core/lib/lantern/simulator/simulator.d.ts +13 -16
  29. package/core/lib/lantern/simulator/simulator.js +10 -16
  30. package/core/lib/lantern/types/lantern.d.ts +129 -0
  31. package/core/lib/lantern/types/lantern.js +7 -0
  32. package/core/lib/network-request.d.ts +3 -4
  33. package/core/lib/network-request.js +2 -3
  34. package/package.json +1 -1
  35. package/tsconfig.json +1 -0
  36. package/types/gatherer.d.ts +1 -1
  37. package/types/internal/lantern.d.ts +0 -124
@@ -1,5 +1,4 @@
1
1
  export { LoadSimulatorComputed as LoadSimulator };
2
- export type SimulationOptions = import('../../types/internal/lantern.js').Lantern.Simulation.Options;
3
2
  declare const LoadSimulatorComputed: typeof LoadSimulator & {
4
3
  request: (dependencies: {
5
4
  devtoolsLog: import("../index.js").DevtoolsLog;
@@ -8,7 +7,6 @@ declare const LoadSimulatorComputed: typeof LoadSimulator & {
8
7
  computedCache: Map<string, import("../lib/arbitrary-equality-map.js").ArbitraryEqualityMap>;
9
8
  }>) => Promise<Simulator<any>>;
10
9
  };
11
- /** @typedef {import('../../types/internal/lantern.js').Lantern.Simulation.Options} SimulationOptions */
12
10
  declare class LoadSimulator {
13
11
  /**
14
12
  * @param {{devtoolsLog: LH.DevtoolsLog, settings: LH.Audit.Context['settings']}} data
@@ -4,13 +4,12 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
+ import * as Lantern from '../lib/lantern/types/lantern.js';
7
8
  import {makeComputedArtifact} from './computed-artifact.js';
8
9
  import * as constants from '../config/constants.js';
9
10
  import {Simulator} from '../lib/lantern/simulator/simulator.js';
10
11
  import {NetworkAnalysis} from './network-analysis.js';
11
12
 
12
- /** @typedef {import('../../types/internal/lantern.js').Lantern.Simulation.Options} SimulationOptions */
13
-
14
13
  class LoadSimulator {
15
14
  /**
16
15
  * @param {{devtoolsLog: LH.DevtoolsLog, settings: LH.Audit.Context['settings']}} data
@@ -21,7 +20,7 @@ class LoadSimulator {
21
20
  const {throttlingMethod, throttling, precomputedLanternData} = data.settings;
22
21
  const networkAnalysis = await NetworkAnalysis.request(data.devtoolsLog, context);
23
22
 
24
- /** @type {SimulationOptions} */
23
+ /** @type {Lantern.Simulation.Options} */
25
24
  const options = {
26
25
  additionalRttByOrigin: networkAnalysis.additionalRttByOrigin,
27
26
  serverResponseTimeByOrigin: networkAnalysis.serverResponseTimeByOrigin,
@@ -77,6 +77,18 @@ declare class LanternFirstContentfulPaint extends LanternMetric {
77
77
  */
78
78
  additionalCpuNodesToTreatAsRenderBlocking?: ((arg0: CPUNode) => boolean) | undefined;
79
79
  }): Node;
80
+ /**
81
+ * @param {Node} dependencyGraph
82
+ * @param {LH.Artifacts.ProcessedNavigation} processedNavigation
83
+ * @return {Node}
84
+ */
85
+ static getOptimisticGraph(dependencyGraph: Node, processedNavigation: LH.Artifacts.ProcessedNavigation): Node;
86
+ /**
87
+ * @param {Node} dependencyGraph
88
+ * @param {LH.Artifacts.ProcessedNavigation} processedNavigation
89
+ * @return {Node}
90
+ */
91
+ static getPessimisticGraph(dependencyGraph: Node, processedNavigation: LH.Artifacts.ProcessedNavigation): Node;
80
92
  }
81
93
  import { LanternMetric } from './lantern-metric.js';
82
94
  //# sourceMappingURL=lantern-first-contentful-paint.d.ts.map
@@ -7,6 +7,18 @@ declare const LanternFirstMeaningfulPaintComputed: typeof LanternFirstMeaningful
7
7
  };
8
8
  /** @typedef {import('../../lib/lantern/base-node.js').Node<LH.Artifacts.NetworkRequest>} Node */
9
9
  declare class LanternFirstMeaningfulPaint extends LanternMetric {
10
+ /**
11
+ * @param {Node} dependencyGraph
12
+ * @param {LH.Artifacts.ProcessedNavigation} processedNavigation
13
+ * @return {Node}
14
+ */
15
+ static getOptimisticGraph(dependencyGraph: Node, processedNavigation: LH.Artifacts.ProcessedNavigation): Node;
16
+ /**
17
+ * @param {Node} dependencyGraph
18
+ * @param {LH.Artifacts.ProcessedNavigation} processedNavigation
19
+ * @return {Node}
20
+ */
21
+ static getPessimisticGraph(dependencyGraph: Node, processedNavigation: LH.Artifacts.ProcessedNavigation): Node;
10
22
  }
11
23
  import { LanternMetric } from './lantern-metric.js';
12
24
  //# sourceMappingURL=lantern-first-meaningful-paint.d.ts.map
@@ -17,6 +17,12 @@ declare class LanternInteractive extends LanternMetric {
17
17
  * @return {Node}
18
18
  */
19
19
  static getPessimisticGraph(dependencyGraph: Node): Node;
20
+ /**
21
+ * @param {LH.Gatherer.Simulation.Result} simulationResult
22
+ * @param {import('../../lib/lantern/metric.js').Extras} extras
23
+ * @return {LH.Gatherer.Simulation.Result}
24
+ */
25
+ static getEstimateFromSimulation(simulationResult: LH.Gatherer.Simulation.Result, extras: import('../../lib/lantern/metric.js').Extras): LH.Gatherer.Simulation.Result;
20
26
  /**
21
27
  * @param {LH.Gatherer.Simulation.Result['nodeTimings']} nodeTimings
22
28
  * @return {number}
@@ -63,7 +63,7 @@ class LanternInteractive extends LanternMetric {
63
63
 
64
64
  /**
65
65
  * @param {LH.Gatherer.Simulation.Result} simulationResult
66
- * @param {import('./lantern-metric.js').Extras} extras
66
+ * @param {import('../../lib/lantern/metric.js').Extras} extras
67
67
  * @return {LH.Gatherer.Simulation.Result}
68
68
  */
69
69
  static getEstimateFromSimulation(simulationResult, extras) {
@@ -15,6 +15,18 @@ declare class LanternLargestContentfulPaint extends LanternMetric {
15
15
  * @return {boolean}
16
16
  */
17
17
  static isNotLowPriorityImageNode(node: Node): boolean;
18
+ /**
19
+ * @param {Node} dependencyGraph
20
+ * @param {LH.Artifacts.ProcessedNavigation} processedNavigation
21
+ * @return {Node}
22
+ */
23
+ static getOptimisticGraph(dependencyGraph: Node, processedNavigation: LH.Artifacts.ProcessedNavigation): Node;
24
+ /**
25
+ * @param {Node} dependencyGraph
26
+ * @param {LH.Artifacts.ProcessedNavigation} processedNavigation
27
+ * @return {Node}
28
+ */
29
+ static getPessimisticGraph(dependencyGraph: Node, processedNavigation: LH.Artifacts.ProcessedNavigation): Node;
18
30
  /**
19
31
  * @param {LH.Gatherer.Simulation.Result} simulationResult
20
32
  * @return {LH.Gatherer.Simulation.Result}
@@ -17,6 +17,12 @@ declare class LanternMaxPotentialFID extends LanternMetric {
17
17
  * @return {Node}
18
18
  */
19
19
  static getPessimisticGraph(dependencyGraph: Node): Node;
20
+ /**
21
+ * @param {LH.Gatherer.Simulation.Result} simulation
22
+ * @param {import('../../lib/lantern/metric.js').Extras} extras
23
+ * @return {LH.Gatherer.Simulation.Result}
24
+ */
25
+ static getEstimateFromSimulation(simulation: LH.Gatherer.Simulation.Result, extras: import('../../lib/lantern/metric.js').Extras): LH.Gatherer.Simulation.Result;
20
26
  /**
21
27
  * @param {LH.Gatherer.Simulation.Result['nodeTimings']} nodeTimings
22
28
  * @param {number} fcpTimeInMs
@@ -41,7 +41,7 @@ class LanternMaxPotentialFID extends LanternMetric {
41
41
 
42
42
  /**
43
43
  * @param {LH.Gatherer.Simulation.Result} simulation
44
- * @param {import('./lantern-metric.js').Extras} extras
44
+ * @param {import('../../lib/lantern/metric.js').Extras} extras
45
45
  * @return {LH.Gatherer.Simulation.Result}
46
46
  */
47
47
  static getEstimateFromSimulation(simulation, extras) {
@@ -1,65 +1,6 @@
1
- export type Node = import('../../lib/lantern/base-node.js').Node<LH.Artifacts.NetworkRequest>;
2
- export type NetworkNode = import('../../lib/lantern/network-node.js').NetworkNode<LH.Artifacts.NetworkRequest>;
3
- export type Simulator = import('../../lib/lantern/simulator/simulator.js').Simulator;
4
- export type Extras = {
5
- optimistic: boolean;
6
- fcpResult?: LH.Artifacts.LanternMetric | undefined;
7
- fmpResult?: LH.Artifacts.LanternMetric | undefined;
8
- interactiveResult?: LH.Artifacts.LanternMetric | undefined;
9
- speedline?: {
10
- speedIndex: number;
11
- } | undefined;
12
- };
13
- /** @typedef {import('../../lib/lantern/base-node.js').Node<LH.Artifacts.NetworkRequest>} Node */
14
- /** @typedef {import('../../lib/lantern/network-node.js').NetworkNode<LH.Artifacts.NetworkRequest>} NetworkNode */
15
- /** @typedef {import('../../lib/lantern/simulator/simulator.js').Simulator} Simulator */
16
- /**
17
- * @typedef Extras
18
- * @property {boolean} optimistic
19
- * @property {LH.Artifacts.LanternMetric=} fcpResult
20
- * @property {LH.Artifacts.LanternMetric=} fmpResult
21
- * @property {LH.Artifacts.LanternMetric=} interactiveResult
22
- * @property {{speedIndex: number}=} speedline
23
- */
24
- export class LanternMetric {
25
- /**
26
- * @param {Node} dependencyGraph
27
- * @param {function(NetworkNode):boolean=} treatNodeAsRenderBlocking
28
- * @return {Set<string>}
29
- */
30
- static getScriptUrls(dependencyGraph: Node, treatNodeAsRenderBlocking?: ((arg0: NetworkNode) => boolean) | undefined): Set<string>;
31
- /**
32
- * @return {LH.Gatherer.Simulation.MetricCoefficients}
33
- */
34
- static get COEFFICIENTS(): import("../../../types/internal/lantern.js").Lantern.Simulation.MetricCoefficients;
35
- /**
36
- * Returns the coefficients, scaled by the throttling settings if needed by the metric.
37
- * Some lantern metrics (speed-index) use components in their estimate that are not
38
- * from the simulator. In this case, we need to adjust the coefficients as the target throttling
39
- * settings change.
40
- *
41
- * @param {number} rttMs
42
- * @return {LH.Gatherer.Simulation.MetricCoefficients}
43
- */
44
- static getScaledCoefficients(rttMs: number): LH.Gatherer.Simulation.MetricCoefficients;
45
- /**
46
- * @param {Node} dependencyGraph
47
- * @param {LH.Artifacts.ProcessedNavigation} processedNavigation
48
- * @return {Node}
49
- */
50
- static getOptimisticGraph(dependencyGraph: Node, processedNavigation: LH.Artifacts.ProcessedNavigation): Node;
51
- /**
52
- * @param {Node} dependencyGraph
53
- * @param {LH.Artifacts.ProcessedNavigation} processedNavigation
54
- * @return {Node}
55
- */
56
- static getPessimisticGraph(dependencyGraph: Node, processedNavigation: LH.Artifacts.ProcessedNavigation): Node;
57
- /**
58
- * @param {LH.Gatherer.Simulation.Result} simulationResult
59
- * @param {Extras} extras
60
- * @return {LH.Gatherer.Simulation.Result}
61
- */
62
- static getEstimateFromSimulation(simulationResult: LH.Gatherer.Simulation.Result, extras: Extras): LH.Gatherer.Simulation.Result;
1
+ export type Extras = import('../../lib/lantern/metric.js').Extras;
2
+ /** @typedef {import('../../lib/lantern/metric.js').Extras} Extras */
3
+ export class LanternMetric extends Metric {
63
4
  /**
64
5
  * @param {LH.Artifacts.MetricComputationDataInput} data
65
6
  * @param {LH.Artifacts.ComputedContext} context
@@ -74,6 +15,5 @@ export class LanternMetric {
74
15
  */
75
16
  static compute_(data: LH.Artifacts.MetricComputationDataInput, context: LH.Artifacts.ComputedContext): Promise<LH.Artifacts.LanternMetric>;
76
17
  }
77
- import { NetworkRequest } from '../../lib/network-request.js';
78
- import { ProcessedNavigation } from '../processed-navigation.js';
18
+ import { Metric } from '../../lib/lantern/metric.js';
79
19
  //# sourceMappingURL=lantern-metric.d.ts.map
@@ -4,93 +4,14 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- import {BaseNode} from '../../lib/lantern/base-node.js';
8
- import {NetworkRequest} from '../../lib/network-request.js';
9
- import {ProcessedNavigation} from '../processed-navigation.js';
10
- import {PageDependencyGraph} from '../page-dependency-graph.js';
7
+ import {Metric} from '../../lib/lantern/metric.js';
11
8
  import {LoadSimulator} from '../load-simulator.js';
9
+ import {PageDependencyGraph} from '../page-dependency-graph.js';
10
+ import {ProcessedNavigation} from '../processed-navigation.js';
12
11
 
13
- /** @typedef {import('../../lib/lantern/base-node.js').Node<LH.Artifacts.NetworkRequest>} Node */
14
- /** @typedef {import('../../lib/lantern/network-node.js').NetworkNode<LH.Artifacts.NetworkRequest>} NetworkNode */
15
- /** @typedef {import('../../lib/lantern/simulator/simulator.js').Simulator} Simulator */
16
-
17
- /**
18
- * @typedef Extras
19
- * @property {boolean} optimistic
20
- * @property {LH.Artifacts.LanternMetric=} fcpResult
21
- * @property {LH.Artifacts.LanternMetric=} fmpResult
22
- * @property {LH.Artifacts.LanternMetric=} interactiveResult
23
- * @property {{speedIndex: number}=} speedline
24
- */
25
-
26
- class LanternMetric {
27
- /**
28
- * @param {Node} dependencyGraph
29
- * @param {function(NetworkNode):boolean=} treatNodeAsRenderBlocking
30
- * @return {Set<string>}
31
- */
32
- static getScriptUrls(dependencyGraph, treatNodeAsRenderBlocking) {
33
- /** @type {Set<string>} */
34
- const scriptUrls = new Set();
35
-
36
- dependencyGraph.traverse(node => {
37
- if (node.type !== BaseNode.TYPES.NETWORK) return;
38
- if (node.record.resourceType !== NetworkRequest.TYPES.Script) return;
39
- if (treatNodeAsRenderBlocking?.(node)) {
40
- scriptUrls.add(node.record.url);
41
- }
42
- });
43
-
44
- return scriptUrls;
45
- }
46
-
47
- /**
48
- * @return {LH.Gatherer.Simulation.MetricCoefficients}
49
- */
50
- static get COEFFICIENTS() {
51
- throw new Error('COEFFICIENTS unimplemented!');
52
- }
53
-
54
- /**
55
- * Returns the coefficients, scaled by the throttling settings if needed by the metric.
56
- * Some lantern metrics (speed-index) use components in their estimate that are not
57
- * from the simulator. In this case, we need to adjust the coefficients as the target throttling
58
- * settings change.
59
- *
60
- * @param {number} rttMs
61
- * @return {LH.Gatherer.Simulation.MetricCoefficients}
62
- */
63
- static getScaledCoefficients(rttMs) { // eslint-disable-line no-unused-vars
64
- return this.COEFFICIENTS;
65
- }
66
-
67
- /**
68
- * @param {Node} dependencyGraph
69
- * @param {LH.Artifacts.ProcessedNavigation} processedNavigation
70
- * @return {Node}
71
- */
72
- static getOptimisticGraph(dependencyGraph, processedNavigation) { // eslint-disable-line no-unused-vars
73
- throw new Error('Optimistic graph unimplemented!');
74
- }
75
-
76
- /**
77
- * @param {Node} dependencyGraph
78
- * @param {LH.Artifacts.ProcessedNavigation} processedNavigation
79
- * @return {Node}
80
- */
81
- static getPessimisticGraph(dependencyGraph, processedNavigation) { // eslint-disable-line no-unused-vars
82
- throw new Error('Pessmistic graph unimplemented!');
83
- }
84
-
85
- /**
86
- * @param {LH.Gatherer.Simulation.Result} simulationResult
87
- * @param {Extras} extras
88
- * @return {LH.Gatherer.Simulation.Result}
89
- */
90
- static getEstimateFromSimulation(simulationResult, extras) { // eslint-disable-line no-unused-vars
91
- return simulationResult;
92
- }
12
+ /** @typedef {import('../../lib/lantern/metric.js').Extras} Extras */
93
13
 
14
+ class LanternMetric extends Metric {
94
15
  /**
95
16
  * @param {LH.Artifacts.MetricComputationDataInput} data
96
17
  * @param {LH.Artifacts.ComputedContext} context
@@ -104,50 +25,11 @@ class LanternMetric {
104
25
  throw new Error(`Lantern metrics can only be computed on navigations`);
105
26
  }
106
27
 
107
- const metricName = this.name.replace('Lantern', '');
108
28
  const graph = await PageDependencyGraph.request(data, context);
109
29
  const processedNavigation = await ProcessedNavigation.request(data.trace, context);
110
30
  const simulator = data.simulator || (await LoadSimulator.request(data, context));
111
31
 
112
- const optimisticGraph = this.getOptimisticGraph(graph, processedNavigation);
113
- const pessimisticGraph = this.getPessimisticGraph(graph, processedNavigation);
114
-
115
- /** @type {{flexibleOrdering?: boolean, label?: string}} */
116
- let simulateOptions = {label: `optimistic${metricName}`};
117
- const optimisticSimulation = simulator.simulate(optimisticGraph, simulateOptions);
118
-
119
- simulateOptions = {label: `optimisticFlex${metricName}`, flexibleOrdering: true};
120
- const optimisticFlexSimulation = simulator.simulate(optimisticGraph, simulateOptions);
121
-
122
- simulateOptions = {label: `pessimistic${metricName}`};
123
- const pessimisticSimulation = simulator.simulate(pessimisticGraph, simulateOptions);
124
-
125
- const optimisticEstimate = this.getEstimateFromSimulation(
126
- optimisticSimulation.timeInMs < optimisticFlexSimulation.timeInMs ?
127
- optimisticSimulation : optimisticFlexSimulation, {...extras, optimistic: true}
128
- );
129
-
130
- const pessimisticEstimate = this.getEstimateFromSimulation(
131
- pessimisticSimulation,
132
- {...extras, optimistic: false}
133
- );
134
-
135
- const coefficients = this.getScaledCoefficients(simulator.rtt);
136
- // Estimates under 1s don't really follow the normal curve fit, minimize the impact of the intercept
137
- const interceptMultiplier = coefficients.intercept > 0 ?
138
- Math.min(1, optimisticEstimate.timeInMs / 1000) : 1;
139
- const timing =
140
- coefficients.intercept * interceptMultiplier +
141
- coefficients.optimistic * optimisticEstimate.timeInMs +
142
- coefficients.pessimistic * pessimisticEstimate.timeInMs;
143
-
144
- return {
145
- timing,
146
- optimisticEstimate,
147
- pessimisticEstimate,
148
- optimisticGraph,
149
- pessimisticGraph,
150
- };
32
+ return this.compute({simulator, graph, processedNavigation}, extras);
151
33
  }
152
34
 
153
35
  /**
@@ -17,6 +17,12 @@ declare class LanternSpeedIndex extends LanternMetric {
17
17
  * @return {Node}
18
18
  */
19
19
  static getPessimisticGraph(dependencyGraph: Node): Node;
20
+ /**
21
+ * @param {LH.Gatherer.Simulation.Result} simulationResult
22
+ * @param {import('../../lib/lantern/metric.js').Extras} extras
23
+ * @return {LH.Gatherer.Simulation.Result}
24
+ */
25
+ static getEstimateFromSimulation(simulationResult: LH.Gatherer.Simulation.Result, extras: import('../../lib/lantern/metric.js').Extras): LH.Gatherer.Simulation.Result;
20
26
  /**
21
27
  * Approximate speed index using layout events from the simulated node timings.
22
28
  * The layout-based speed index is the weighted average of the endTime of CPU nodes that contained
@@ -73,7 +73,7 @@ class LanternSpeedIndex extends LanternMetric {
73
73
 
74
74
  /**
75
75
  * @param {LH.Gatherer.Simulation.Result} simulationResult
76
- * @param {import('./lantern-metric.js').Extras} extras
76
+ * @param {import('../../lib/lantern/metric.js').Extras} extras
77
77
  * @return {LH.Gatherer.Simulation.Result}
78
78
  */
79
79
  static getEstimateFromSimulation(simulationResult, extras) {
@@ -17,6 +17,12 @@ declare class LanternTotalBlockingTime extends LanternMetric {
17
17
  * @return {Node}
18
18
  */
19
19
  static getPessimisticGraph(dependencyGraph: Node): Node;
20
+ /**
21
+ * @param {LH.Gatherer.Simulation.Result} simulation
22
+ * @param {import('../../lib/lantern/metric.js').Extras} extras
23
+ * @return {LH.Gatherer.Simulation.Result}
24
+ */
25
+ static getEstimateFromSimulation(simulation: LH.Gatherer.Simulation.Result, extras: import('../../lib/lantern/metric.js').Extras): LH.Gatherer.Simulation.Result;
20
26
  /**
21
27
  * @param {LH.Gatherer.Simulation.Result['nodeTimings']} nodeTimings
22
28
  * @param {number} minDurationMs
@@ -43,7 +43,7 @@ class LanternTotalBlockingTime extends LanternMetric {
43
43
 
44
44
  /**
45
45
  * @param {LH.Gatherer.Simulation.Result} simulation
46
- * @param {import('./lantern-metric.js').Extras} extras
46
+ * @param {import('../../lib/lantern/metric.js').Extras} extras
47
47
  * @return {LH.Gatherer.Simulation.Result}
48
48
  */
49
49
  static getEstimateFromSimulation(simulation, extras) {
@@ -0,0 +1,71 @@
1
+ export type Node = import('./base-node.js').Node;
2
+ export type NetworkNode = import('./network-node.js').NetworkNode;
3
+ export type Simulator = import('./simulator/simulator.js').Simulator;
4
+ export type Extras = {
5
+ optimistic: boolean;
6
+ fcpResult?: LH.Artifacts.LanternMetric | undefined;
7
+ fmpResult?: LH.Artifacts.LanternMetric | undefined;
8
+ interactiveResult?: LH.Artifacts.LanternMetric | undefined;
9
+ speedline?: {
10
+ speedIndex: number;
11
+ } | undefined;
12
+ };
13
+ /** @typedef {import('./base-node.js').Node} Node */
14
+ /** @typedef {import('./network-node.js').NetworkNode} NetworkNode */
15
+ /** @typedef {import('./simulator/simulator.js').Simulator} Simulator */
16
+ /**
17
+ * @typedef Extras
18
+ * @property {boolean} optimistic
19
+ * @property {LH.Artifacts.LanternMetric=} fcpResult
20
+ * @property {LH.Artifacts.LanternMetric=} fmpResult
21
+ * @property {LH.Artifacts.LanternMetric=} interactiveResult
22
+ * @property {{speedIndex: number}=} speedline
23
+ */
24
+ export class Metric {
25
+ /**
26
+ * @param {Node} dependencyGraph
27
+ * @param {function(NetworkNode):boolean=} treatNodeAsRenderBlocking
28
+ * @return {Set<string>}
29
+ */
30
+ static getScriptUrls(dependencyGraph: Node, treatNodeAsRenderBlocking?: ((arg0: NetworkNode) => boolean) | undefined): Set<string>;
31
+ /**
32
+ * @return {Lantern.Simulation.MetricCoefficients}
33
+ */
34
+ static get COEFFICIENTS(): Lantern.Simulation.MetricCoefficients;
35
+ /**
36
+ * Returns the coefficients, scaled by the throttling settings if needed by the metric.
37
+ * Some lantern metrics (speed-index) use components in their estimate that are not
38
+ * from the simulator. In this case, we need to adjust the coefficients as the target throttling
39
+ * settings change.
40
+ *
41
+ * @param {number} rttMs
42
+ * @return {Lantern.Simulation.MetricCoefficients}
43
+ */
44
+ static getScaledCoefficients(rttMs: number): Lantern.Simulation.MetricCoefficients;
45
+ /**
46
+ * @param {Node} dependencyGraph
47
+ * @param {LH.Artifacts.ProcessedNavigation} processedNavigation
48
+ * @return {Node}
49
+ */
50
+ static getOptimisticGraph(dependencyGraph: Node, processedNavigation: LH.Artifacts.ProcessedNavigation): Node;
51
+ /**
52
+ * @param {Node} dependencyGraph
53
+ * @param {LH.Artifacts.ProcessedNavigation} processedNavigation
54
+ * @return {Node}
55
+ */
56
+ static getPessimisticGraph(dependencyGraph: Node, processedNavigation: LH.Artifacts.ProcessedNavigation): Node;
57
+ /**
58
+ * @param {Lantern.Simulation.Result} simulationResult
59
+ * @param {Extras} extras
60
+ * @return {Lantern.Simulation.Result}
61
+ */
62
+ static getEstimateFromSimulation(simulationResult: Lantern.Simulation.Result, extras: Extras): Lantern.Simulation.Result;
63
+ /**
64
+ * @param {Lantern.Simulation.MetricComputationDataInput} data
65
+ * @param {Omit<Extras, 'optimistic'>=} extras
66
+ * @return {Promise<LH.Artifacts.LanternMetric>}
67
+ */
68
+ static compute(data: Lantern.Simulation.MetricComputationDataInput, extras?: Omit<Extras, 'optimistic'> | undefined): Promise<LH.Artifacts.LanternMetric>;
69
+ }
70
+ import * as Lantern from './types/lantern.js';
71
+ //# sourceMappingURL=metric.d.ts.map
@@ -0,0 +1,143 @@
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
+ import {BaseNode} from '../../lib/lantern/base-node.js';
9
+ import {NetworkRequest} from '../../lib/network-request.js';
10
+
11
+ /** @typedef {import('./base-node.js').Node} Node */
12
+ /** @typedef {import('./network-node.js').NetworkNode} NetworkNode */
13
+ /** @typedef {import('./simulator/simulator.js').Simulator} Simulator */
14
+
15
+ /**
16
+ * @typedef Extras
17
+ * @property {boolean} optimistic
18
+ * @property {LH.Artifacts.LanternMetric=} fcpResult
19
+ * @property {LH.Artifacts.LanternMetric=} fmpResult
20
+ * @property {LH.Artifacts.LanternMetric=} interactiveResult
21
+ * @property {{speedIndex: number}=} speedline
22
+ */
23
+
24
+ class Metric {
25
+ /**
26
+ * @param {Node} dependencyGraph
27
+ * @param {function(NetworkNode):boolean=} treatNodeAsRenderBlocking
28
+ * @return {Set<string>}
29
+ */
30
+ static getScriptUrls(dependencyGraph, treatNodeAsRenderBlocking) {
31
+ /** @type {Set<string>} */
32
+ const scriptUrls = new Set();
33
+
34
+ dependencyGraph.traverse(node => {
35
+ if (node.type !== BaseNode.TYPES.NETWORK) return;
36
+ if (node.record.resourceType !== NetworkRequest.TYPES.Script) return;
37
+ if (treatNodeAsRenderBlocking?.(node)) {
38
+ scriptUrls.add(node.record.url);
39
+ }
40
+ });
41
+
42
+ return scriptUrls;
43
+ }
44
+
45
+ /**
46
+ * @return {Lantern.Simulation.MetricCoefficients}
47
+ */
48
+ static get COEFFICIENTS() {
49
+ throw new Error('COEFFICIENTS unimplemented!');
50
+ }
51
+
52
+ /**
53
+ * Returns the coefficients, scaled by the throttling settings if needed by the metric.
54
+ * Some lantern metrics (speed-index) use components in their estimate that are not
55
+ * from the simulator. In this case, we need to adjust the coefficients as the target throttling
56
+ * settings change.
57
+ *
58
+ * @param {number} rttMs
59
+ * @return {Lantern.Simulation.MetricCoefficients}
60
+ */
61
+ static getScaledCoefficients(rttMs) { // eslint-disable-line no-unused-vars
62
+ return this.COEFFICIENTS;
63
+ }
64
+
65
+ /**
66
+ * @param {Node} dependencyGraph
67
+ * @param {LH.Artifacts.ProcessedNavigation} processedNavigation
68
+ * @return {Node}
69
+ */
70
+ static getOptimisticGraph(dependencyGraph, processedNavigation) { // eslint-disable-line no-unused-vars
71
+ throw new Error('Optimistic graph unimplemented!');
72
+ }
73
+
74
+ /**
75
+ * @param {Node} dependencyGraph
76
+ * @param {LH.Artifacts.ProcessedNavigation} processedNavigation
77
+ * @return {Node}
78
+ */
79
+ static getPessimisticGraph(dependencyGraph, processedNavigation) { // eslint-disable-line no-unused-vars
80
+ throw new Error('Pessmistic graph unimplemented!');
81
+ }
82
+
83
+ /**
84
+ * @param {Lantern.Simulation.Result} simulationResult
85
+ * @param {Extras} extras
86
+ * @return {Lantern.Simulation.Result}
87
+ */
88
+ static getEstimateFromSimulation(simulationResult, extras) { // eslint-disable-line no-unused-vars
89
+ return simulationResult;
90
+ }
91
+
92
+ /**
93
+ * @param {Lantern.Simulation.MetricComputationDataInput} data
94
+ * @param {Omit<Extras, 'optimistic'>=} extras
95
+ * @return {Promise<LH.Artifacts.LanternMetric>}
96
+ */
97
+ static async compute(data, extras) {
98
+ const {simulator, graph, processedNavigation} = data;
99
+
100
+ const metricName = this.name.replace('Lantern', '');
101
+ const optimisticGraph = this.getOptimisticGraph(graph, processedNavigation);
102
+ const pessimisticGraph = this.getPessimisticGraph(graph, processedNavigation);
103
+
104
+ /** @type {{flexibleOrdering?: boolean, label?: string}} */
105
+ let simulateOptions = {label: `optimistic${metricName}`};
106
+ const optimisticSimulation = simulator.simulate(optimisticGraph, simulateOptions);
107
+
108
+ simulateOptions = {label: `optimisticFlex${metricName}`, flexibleOrdering: true};
109
+ const optimisticFlexSimulation = simulator.simulate(optimisticGraph, simulateOptions);
110
+
111
+ simulateOptions = {label: `pessimistic${metricName}`};
112
+ const pessimisticSimulation = simulator.simulate(pessimisticGraph, simulateOptions);
113
+
114
+ const optimisticEstimate = this.getEstimateFromSimulation(
115
+ optimisticSimulation.timeInMs < optimisticFlexSimulation.timeInMs ?
116
+ optimisticSimulation : optimisticFlexSimulation, {...extras, optimistic: true}
117
+ );
118
+
119
+ const pessimisticEstimate = this.getEstimateFromSimulation(
120
+ pessimisticSimulation,
121
+ {...extras, optimistic: false}
122
+ );
123
+
124
+ const coefficients = this.getScaledCoefficients(simulator.rtt);
125
+ // Estimates under 1s don't really follow the normal curve fit, minimize the impact of the intercept
126
+ const interceptMultiplier = coefficients.intercept > 0 ?
127
+ Math.min(1, optimisticEstimate.timeInMs / 1000) : 1;
128
+ const timing =
129
+ coefficients.intercept * interceptMultiplier +
130
+ coefficients.optimistic * optimisticEstimate.timeInMs +
131
+ coefficients.pessimistic * pessimisticEstimate.timeInMs;
132
+
133
+ return {
134
+ timing,
135
+ optimisticEstimate,
136
+ pessimisticEstimate,
137
+ optimisticGraph,
138
+ pessimisticGraph,
139
+ };
140
+ }
141
+ }
142
+
143
+ export {Metric};