lighthouse 11.6.0-dev.20240306 → 11.6.0-dev.20240308

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 (41) hide show
  1. package/cli/test/smokehouse/core-tests.js +2 -0
  2. package/core/computed/load-simulator.d.ts +0 -2
  3. package/core/computed/load-simulator.js +2 -3
  4. package/core/computed/metrics/lantern-first-contentful-paint.d.ts +12 -0
  5. package/core/computed/metrics/lantern-first-meaningful-paint.d.ts +12 -0
  6. package/core/computed/metrics/lantern-interactive.d.ts +6 -0
  7. package/core/computed/metrics/lantern-interactive.js +1 -1
  8. package/core/computed/metrics/lantern-largest-contentful-paint.d.ts +12 -0
  9. package/core/computed/metrics/lantern-max-potential-fid.d.ts +6 -0
  10. package/core/computed/metrics/lantern-max-potential-fid.js +1 -1
  11. package/core/computed/metrics/lantern-metric.d.ts +4 -64
  12. package/core/computed/metrics/lantern-metric.js +6 -124
  13. package/core/computed/metrics/lantern-speed-index.d.ts +6 -0
  14. package/core/computed/metrics/lantern-speed-index.js +1 -1
  15. package/core/computed/metrics/lantern-total-blocking-time.d.ts +6 -0
  16. package/core/computed/metrics/lantern-total-blocking-time.js +1 -1
  17. package/core/gather/gatherers/full-page-screenshot.d.ts +4 -0
  18. package/core/gather/gatherers/full-page-screenshot.js +26 -32
  19. package/core/lib/lantern/metric.d.ts +71 -0
  20. package/core/lib/lantern/metric.js +143 -0
  21. package/core/lib/lantern/network-node.d.ts +5 -5
  22. package/core/lib/lantern/network-node.js +3 -4
  23. package/core/lib/lantern/page-dependency-graph.d.ts +7 -7
  24. package/core/lib/lantern/page-dependency-graph.js +4 -4
  25. package/core/lib/lantern/simulator/connection-pool.d.ts +14 -15
  26. package/core/lib/lantern/simulator/connection-pool.js +7 -9
  27. package/core/lib/lantern/simulator/dns-cache.d.ts +5 -11
  28. package/core/lib/lantern/simulator/dns-cache.js +3 -3
  29. package/core/lib/lantern/simulator/network-analyzer.d.ts +30 -30
  30. package/core/lib/lantern/simulator/network-analyzer.js +14 -15
  31. package/core/lib/lantern/simulator/simulator.d.ts +13 -16
  32. package/core/lib/lantern/simulator/simulator.js +10 -16
  33. package/core/lib/lantern/types/lantern.d.ts +129 -0
  34. package/core/lib/lantern/types/lantern.js +7 -0
  35. package/core/lib/network-request.d.ts +3 -4
  36. package/core/lib/network-request.js +2 -3
  37. package/package.json +1 -1
  38. package/tsconfig.json +1 -0
  39. package/types/gatherer.d.ts +1 -1
  40. package/types/lhr/lhr.d.ts +1 -1
  41. package/types/internal/lantern.d.ts +0 -124
@@ -17,6 +17,7 @@ import formsAutoComplete from './test-definitions/forms-autocomplete.js';
17
17
  import fpsMax from './test-definitions/fps-max.js';
18
18
  import fpsMaxPassive from './test-definitions/fps-max-passive.js';
19
19
  import fpsScaled from './test-definitions/fps-scaled.js';
20
+ import fpsOverflowX from './test-definitions/fps-overflow-x.js';
20
21
  import issuesMixedContent from './test-definitions/issues-mixed-content.js';
21
22
  import lanternFetch from './test-definitions/lantern-fetch.js';
22
23
  import lanternIdleCallbackLong from './test-definitions/lantern-idle-callback-long.js';
@@ -80,6 +81,7 @@ const smokeTests = [
80
81
  formsAutoComplete,
81
82
  fpsMax,
82
83
  fpsMaxPassive,
84
+ fpsOverflowX,
83
85
  fpsScaled,
84
86
  issuesMixedContent,
85
87
  lanternFetch,
@@ -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) {
@@ -1,5 +1,9 @@
1
1
  export default FullPageScreenshot;
2
2
  declare class FullPageScreenshot extends BaseGatherer {
3
+ /**
4
+ * @param {LH.Gatherer.Context} context
5
+ */
6
+ waitForNetworkIdle(context: LH.Gatherer.Context): import("../driver/wait-for-condition.js").CancellableWait<void>;
3
7
  /**
4
8
  * @param {LH.Gatherer.Context} context
5
9
  * @param {{height: number, width: number, mobile: boolean}} deviceMetrics
@@ -13,7 +13,10 @@ import {waitForNetworkIdle} from '../driver/wait-for-condition.js';
13
13
  // JPEG quality setting
14
14
  // Exploration and examples of reports using different quality settings: https://docs.google.com/document/d/1ZSffucIca9XDW2eEwfoevrk-OTl7WQFeMf0CgeJAA8M/edit#
15
15
  // Note: this analysis was done for JPEG, but now we use WEBP.
16
- const FULL_PAGE_SCREENSHOT_QUALITY = 30;
16
+ const FULL_PAGE_SCREENSHOT_QUALITY = process.env.LH_FPS_TEST ? 100 : 30;
17
+ // webp currently cant do lossless encoding, so to help tests switch to png
18
+ // Remove when this is resolved: https://bugs.chromium.org/p/chromium/issues/detail?id=1469183
19
+ const FULL_PAGE_SCREENSHOT_FORMAT = process.env.LH_FPS_TEST ? 'png' : 'webp';
17
20
 
18
21
  // https://developers.google.com/speed/webp/faq#what_is_the_maximum_size_a_webp_image_can_be
19
22
  const MAX_WEBP_SIZE = 16383;
@@ -44,17 +47,6 @@ function getObservedDeviceMetrics() {
44
47
  };
45
48
  }
46
49
 
47
- /**
48
- * The screenshot dimensions are sized to `window.outerHeight` / `window.outerWidth`,
49
- * however the bounding boxes of the elements are relative to `window.innerHeight` / `window.innerWidth`.
50
- */
51
- function getScreenshotAreaSize() {
52
- return {
53
- width: window.innerWidth,
54
- height: window.innerHeight,
55
- };
56
- }
57
-
58
50
  function waitForDoubleRaf() {
59
51
  return new Promise((resolve) => {
60
52
  requestAnimationFrame(() => requestAnimationFrame(resolve));
@@ -69,6 +61,21 @@ class FullPageScreenshot extends BaseGatherer {
69
61
  supportedModes: ['snapshot', 'timespan', 'navigation'],
70
62
  };
71
63
 
64
+ /**
65
+ * @param {LH.Gatherer.Context} context
66
+ */
67
+ waitForNetworkIdle(context) {
68
+ const session = context.driver.defaultSession;
69
+ const networkMonitor = context.driver.networkMonitor;
70
+ return waitForNetworkIdle(session, networkMonitor, {
71
+ pretendDCLAlreadyFired: true,
72
+ networkQuietThresholdMs: 1000,
73
+ busyEvent: 'network-critical-busy',
74
+ idleEvent: 'network-critical-idle',
75
+ isIdle: recorder => recorder.isCriticalIdle(),
76
+ });
77
+ }
78
+
72
79
  /**
73
80
  * @param {LH.Gatherer.Context} context
74
81
  * @param {{height: number, width: number, mobile: boolean}} deviceMetrics
@@ -86,15 +93,7 @@ class FullPageScreenshot extends BaseGatherer {
86
93
  );
87
94
  const height = Math.min(fullHeight, MAX_WEBP_SIZE);
88
95
 
89
- // Setup network monitor before we change the viewport.
90
- const networkMonitor = context.driver.networkMonitor;
91
- const waitForNetworkIdleResult = waitForNetworkIdle(session, networkMonitor, {
92
- pretendDCLAlreadyFired: true,
93
- networkQuietThresholdMs: 1000,
94
- busyEvent: 'network-critical-busy',
95
- idleEvent: 'network-critical-idle',
96
- isIdle: recorder => recorder.isCriticalIdle(),
97
- });
96
+ const waitForNetworkIdleResult = this.waitForNetworkIdle(context);
98
97
 
99
98
  await session.sendCommand('Emulation.setDeviceMetricsOverride', {
100
99
  mobile: deviceMetrics.mobile,
@@ -120,22 +119,17 @@ class FullPageScreenshot extends BaseGatherer {
120
119
  * @return {Promise<LH.Result.FullPageScreenshot['screenshot']>}
121
120
  */
122
121
  async _takeScreenshot(context) {
122
+ const metrics = await context.driver.defaultSession.sendCommand('Page.getLayoutMetrics');
123
123
  const result = await context.driver.defaultSession.sendCommand('Page.captureScreenshot', {
124
- format: 'webp',
124
+ format: FULL_PAGE_SCREENSHOT_FORMAT,
125
125
  quality: FULL_PAGE_SCREENSHOT_QUALITY,
126
126
  });
127
- const data = 'data:image/webp;base64,' + result.data;
128
-
129
- const screenshotAreaSize =
130
- await context.driver.executionContext.evaluate(getScreenshotAreaSize, {
131
- args: [],
132
- useIsolation: true,
133
- });
127
+ const data = `data:image/${FULL_PAGE_SCREENSHOT_FORMAT};base64,` + result.data;
134
128
 
135
129
  return {
136
130
  data,
137
- width: screenshotAreaSize.width,
138
- height: screenshotAreaSize.height,
131
+ width: metrics.cssVisualViewport.clientWidth,
132
+ height: metrics.cssVisualViewport.clientHeight,
139
133
  };
140
134
  }
141
135
 
@@ -159,7 +153,7 @@ class FullPageScreenshot extends BaseGatherer {
159
153
  for (const [node, id] of lhIdToElements.entries()) {
160
154
  // @ts-expect-error - getBoundingClientRect put into scope via stringification
161
155
  const rect = getBoundingClientRect(node);
162
- nodes[id] = rect;
156
+ nodes[id] = {id: node.id, ...rect};
163
157
  }
164
158
 
165
159
  return nodes;
@@ -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