lighthouse 12.0.0 → 12.1.0

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 (219) hide show
  1. package/cli/run.js +5 -38
  2. package/cli/test/smokehouse/lighthouse-runners/bundle.js +1 -1
  3. package/cli/test/smokehouse/smokehouse.js +11 -1
  4. package/core/audits/accessibility/aria-allowed-role.js +7 -9
  5. package/core/audits/byte-efficiency/byte-efficiency-audit.d.ts +2 -2
  6. package/core/audits/byte-efficiency/byte-efficiency-audit.js +3 -3
  7. package/core/audits/byte-efficiency/offscreen-images.js +1 -1
  8. package/core/audits/byte-efficiency/render-blocking-resources.d.ts +3 -3
  9. package/core/audits/byte-efficiency/render-blocking-resources.js +10 -10
  10. package/core/audits/dobetterweb/uses-http2.d.ts +2 -2
  11. package/core/audits/dobetterweb/uses-http2.js +5 -5
  12. package/core/audits/long-tasks.d.ts +7 -6
  13. package/core/audits/long-tasks.js +5 -4
  14. package/core/audits/metrics/first-meaningful-paint.d.ts +1 -17
  15. package/core/audits/metrics/first-meaningful-paint.js +5 -47
  16. package/core/audits/metrics/interactive.d.ts +1 -1
  17. package/core/audits/metrics/interactive.js +1 -1
  18. package/core/audits/predictive-perf.js +0 -6
  19. package/core/audits/prioritize-lcp-image.d.ts +1 -1
  20. package/core/audits/prioritize-lcp-image.js +2 -2
  21. package/core/audits/redirects.js +2 -3
  22. package/core/audits/third-party-facades.js +1 -1
  23. package/core/audits/third-party-summary.js +1 -1
  24. package/core/audits/uses-rel-preconnect.js +2 -2
  25. package/core/audits/uses-rel-preload.js +9 -9
  26. package/core/computed/critical-request-chains.js +3 -3
  27. package/core/computed/document-urls.js +3 -2
  28. package/core/computed/load-simulator.d.ts +4 -4
  29. package/core/computed/load-simulator.js +3 -54
  30. package/core/computed/main-resource.js +3 -2
  31. package/core/computed/metrics/interactive.d.ts +6 -0
  32. package/core/computed/metrics/interactive.js +2 -2
  33. package/core/computed/metrics/lantern-first-contentful-paint.d.ts +4 -4
  34. package/core/computed/metrics/lantern-first-contentful-paint.js +3 -3
  35. package/core/computed/metrics/lantern-interactive.d.ts +4 -4
  36. package/core/computed/metrics/lantern-interactive.js +6 -6
  37. package/core/computed/metrics/lantern-largest-contentful-paint.d.ts +4 -4
  38. package/core/computed/metrics/lantern-largest-contentful-paint.js +3 -3
  39. package/core/computed/metrics/lantern-max-potential-fid.d.ts +4 -4
  40. package/core/computed/metrics/lantern-max-potential-fid.js +3 -3
  41. package/core/computed/metrics/lantern-metric.d.ts +21 -2
  42. package/core/computed/metrics/lantern-metric.js +39 -4
  43. package/core/computed/metrics/lantern-speed-index.d.ts +4 -4
  44. package/core/computed/metrics/lantern-speed-index.js +4 -4
  45. package/core/computed/metrics/lantern-total-blocking-time.d.ts +4 -4
  46. package/core/computed/metrics/lantern-total-blocking-time.js +3 -3
  47. package/core/computed/metrics/timing-summary.js +0 -6
  48. package/core/computed/metrics/total-blocking-time.js +3 -1
  49. package/core/computed/navigation-insights.d.ts +2 -20
  50. package/core/computed/network-analysis.d.ts +0 -5
  51. package/core/computed/network-analysis.js +2 -42
  52. package/core/computed/page-dependency-graph.d.ts +5 -3
  53. package/core/computed/page-dependency-graph.js +17 -7
  54. package/core/computed/processed-navigation.d.ts +1 -1
  55. package/core/computed/tbt-impact-tasks.js +4 -2
  56. package/core/computed/trace-engine-result.d.ts +0 -11
  57. package/core/computed/trace-engine-result.js +5 -19
  58. package/core/config/constants.d.ts +28 -53
  59. package/core/config/constants.js +2 -43
  60. package/core/gather/driver/navigation.js +1 -1
  61. package/core/gather/driver/network-monitor.d.ts +2 -1
  62. package/core/gather/driver/network-monitor.js +4 -4
  63. package/core/gather/driver/target-manager.d.ts +1 -1
  64. package/core/gather/driver.d.ts +0 -12
  65. package/core/gather/driver.js +1 -26
  66. package/core/gather/gatherers/inspector-issues.js +1 -0
  67. package/core/gather/gatherers/root-causes.js +0 -1
  68. package/core/gather/session.d.ts +5 -3
  69. package/core/gather/session.js +22 -1
  70. package/core/lib/asset-saver.d.ts +13 -9
  71. package/core/lib/asset-saver.js +77 -30
  72. package/core/lib/bf-cache-strings.js +2 -2
  73. package/core/lib/lantern/{base-node.d.ts → BaseNode.d.ts} +7 -9
  74. package/core/lib/lantern/{base-node.js → BaseNode.js} +6 -6
  75. package/core/lib/lantern/BaseNode.test.js +385 -0
  76. package/core/lib/lantern/CpuNode.d.ts +43 -0
  77. package/core/lib/lantern/{cpu-node.js → CpuNode.js} +8 -9
  78. package/core/lib/lantern/{lantern-error.d.ts → LanternError.d.ts} +1 -1
  79. package/core/lib/lantern/{metric.d.ts → Metric.d.ts} +23 -25
  80. package/core/lib/lantern/{metric.js → Metric.js} +14 -16
  81. package/core/lib/lantern/{network-node.d.ts → NetworkNode.d.ts} +6 -7
  82. package/core/lib/lantern/{network-node.js → NetworkNode.js} +7 -9
  83. package/core/lib/lantern/PageDependencyGraph.d.ts +82 -0
  84. package/core/lib/lantern/{page-dependency-graph.js → PageDependencyGraph.js} +185 -50
  85. package/core/lib/lantern/PageDependencyGraph.test.js +654 -0
  86. package/core/{computed/metrics/tbt-utils.d.ts → lib/lantern/TBTUtils.d.ts} +1 -1
  87. package/core/lib/lantern/TBTUtils.test.d.ts +2 -0
  88. package/core/lib/lantern/TBTUtils.test.js +130 -0
  89. package/core/lib/lantern/TraceEngineComputationData.d.ts +25 -0
  90. package/core/lib/lantern/TraceEngineComputationData.js +466 -0
  91. package/core/lib/lantern/lantern.d.ts +19 -7
  92. package/core/lib/lantern/lantern.js +21 -1
  93. package/core/lib/lantern/metrics/{first-contentful-paint.d.ts → FirstContentfulPaint.d.ts} +11 -11
  94. package/core/lib/lantern/metrics/{first-contentful-paint.js → FirstContentfulPaint.js} +11 -13
  95. package/core/lib/lantern/metrics/FirstContentfulPaint.test.js +54 -0
  96. package/core/lib/lantern/metrics/Interactive.d.ts +20 -0
  97. package/core/lib/lantern/metrics/{interactive.js → Interactive.js} +23 -26
  98. package/core/lib/lantern/metrics/Interactive.test.js +56 -0
  99. package/core/lib/lantern/metrics/LargestContentfulPaint.d.ts +19 -0
  100. package/core/lib/lantern/metrics/{largest-contentful-paint.js → LargestContentfulPaint.js} +16 -19
  101. package/core/lib/lantern/metrics/LargestContentfulPaint.test.js +42 -0
  102. package/core/lib/lantern/metrics/MaxPotentialFID.d.ts +24 -0
  103. package/core/lib/lantern/metrics/{max-potential-fid.js → MaxPotentialFID.js} +12 -13
  104. package/core/lib/lantern/metrics/MetricTestUtils.d.ts +19 -0
  105. package/core/lib/lantern/metrics/MetricTestUtils.js +48 -0
  106. package/core/lib/lantern/metrics/{speed-index.d.ts → SpeedIndex.d.ts} +7 -13
  107. package/core/lib/lantern/metrics/{speed-index.js → SpeedIndex.js} +14 -16
  108. package/core/lib/lantern/metrics/SpeedIndex.test.js +83 -0
  109. package/core/lib/lantern/metrics/TotalBlockingTime.d.ts +25 -0
  110. package/core/lib/lantern/metrics/{total-blocking-time.js → TotalBlockingTime.js} +13 -16
  111. package/core/lib/lantern/metrics/__snapshots__/FirstContentfulPaint.test.js.snap +11 -0
  112. package/core/lib/lantern/metrics/__snapshots__/Interactive.test.js.snap +17 -0
  113. package/core/lib/lantern/metrics/metrics.d.ts +9 -0
  114. package/core/lib/lantern/metrics/metrics.js +16 -0
  115. package/core/lib/lantern/{simulator/connection-pool.d.ts → simulation/ConnectionPool.d.ts} +15 -15
  116. package/core/lib/lantern/{simulator/connection-pool.js → simulation/ConnectionPool.js} +25 -25
  117. package/core/lib/lantern/simulation/ConnectionPool.test.js +195 -0
  118. package/core/lib/lantern/simulation/Constants.d.ts +52 -0
  119. package/core/lib/lantern/simulation/Constants.js +48 -0
  120. package/core/lib/lantern/{simulator/dns-cache.d.ts → simulation/DNSCache.d.ts} +3 -3
  121. package/core/lib/lantern/{simulator/dns-cache.js → simulation/DNSCache.js} +2 -2
  122. package/core/lib/lantern/simulation/DNSCache.test.js +72 -0
  123. package/core/lib/lantern/{simulator/network-analyzer.d.ts → simulation/NetworkAnalyzer.d.ts} +34 -21
  124. package/core/lib/lantern/{simulator/network-analyzer.js → simulation/NetworkAnalyzer.js} +106 -57
  125. package/core/lib/lantern/simulation/NetworkAnalyzer.test.js +475 -0
  126. package/core/lib/lantern/{simulator/simulator-timing-map.d.ts → simulation/SimulationTimingMap.d.ts} +7 -7
  127. package/core/lib/lantern/{simulator/simulator-timing-map.js → simulation/SimulationTimingMap.js} +5 -6
  128. package/core/lib/lantern/{simulator/simulator.d.ts → simulation/Simulator.d.ts} +21 -19
  129. package/core/lib/lantern/{simulator/simulator.js → simulation/Simulator.js} +100 -45
  130. package/core/lib/lantern/simulation/Simulator.test.js +434 -0
  131. package/core/lib/lantern/simulation/TCPConnection.test.d.ts +2 -0
  132. package/core/lib/lantern/simulation/TCPConnection.test.js +374 -0
  133. package/core/lib/lantern/{simulator/tcp-connection.d.ts → simulation/TcpConnection.d.ts} +2 -2
  134. package/core/lib/lantern/{simulator/tcp-connection.js → simulation/TcpConnection.js} +1 -1
  135. package/core/lib/lantern/simulation/simulation.d.ts +21 -0
  136. package/core/lib/lantern/simulation/simulation.js +28 -0
  137. package/core/lib/lantern/types/lantern.d.ts +145 -20
  138. package/core/lib/lantern-trace-saver.d.ts +4 -4
  139. package/core/lib/lantern-trace-saver.js +4 -4
  140. package/core/lib/navigation-error.js +3 -3
  141. package/core/lib/network-recorder.js +2 -2
  142. package/core/lib/network-request.d.ts +29 -3
  143. package/core/lib/network-request.js +20 -13
  144. package/core/lib/tracehouse/trace-processor.d.ts +0 -2
  145. package/core/lib/tracehouse/trace-processor.js +1 -31
  146. package/core/lib/traces/metric-trace-events.js +0 -5
  147. package/dist/report/bundle.esm.js +1 -1
  148. package/dist/report/flow.js +1 -1
  149. package/dist/report/standalone.js +1 -1
  150. package/package.json +14 -13
  151. package/report/renderer/performance-category-renderer.js +1 -1
  152. package/shared/localization/locales/ar-XB.json +43 -4
  153. package/shared/localization/locales/ar.json +43 -4
  154. package/shared/localization/locales/bg.json +43 -4
  155. package/shared/localization/locales/ca.json +44 -5
  156. package/shared/localization/locales/cs.json +43 -4
  157. package/shared/localization/locales/da.json +43 -4
  158. package/shared/localization/locales/de.json +43 -4
  159. package/shared/localization/locales/el.json +43 -4
  160. package/shared/localization/locales/en-GB.json +42 -3
  161. package/shared/localization/locales/en-US.json +4 -4
  162. package/shared/localization/locales/en-XA.json +43 -4
  163. package/shared/localization/locales/en-XL.json +4 -4
  164. package/shared/localization/locales/es-419.json +43 -4
  165. package/shared/localization/locales/es.json +42 -3
  166. package/shared/localization/locales/fi.json +43 -4
  167. package/shared/localization/locales/fil.json +42 -3
  168. package/shared/localization/locales/fr.json +42 -3
  169. package/shared/localization/locales/he.json +48 -9
  170. package/shared/localization/locales/hi.json +43 -4
  171. package/shared/localization/locales/hr.json +43 -4
  172. package/shared/localization/locales/hu.json +42 -3
  173. package/shared/localization/locales/id.json +42 -3
  174. package/shared/localization/locales/it.json +43 -4
  175. package/shared/localization/locales/ja.json +42 -3
  176. package/shared/localization/locales/ko.json +43 -4
  177. package/shared/localization/locales/lt.json +42 -3
  178. package/shared/localization/locales/lv.json +43 -4
  179. package/shared/localization/locales/nl.json +44 -5
  180. package/shared/localization/locales/no.json +42 -3
  181. package/shared/localization/locales/pl.json +43 -4
  182. package/shared/localization/locales/pt-PT.json +43 -4
  183. package/shared/localization/locales/pt.json +43 -4
  184. package/shared/localization/locales/ro.json +43 -4
  185. package/shared/localization/locales/ru.json +43 -4
  186. package/shared/localization/locales/sk.json +43 -4
  187. package/shared/localization/locales/sl.json +42 -3
  188. package/shared/localization/locales/sr-Latn.json +43 -4
  189. package/shared/localization/locales/sr.json +43 -4
  190. package/shared/localization/locales/sv.json +42 -3
  191. package/shared/localization/locales/ta.json +42 -3
  192. package/shared/localization/locales/te.json +43 -4
  193. package/shared/localization/locales/th.json +44 -5
  194. package/shared/localization/locales/tr.json +43 -4
  195. package/shared/localization/locales/uk.json +43 -4
  196. package/shared/localization/locales/vi.json +43 -4
  197. package/shared/localization/locales/zh-HK.json +43 -4
  198. package/shared/localization/locales/zh-TW.json +43 -4
  199. package/shared/localization/locales/zh.json +43 -4
  200. package/third-party/chromium-synchronization/inspector-issueAdded-types-test.js +1 -0
  201. package/tsconfig-all.json +1 -0
  202. package/tsconfig.json +11 -7
  203. package/types/artifacts.d.ts +23 -25
  204. package/types/gatherer.d.ts +2 -3
  205. package/types/lhr/lhr.d.ts +2 -0
  206. package/core/computed/metrics/first-meaningful-paint.d.ts +0 -21
  207. package/core/computed/metrics/first-meaningful-paint.js +0 -44
  208. package/core/computed/metrics/lantern-first-meaningful-paint.d.ts +0 -25
  209. package/core/computed/metrics/lantern-first-meaningful-paint.js +0 -43
  210. package/core/lib/lantern/cpu-node.d.ts +0 -44
  211. package/core/lib/lantern/metrics/first-meaningful-paint.d.ts +0 -6
  212. package/core/lib/lantern/metrics/first-meaningful-paint.js +0 -64
  213. package/core/lib/lantern/metrics/interactive.d.ts +0 -26
  214. package/core/lib/lantern/metrics/largest-contentful-paint.d.ts +0 -19
  215. package/core/lib/lantern/metrics/max-potential-fid.d.ts +0 -30
  216. package/core/lib/lantern/metrics/total-blocking-time.d.ts +0 -31
  217. package/core/lib/lantern/page-dependency-graph.d.ts +0 -58
  218. /package/core/lib/lantern/{lantern-error.js → LanternError.js} +0 -0
  219. /package/core/{computed/metrics/tbt-utils.js → lib/lantern/TBTUtils.js} +0 -0
@@ -4,9 +4,8 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- import * as Lantern from './types/lantern.js';
7
+ import * as Lantern from './lantern.js';
8
8
  import {NetworkRequestTypes} from './lantern.js';
9
- import {BaseNode} from './base-node.js';
10
9
 
11
10
  const NON_NETWORK_SCHEMES = [
12
11
  'blob', // @see https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL
@@ -18,7 +17,6 @@ const NON_NETWORK_SCHEMES = [
18
17
  ];
19
18
 
20
19
  /**
21
- * Use `NetworkRequest.isNonNetworkRequest(req)` if working with a request.
22
20
  * Note: the `protocol` field from CDP can be 'h2', 'http', (not 'https'!) or it'll be url's scheme.
23
21
  * https://source.chromium.org/chromium/chromium/src/+/main:content/browser/devtools/protocol/network_handler.cc;l=598-611;drc=56d4a9a9deb30be73adcee8737c73bcb2a5ab64f
24
22
  * However, a `new URL(href).protocol` has a colon suffix.
@@ -36,9 +34,9 @@ function isNonNetworkProtocol(protocol) {
36
34
 
37
35
  /**
38
36
  * @template [T=any]
39
- * @extends {BaseNode<T>}
37
+ * @extends {Lantern.BaseNode<T>}
40
38
  */
41
- class NetworkNode extends BaseNode {
39
+ class NetworkNode extends Lantern.BaseNode {
42
40
  /**
43
41
  * @param {Lantern.NetworkRequest<T>} networkRequest
44
42
  */
@@ -49,7 +47,7 @@ class NetworkNode extends BaseNode {
49
47
  }
50
48
 
51
49
  get type() {
52
- return BaseNode.TYPES.NETWORK;
50
+ return Lantern.BaseNode.TYPES.NETWORK;
53
51
  }
54
52
 
55
53
  /**
@@ -69,8 +67,8 @@ class NetworkNode extends BaseNode {
69
67
  /**
70
68
  * @return {Readonly<T>}
71
69
  */
72
- get record() {
73
- return /** @type {Required<T>} */ (this._request.record);
70
+ get rawRequest() {
71
+ return /** @type {Required<T>} */ (this._request.rawRequest);
74
72
  }
75
73
 
76
74
  /**
@@ -105,7 +103,7 @@ class NetworkNode extends BaseNode {
105
103
  }
106
104
 
107
105
  /**
108
- * Returns whether this network record can be downloaded without a TCP connection.
106
+ * Returns whether this network request can be downloaded without a TCP connection.
109
107
  * During simulation we treat data coming in over a network connection separately from on-device data.
110
108
  * @return {boolean}
111
109
  */
@@ -0,0 +1,82 @@
1
+ export type Node = import('./BaseNode.js').Node;
2
+ export type NetworkNodeOutput = {
3
+ nodes: Array<NetworkNode>;
4
+ idToNodeMap: Map<string, NetworkNode>;
5
+ urlToNodeMap: Map<string, Array<NetworkNode>>;
6
+ frameIdToNodeMap: Map<string, NetworkNode | null>;
7
+ };
8
+ export class PageDependencyGraph {
9
+ /**
10
+ * @param {Lantern.NetworkRequest} request
11
+ * @return {Array<string>}
12
+ */
13
+ static getNetworkInitiators(request: Lantern.NetworkRequest): Array<string>;
14
+ /**
15
+ * @param {Array<Lantern.NetworkRequest>} networkRequests
16
+ * @return {NetworkNodeOutput}
17
+ */
18
+ static getNetworkNodeOutput(networkRequests: Array<Lantern.NetworkRequest>): NetworkNodeOutput;
19
+ /**
20
+ * @param {Lantern.TraceEvent} evt
21
+ * @return {boolean}
22
+ */
23
+ static isScheduleableTask(evt: Lantern.TraceEvent): boolean;
24
+ /**
25
+ * There should *always* be at least one top level event, having 0 typically means something is
26
+ * drastically wrong with the trace and we should just give up early and loudly.
27
+ *
28
+ * @param {Lantern.TraceEvent[]} events
29
+ */
30
+ static assertHasToplevelEvents(events: Lantern.TraceEvent[]): void;
31
+ /**
32
+ * @param {Lantern.TraceEvent[]} mainThreadEvents
33
+ * @return {Array<CPUNode>}
34
+ */
35
+ static getCPUNodes(mainThreadEvents: Lantern.TraceEvent[]): Array<CPUNode>;
36
+ /**
37
+ * @param {NetworkNode} rootNode
38
+ * @param {NetworkNodeOutput} networkNodeOutput
39
+ */
40
+ static linkNetworkNodes(rootNode: NetworkNode, networkNodeOutput: NetworkNodeOutput): void;
41
+ /**
42
+ * @param {Node} rootNode
43
+ * @param {NetworkNodeOutput} networkNodeOutput
44
+ * @param {Array<CPUNode>} cpuNodes
45
+ */
46
+ static linkCPUNodes(rootNode: Node, networkNodeOutput: NetworkNodeOutput, cpuNodes: Array<CPUNode>): void;
47
+ /**
48
+ * Removes the given node from the graph, but retains all paths between its dependencies and
49
+ * dependents.
50
+ * @param {Node} node
51
+ */
52
+ static _pruneNode(node: Node): void;
53
+ /**
54
+ * TODO(15841): remove when CDT backend is gone. until then, this is a useful debugging tool
55
+ * to find delta between using CDP or the trace to create the network requests.
56
+ *
57
+ * When a test fails using the trace backend, I enabled this debug method and copied the network
58
+ * requests when CDP was used, then when trace is used, and diff'd them. This method helped
59
+ * remove non-logical differences from the comparison (order of properties, slight rounding
60
+ * discrepancies, removing object cycles, etc).
61
+ *
62
+ * When using for a unit test, make sure to do `.only` so you are getting what you expect.
63
+ * @param {Lantern.NetworkRequest[]} lanternRequests
64
+ * @return {never}
65
+ */
66
+ static _debugNormalizeRequests(lanternRequests: Lantern.NetworkRequest[]): never;
67
+ /**
68
+ * @param {Lantern.TraceEvent[]} mainThreadEvents
69
+ * @param {Lantern.NetworkRequest[]} networkRequests
70
+ * @param {Lantern.Simulation.URL} URL
71
+ * @return {Node}
72
+ */
73
+ static createGraph(mainThreadEvents: Lantern.TraceEvent[], networkRequests: Lantern.NetworkRequest[], URL: Lantern.Simulation.URL): Node;
74
+ /**
75
+ * @param {Node} rootNode
76
+ */
77
+ static printGraph(rootNode: Node, widthInCharacters?: number): void;
78
+ }
79
+ import { NetworkNode } from './NetworkNode.js';
80
+ import * as Lantern from './lantern.js';
81
+ import { CPUNode } from './CpuNode.js';
82
+ //# sourceMappingURL=PageDependencyGraph.d.ts.map
@@ -4,15 +4,20 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- import * as Lantern from './types/lantern.js';
8
- import {NetworkRequestTypes} from './lantern.js';
9
- import {NetworkNode} from './network-node.js';
10
- import {CPUNode} from './cpu-node.js';
11
- import {TraceProcessor} from '../tracehouse/trace-processor.js';
12
- import {NetworkAnalyzer} from './simulator/network-analyzer.js';
7
+ import * as Lantern from './lantern.js';
8
+ import {NetworkNode} from './NetworkNode.js';
9
+ import {CPUNode} from './CpuNode.js';
13
10
 
14
- /** @typedef {import('./base-node.js').Node} Node */
15
- /** @typedef {Omit<LH.Artifacts['URL'], 'finalDisplayedUrl'>} URLArtifact */
11
+ // COMPAT: m71+ We added RunTask to `disabled-by-default-lighthouse`
12
+ const SCHEDULABLE_TASK_TITLE_LH = 'RunTask';
13
+ // m69-70 DoWork is different and we now need RunTask, see https://bugs.chromium.org/p/chromium/issues/detail?id=871204#c11
14
+ const SCHEDULABLE_TASK_TITLE_ALT1 = 'ThreadControllerImpl::RunTask';
15
+ // In m66-68 refactored to this task title, https://crrev.com/c/883346
16
+ const SCHEDULABLE_TASK_TITLE_ALT2 = 'ThreadControllerImpl::DoWork';
17
+ // m65 and earlier
18
+ const SCHEDULABLE_TASK_TITLE_ALT3 = 'TaskQueueManager::ProcessTaskFromWorkQueue';
19
+
20
+ /** @typedef {import('./BaseNode.js').Node} Node */
16
21
 
17
22
  /**
18
23
  * @typedef {Object} NetworkNodeOutput
@@ -31,19 +36,19 @@ const IGNORED_MIME_TYPES_REGEX = /^video/;
31
36
 
32
37
  class PageDependencyGraph {
33
38
  /**
34
- * @param {Lantern.NetworkRequest} record
39
+ * @param {Lantern.NetworkRequest} request
35
40
  * @return {Array<string>}
36
41
  */
37
- static getNetworkInitiators(record) {
38
- if (!record.initiator) return [];
39
- if (record.initiator.url) return [record.initiator.url];
40
- if (record.initiator.type === 'script') {
42
+ static getNetworkInitiators(request) {
43
+ if (!request.initiator) return [];
44
+ if (request.initiator.url) return [request.initiator.url];
45
+ if (request.initiator.type === 'script') {
41
46
  // Script initiators have the stack of callFrames from all functions that led to this request.
42
47
  // If async stacks are enabled, then the stack will also have the parent functions that asynchronously
43
48
  // led to this request chained in the `parent` property.
44
49
  /** @type {Set<string>} */
45
50
  const scriptURLs = new Set();
46
- let stack = record.initiator.stack;
51
+ let stack = request.initiator.stack;
47
52
  while (stack) {
48
53
  const callFrames = stack.callFrames || [];
49
54
  for (const frame of callFrames) {
@@ -60,10 +65,10 @@ class PageDependencyGraph {
60
65
  }
61
66
 
62
67
  /**
63
- * @param {Array<Lantern.NetworkRequest>} networkRecords
68
+ * @param {Array<Lantern.NetworkRequest>} networkRequests
64
69
  * @return {NetworkNodeOutput}
65
70
  */
66
- static getNetworkNodeOutput(networkRecords) {
71
+ static getNetworkNodeOutput(networkRequests) {
67
72
  /** @type {Array<NetworkNode>} */
68
73
  const nodes = [];
69
74
  /** @type {Map<string, NetworkNode>} */
@@ -73,35 +78,35 @@ class PageDependencyGraph {
73
78
  /** @type {Map<string, NetworkNode|null>} */
74
79
  const frameIdToNodeMap = new Map();
75
80
 
76
- networkRecords.forEach(record => {
77
- if (IGNORED_MIME_TYPES_REGEX.test(record.mimeType)) return;
78
- if (record.sessionTargetType === 'worker') return;
81
+ networkRequests.forEach(request => {
82
+ if (IGNORED_MIME_TYPES_REGEX.test(request.mimeType)) return;
83
+ if (request.fromWorker) return;
79
84
 
80
- // Network record requestIds can be duplicated for an unknown reason
81
- // Suffix all subsequent records with `:duplicate` until it's unique
85
+ // Network requestIds can be duplicated for an unknown reason
86
+ // Suffix all subsequent requests with `:duplicate` until it's unique
82
87
  // NOTE: This should never happen with modern NetworkRequest library, but old fixtures
83
88
  // might still have this issue.
84
- while (idToNodeMap.has(record.requestId)) {
85
- record.requestId += ':duplicate';
89
+ while (idToNodeMap.has(request.requestId)) {
90
+ request.requestId += ':duplicate';
86
91
  }
87
92
 
88
- const node = new NetworkNode(record);
93
+ const node = new NetworkNode(request);
89
94
  nodes.push(node);
90
95
 
91
- const urlList = urlToNodeMap.get(record.url) || [];
96
+ const urlList = urlToNodeMap.get(request.url) || [];
92
97
  urlList.push(node);
93
98
 
94
- idToNodeMap.set(record.requestId, node);
95
- urlToNodeMap.set(record.url, urlList);
99
+ idToNodeMap.set(request.requestId, node);
100
+ urlToNodeMap.set(request.url, urlList);
96
101
 
97
102
  // If the request was for the root document of an iframe, save an entry in our
98
103
  // map so we can link up the task `args.data.frame` dependencies later in graph creation.
99
- if (record.frameId &&
100
- record.resourceType === NetworkRequestTypes.Document &&
101
- record.documentURL === record.url) {
104
+ if (request.frameId &&
105
+ request.resourceType === Lantern.NetworkRequestTypes.Document &&
106
+ request.documentURL === request.url) {
102
107
  // If there's ever any ambiguity, permanently set the value to `false` to avoid loops in the graph.
103
- const value = frameIdToNodeMap.has(record.frameId) ? null : node;
104
- frameIdToNodeMap.set(record.frameId, value);
108
+ const value = frameIdToNodeMap.has(request.frameId) ? null : node;
109
+ frameIdToNodeMap.set(request.frameId, value);
105
110
  }
106
111
  });
107
112
 
@@ -109,7 +114,31 @@ class PageDependencyGraph {
109
114
  }
110
115
 
111
116
  /**
112
- * @param {LH.TraceEvent[]} mainThreadEvents
117
+ * @param {Lantern.TraceEvent} evt
118
+ * @return {boolean}
119
+ */
120
+ static isScheduleableTask(evt) {
121
+ return evt.name === SCHEDULABLE_TASK_TITLE_LH ||
122
+ evt.name === SCHEDULABLE_TASK_TITLE_ALT1 ||
123
+ evt.name === SCHEDULABLE_TASK_TITLE_ALT2 ||
124
+ evt.name === SCHEDULABLE_TASK_TITLE_ALT3;
125
+ }
126
+
127
+ /**
128
+ * There should *always* be at least one top level event, having 0 typically means something is
129
+ * drastically wrong with the trace and we should just give up early and loudly.
130
+ *
131
+ * @param {Lantern.TraceEvent[]} events
132
+ */
133
+ static assertHasToplevelEvents(events) {
134
+ const hasToplevelTask = events.some(this.isScheduleableTask);
135
+ if (!hasToplevelTask) {
136
+ throw new Error('Could not find any top level events');
137
+ }
138
+ }
139
+
140
+ /**
141
+ * @param {Lantern.TraceEvent[]} mainThreadEvents
113
142
  * @return {Array<CPUNode>}
114
143
  */
115
144
  static getCPUNodes(mainThreadEvents) {
@@ -117,14 +146,14 @@ class PageDependencyGraph {
117
146
  const nodes = [];
118
147
  let i = 0;
119
148
 
120
- TraceProcessor.assertHasToplevelEvents(mainThreadEvents);
149
+ PageDependencyGraph.assertHasToplevelEvents(mainThreadEvents);
121
150
 
122
151
  while (i < mainThreadEvents.length) {
123
152
  const evt = mainThreadEvents[i];
124
153
  i++;
125
154
 
126
155
  // Skip all trace events that aren't schedulable tasks with sizable duration
127
- if (!TraceProcessor.isScheduleableTask(evt) || !evt.dur) {
156
+ if (!PageDependencyGraph.isScheduleableTask(evt) || !evt.dur) {
128
157
  continue;
129
158
  }
130
159
 
@@ -132,23 +161,25 @@ class PageDependencyGraph {
132
161
  let correctedEndTs = undefined;
133
162
 
134
163
  // Capture all events that occurred within the task
135
- /** @type {Array<LH.TraceEvent>} */
164
+ /** @type {Array<Lantern.TraceEvent>} */
136
165
  const children = [];
137
166
  for (
138
167
  const endTime = evt.ts + evt.dur;
139
168
  i < mainThreadEvents.length && mainThreadEvents[i].ts < endTime;
140
169
  i++
141
170
  ) {
171
+ const event = mainThreadEvents[i];
172
+
142
173
  // Temporary fix for a Chrome bug where some RunTask events can be overlapping.
143
174
  // We correct that here be ensuring each RunTask ends at least 1 microsecond before the next
144
175
  // https://github.com/GoogleChrome/lighthouse/issues/15896
145
176
  // https://issues.chromium.org/issues/329678173
146
- if (TraceProcessor.isScheduleableTask(mainThreadEvents[i]) && mainThreadEvents[i].dur) {
147
- correctedEndTs = mainThreadEvents[i].ts - 1;
177
+ if (PageDependencyGraph.isScheduleableTask(event) && event.dur) {
178
+ correctedEndTs = event.ts - 1;
148
179
  break;
149
180
  }
150
181
 
151
- children.push(mainThreadEvents[i]);
182
+ children.push(event);
152
183
  }
153
184
 
154
185
  nodes.push(new CPUNode(evt, children, correctedEndTs));
@@ -210,9 +241,11 @@ class PageDependencyGraph {
210
241
  * @param {Array<CPUNode>} cpuNodes
211
242
  */
212
243
  static linkCPUNodes(rootNode, networkNodeOutput, cpuNodes) {
213
- /** @type {Set<LH.Crdp.Network.ResourceType|undefined>} */
244
+ /** @type {Set<Lantern.ResourceType|undefined>} */
214
245
  const linkableResourceTypes = new Set([
215
- NetworkRequestTypes.XHR, NetworkRequestTypes.Fetch, NetworkRequestTypes.Script,
246
+ Lantern.NetworkRequestTypes.XHR,
247
+ Lantern.NetworkRequestTypes.Fetch,
248
+ Lantern.NetworkRequestTypes.Script,
216
249
  ]);
217
250
 
218
251
  /** @param {CPUNode} cpuNode @param {string} reqId */
@@ -405,25 +438,128 @@ class PageDependencyGraph {
405
438
  }
406
439
 
407
440
  /**
408
- * @param {LH.TraceEvent[]} mainThreadEvents
409
- * @param {Array<Lantern.NetworkRequest>} networkRecords
410
- * @param {URLArtifact} URL
441
+ * TODO(15841): remove when CDT backend is gone. until then, this is a useful debugging tool
442
+ * to find delta between using CDP or the trace to create the network requests.
443
+ *
444
+ * When a test fails using the trace backend, I enabled this debug method and copied the network
445
+ * requests when CDP was used, then when trace is used, and diff'd them. This method helped
446
+ * remove non-logical differences from the comparison (order of properties, slight rounding
447
+ * discrepancies, removing object cycles, etc).
448
+ *
449
+ * When using for a unit test, make sure to do `.only` so you are getting what you expect.
450
+ * @param {Lantern.NetworkRequest[]} lanternRequests
451
+ * @return {never}
452
+ */
453
+ static _debugNormalizeRequests(lanternRequests) {
454
+ for (const request of lanternRequests) {
455
+ request.rendererStartTime = Math.round(request.rendererStartTime * 1000) / 1000;
456
+ request.networkRequestTime = Math.round(request.networkRequestTime * 1000) / 1000;
457
+ request.responseHeadersEndTime = Math.round(request.responseHeadersEndTime * 1000) / 1000;
458
+ request.networkEndTime = Math.round(request.networkEndTime * 1000) / 1000;
459
+ }
460
+
461
+ for (const r of lanternRequests) {
462
+ delete r.rawRequest;
463
+ if (r.initiatorRequest) {
464
+ // @ts-expect-error
465
+ r.initiatorRequest = {id: r.initiatorRequest.requestId};
466
+ }
467
+ if (r.redirectDestination) {
468
+ // @ts-expect-error
469
+ r.redirectDestination = {id: r.redirectDestination.requestId};
470
+ }
471
+ if (r.redirectSource) {
472
+ // @ts-expect-error
473
+ r.redirectSource = {id: r.redirectSource.requestId};
474
+ }
475
+ if (r.redirects) {
476
+ // @ts-expect-error
477
+ r.redirects = r.redirects.map(r2 => r2.requestId);
478
+ }
479
+ }
480
+ /** @type {Lantern.NetworkRequest[]} */
481
+ const requests = lanternRequests.map(r => ({
482
+ requestId: r.requestId,
483
+ connectionId: r.connectionId,
484
+ connectionReused: r.connectionReused,
485
+ url: r.url,
486
+ protocol: r.protocol,
487
+ parsedURL: r.parsedURL,
488
+ documentURL: r.documentURL,
489
+ rendererStartTime: r.rendererStartTime,
490
+ networkRequestTime: r.networkRequestTime,
491
+ responseHeadersEndTime: r.responseHeadersEndTime,
492
+ networkEndTime: r.networkEndTime,
493
+ transferSize: r.transferSize,
494
+ resourceSize: r.resourceSize,
495
+ fromDiskCache: r.fromDiskCache,
496
+ fromMemoryCache: r.fromMemoryCache,
497
+ finished: r.finished,
498
+ statusCode: r.statusCode,
499
+ redirectSource: r.redirectSource,
500
+ redirectDestination: r.redirectDestination,
501
+ redirects: r.redirects,
502
+ failed: r.failed,
503
+ initiator: r.initiator,
504
+ timing: r.timing ? {
505
+ requestTime: r.timing.requestTime,
506
+ proxyStart: r.timing.proxyStart,
507
+ proxyEnd: r.timing.proxyEnd,
508
+ dnsStart: r.timing.dnsStart,
509
+ dnsEnd: r.timing.dnsEnd,
510
+ connectStart: r.timing.connectStart,
511
+ connectEnd: r.timing.connectEnd,
512
+ sslStart: r.timing.sslStart,
513
+ sslEnd: r.timing.sslEnd,
514
+ workerStart: r.timing.workerStart,
515
+ workerReady: r.timing.workerReady,
516
+ workerFetchStart: r.timing.workerFetchStart,
517
+ workerRespondWithSettled: r.timing.workerRespondWithSettled,
518
+ sendStart: r.timing.sendStart,
519
+ sendEnd: r.timing.sendEnd,
520
+ pushStart: r.timing.pushStart,
521
+ pushEnd: r.timing.pushEnd,
522
+ receiveHeadersStart: r.timing.receiveHeadersStart,
523
+ receiveHeadersEnd: r.timing.receiveHeadersEnd,
524
+ } : r.timing,
525
+ resourceType: r.resourceType,
526
+ mimeType: r.mimeType,
527
+ priority: r.priority,
528
+ initiatorRequest: r.initiatorRequest,
529
+ frameId: r.frameId,
530
+ fromWorker: r.fromWorker,
531
+ isLinkPreload: r.isLinkPreload,
532
+ serverResponseTime: r.serverResponseTime,
533
+ })).filter(r => !r.fromWorker);
534
+ // eslint-disable-next-line no-unused-vars
535
+ const debug = requests;
536
+ // Set breakpoint here.
537
+ // Copy `debug` and compare with https://www.diffchecker.com/text-compare/
538
+ process.exit(1);
539
+ }
540
+
541
+ /**
542
+ * @param {Lantern.TraceEvent[]} mainThreadEvents
543
+ * @param {Lantern.NetworkRequest[]} networkRequests
544
+ * @param {Lantern.Simulation.URL} URL
411
545
  * @return {Node}
412
546
  */
413
- static createGraph(mainThreadEvents, networkRecords, URL) {
414
- const networkNodeOutput = PageDependencyGraph.getNetworkNodeOutput(networkRecords);
547
+ static createGraph(mainThreadEvents, networkRequests, URL) {
548
+ // This is for debugging trace/devtoolslog network records.
549
+ // const debug = PageDependencyGraph._debugNormalizeRequests(networkRequests);
550
+ const networkNodeOutput = PageDependencyGraph.getNetworkNodeOutput(networkRequests);
415
551
  const cpuNodes = PageDependencyGraph.getCPUNodes(mainThreadEvents);
416
552
  const {requestedUrl, mainDocumentUrl} = URL;
417
553
  if (!requestedUrl) throw new Error('requestedUrl is required to get the root request');
418
554
  if (!mainDocumentUrl) throw new Error('mainDocumentUrl is required to get the main resource');
419
555
 
420
- const rootRequest = NetworkAnalyzer.findResourceForUrl(networkRecords, requestedUrl);
556
+ const rootRequest =
557
+ Lantern.Simulation.NetworkAnalyzer.findResourceForUrl(networkRequests, requestedUrl);
421
558
  if (!rootRequest) throw new Error('rootRequest not found');
422
559
  const rootNode = networkNodeOutput.idToNodeMap.get(rootRequest.requestId);
423
560
  if (!rootNode) throw new Error('rootNode not found');
424
-
425
561
  const mainDocumentRequest =
426
- NetworkAnalyzer.findLastDocumentForUrl(networkRecords, mainDocumentUrl);
562
+ Lantern.Simulation.NetworkAnalyzer.findLastDocumentForUrl(networkRequests, mainDocumentUrl);
427
563
  if (!mainDocumentRequest) throw new Error('mainDocumentRequest not found');
428
564
  const mainDocumentNode = networkNodeOutput.idToNodeMap.get(mainDocumentRequest.requestId);
429
565
  if (!mainDocumentNode) throw new Error('mainDocumentNode not found');
@@ -440,7 +576,6 @@ class PageDependencyGraph {
440
576
  }
441
577
 
442
578
  /**
443
- *
444
579
  * @param {Node} rootNode
445
580
  */
446
581
  static printGraph(rootNode, widthInCharacters = 100) {