lighthouse 11.6.0 → 11.7.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 (141) hide show
  1. package/cli/test/smokehouse/core-tests.js +2 -2
  2. package/core/audits/byte-efficiency/byte-efficiency-audit.d.ts +2 -2
  3. package/core/audits/byte-efficiency/byte-efficiency-audit.js +7 -7
  4. package/core/audits/byte-efficiency/render-blocking-resources.d.ts +4 -3
  5. package/core/audits/byte-efficiency/render-blocking-resources.js +6 -6
  6. package/core/audits/dobetterweb/uses-http2.d.ts +3 -3
  7. package/core/audits/dobetterweb/uses-http2.js +4 -4
  8. package/core/audits/installable-manifest.d.ts +2 -0
  9. package/core/audits/installable-manifest.js +2 -0
  10. package/core/audits/metrics/interaction-to-next-paint.js +1 -3
  11. package/core/audits/prioritize-lcp-image.d.ts +1 -1
  12. package/core/audits/work-during-interaction.js +0 -8
  13. package/core/computed/document-urls.js +1 -1
  14. package/core/computed/load-simulator.d.ts +2 -2
  15. package/core/computed/load-simulator.js +3 -2
  16. package/core/computed/main-resource.js +1 -1
  17. package/core/computed/metrics/lantern-first-contentful-paint.d.ts +18 -6
  18. package/core/computed/metrics/lantern-first-contentful-paint.js +4 -4
  19. package/core/computed/metrics/lantern-first-meaningful-paint.d.ts +14 -2
  20. package/core/computed/metrics/lantern-first-meaningful-paint.js +1 -1
  21. package/core/computed/metrics/lantern-interactive.d.ts +8 -6
  22. package/core/computed/metrics/lantern-interactive.js +3 -3
  23. package/core/computed/metrics/lantern-largest-contentful-paint.d.ts +14 -2
  24. package/core/computed/metrics/lantern-largest-contentful-paint.js +1 -1
  25. package/core/computed/metrics/lantern-max-potential-fid.d.ts +8 -2
  26. package/core/computed/metrics/lantern-max-potential-fid.js +3 -3
  27. package/core/computed/metrics/lantern-metric.d.ts +4 -63
  28. package/core/computed/metrics/lantern-metric.js +6 -124
  29. package/core/computed/metrics/lantern-speed-index.d.ts +8 -2
  30. package/core/computed/metrics/lantern-speed-index.js +3 -3
  31. package/core/computed/metrics/lantern-total-blocking-time.d.ts +8 -2
  32. package/core/computed/metrics/lantern-total-blocking-time.js +3 -3
  33. package/core/computed/metrics/responsiveness.d.ts +5 -13
  34. package/core/computed/metrics/responsiveness.js +10 -14
  35. package/core/computed/network-analysis.js +1 -1
  36. package/core/computed/page-dependency-graph.d.ts +4 -57
  37. package/core/computed/page-dependency-graph.js +4 -451
  38. package/core/config/config-helpers.js +1 -1
  39. package/core/gather/driver/execution-context.d.ts +2 -1
  40. package/core/gather/driver/execution-context.js +9 -9
  41. package/core/gather/driver/wait-for-condition.js +4 -2
  42. package/core/gather/gatherers/accessibility.js +2 -1
  43. package/core/gather/gatherers/css-usage.d.ts +1 -9
  44. package/core/gather/gatherers/css-usage.js +23 -25
  45. package/core/gather/gatherers/devtools-log.d.ts +4 -0
  46. package/core/gather/gatherers/devtools-log.js +7 -0
  47. package/core/gather/gatherers/full-page-screenshot.d.ts +4 -0
  48. package/core/gather/gatherers/full-page-screenshot.js +31 -35
  49. package/core/gather/gatherers/root-causes.js +1 -3
  50. package/core/gather/gatherers/trace-elements.js +1 -1
  51. package/core/gather/gatherers/trace.d.ts +1 -0
  52. package/core/gather/gatherers/trace.js +4 -0
  53. package/core/gather/navigation-runner.js +49 -62
  54. package/core/gather/session.js +5 -0
  55. package/core/gather/snapshot-runner.js +25 -25
  56. package/core/gather/timespan-runner.js +24 -25
  57. package/core/lib/asset-saver.js +1 -1
  58. package/core/lib/emulation.js +0 -3
  59. package/core/lib/{dependency-graph → lantern}/base-node.d.ts +12 -8
  60. package/core/lib/{dependency-graph → lantern}/base-node.js +8 -3
  61. package/core/lib/{dependency-graph → lantern}/cpu-node.d.ts +5 -1
  62. package/core/lib/{dependency-graph → lantern}/cpu-node.js +4 -0
  63. package/core/lib/lantern/lantern.d.ts +8 -0
  64. package/core/lib/lantern/lantern.js +31 -0
  65. package/core/lib/lantern/metric.d.ts +71 -0
  66. package/core/lib/lantern/metric.js +143 -0
  67. package/core/lib/{dependency-graph → lantern}/network-node.d.ts +17 -10
  68. package/core/lib/lantern/network-node.js +114 -0
  69. package/core/lib/lantern/page-dependency-graph.d.ts +58 -0
  70. package/core/lib/lantern/page-dependency-graph.js +463 -0
  71. package/core/lib/{dependency-graph → lantern}/simulator/connection-pool.d.ts +14 -14
  72. package/core/lib/{dependency-graph → lantern}/simulator/connection-pool.js +7 -7
  73. package/core/lib/{dependency-graph → lantern}/simulator/dns-cache.d.ts +5 -5
  74. package/core/lib/{dependency-graph → lantern}/simulator/dns-cache.js +3 -3
  75. package/core/lib/{dependency-graph → lantern}/simulator/network-analyzer.d.ts +36 -32
  76. package/core/lib/{dependency-graph → lantern}/simulator/network-analyzer.js +21 -17
  77. package/core/lib/{dependency-graph → lantern}/simulator/simulator.d.ts +18 -15
  78. package/core/lib/{dependency-graph → lantern}/simulator/simulator.js +18 -15
  79. package/core/lib/lantern/types/lantern.d.ts +129 -0
  80. package/core/lib/lantern/types/lantern.js +7 -0
  81. package/core/lib/lantern-trace-saver.d.ts +4 -4
  82. package/core/lib/lantern-trace-saver.js +6 -4
  83. package/core/lib/navigation-error.js +1 -1
  84. package/core/lib/network-recorder.js +2 -2
  85. package/core/lib/network-request.d.ts +6 -0
  86. package/core/lib/network-request.js +12 -0
  87. package/package.json +4 -5
  88. package/shared/localization/locales/ar-XB.json +1 -1
  89. package/shared/localization/locales/ar.json +1 -1
  90. package/shared/localization/locales/bg.json +1 -1
  91. package/shared/localization/locales/ca.json +1 -1
  92. package/shared/localization/locales/cs.json +1 -1
  93. package/shared/localization/locales/da.json +2 -2
  94. package/shared/localization/locales/de.json +1 -1
  95. package/shared/localization/locales/el.json +1 -1
  96. package/shared/localization/locales/en-GB.json +1 -1
  97. package/shared/localization/locales/en-US.json +3 -0
  98. package/shared/localization/locales/en-XA.json +1 -1
  99. package/shared/localization/locales/en-XL.json +3 -0
  100. package/shared/localization/locales/es-419.json +1 -1
  101. package/shared/localization/locales/es.json +1 -1
  102. package/shared/localization/locales/fi.json +1 -1
  103. package/shared/localization/locales/fil.json +1 -1
  104. package/shared/localization/locales/he.json +1 -1
  105. package/shared/localization/locales/hi.json +1 -1
  106. package/shared/localization/locales/hr.json +1 -1
  107. package/shared/localization/locales/hu.json +1 -1
  108. package/shared/localization/locales/id.json +1 -1
  109. package/shared/localization/locales/it.json +1 -1
  110. package/shared/localization/locales/ko.json +1 -1
  111. package/shared/localization/locales/lt.json +1 -1
  112. package/shared/localization/locales/nl.json +1 -1
  113. package/shared/localization/locales/no.json +1 -1
  114. package/shared/localization/locales/pl.json +1 -1
  115. package/shared/localization/locales/pt-PT.json +1 -1
  116. package/shared/localization/locales/pt.json +1 -1
  117. package/shared/localization/locales/ro.json +1 -1
  118. package/shared/localization/locales/sk.json +1 -1
  119. package/shared/localization/locales/sl.json +1 -1
  120. package/shared/localization/locales/sr-Latn.json +1 -1
  121. package/shared/localization/locales/sr.json +1 -1
  122. package/shared/localization/locales/sv.json +1 -1
  123. package/shared/localization/locales/ta.json +1 -1
  124. package/shared/localization/locales/te.json +1 -1
  125. package/shared/localization/locales/th.json +4 -4
  126. package/shared/localization/locales/tr.json +1 -1
  127. package/shared/localization/locales/uk.json +1 -1
  128. package/shared/localization/locales/vi.json +1 -1
  129. package/shared/localization/locales/zh-HK.json +1 -1
  130. package/shared/localization/locales/zh-TW.json +1 -1
  131. package/shared/localization/locales/zh.json +1 -1
  132. package/third-party/chromium-synchronization/installability-errors-test.js +1 -1
  133. package/tsconfig.json +7 -5
  134. package/types/artifacts.d.ts +1 -1
  135. package/types/gatherer.d.ts +8 -35
  136. package/types/lhr/lhr.d.ts +1 -1
  137. package/core/lib/dependency-graph/network-node.js +0 -99
  138. /package/core/lib/{dependency-graph → lantern}/simulator/simulator-timing-map.d.ts +0 -0
  139. /package/core/lib/{dependency-graph → lantern}/simulator/simulator-timing-map.js +0 -0
  140. /package/core/lib/{dependency-graph → lantern}/simulator/tcp-connection.d.ts +0 -0
  141. /package/core/lib/{dependency-graph → lantern}/simulator/tcp-connection.js +0 -0
@@ -12,6 +12,10 @@ declare class DevtoolsLog extends BaseGatherer {
12
12
  * @param {LH.Gatherer.Context} passContext
13
13
  */
14
14
  stopSensitiveInstrumentation({ driver }: LH.Gatherer.Context): Promise<void>;
15
+ /**
16
+ * @return {LH.Artifacts['DevtoolsLog']}
17
+ */
18
+ getDebugData(): LH.Artifacts['DevtoolsLog'];
15
19
  /**
16
20
  * @return {Promise<LH.Artifacts['DevtoolsLog']>}
17
21
  */
@@ -49,6 +49,13 @@ class DevtoolsLog extends BaseGatherer {
49
49
  driver.targetManager.off('protocolevent', this._onProtocolMessage);
50
50
  }
51
51
 
52
+ /**
53
+ * @return {LH.Artifacts['DevtoolsLog']}
54
+ */
55
+ getDebugData() {
56
+ return this._messageLog.messages;
57
+ }
58
+
52
59
  /**
53
60
  * @return {Promise<LH.Artifacts['DevtoolsLog']>}
54
61
  */
@@ -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,19 @@ class FullPageScreenshot extends BaseGatherer {
120
119
  * @return {Promise<LH.Result.FullPageScreenshot['screenshot']>}
121
120
  */
122
121
  async _takeScreenshot(context) {
123
- const result = await context.driver.defaultSession.sendCommand('Page.captureScreenshot', {
124
- format: 'webp',
125
- quality: FULL_PAGE_SCREENSHOT_QUALITY,
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
- });
122
+ const [metrics, result] = await Promise.all([
123
+ context.driver.defaultSession.sendCommand('Page.getLayoutMetrics'),
124
+ context.driver.defaultSession.sendCommand('Page.captureScreenshot', {
125
+ format: FULL_PAGE_SCREENSHOT_FORMAT,
126
+ quality: FULL_PAGE_SCREENSHOT_QUALITY,
127
+ }),
128
+ ]);
129
+ const data = `data:image/${FULL_PAGE_SCREENSHOT_FORMAT};base64,` + result.data;
134
130
 
135
131
  return {
136
132
  data,
137
- width: screenshotAreaSize.width,
138
- height: screenshotAreaSize.height,
133
+ width: metrics.cssVisualViewport.clientWidth,
134
+ height: metrics.cssVisualViewport.clientHeight,
139
135
  };
140
136
  }
141
137
 
@@ -159,7 +155,7 @@ class FullPageScreenshot extends BaseGatherer {
159
155
  for (const [node, id] of lhIdToElements.entries()) {
160
156
  // @ts-expect-error - getBoundingClientRect put into scope via stringification
161
157
  const rect = getBoundingClientRect(node);
162
- nodes[id] = rect;
158
+ nodes[id] = {id: node.id, ...rect};
163
159
  }
164
160
 
165
161
  return nodes;
@@ -124,9 +124,7 @@ class RootCauses extends BaseGatherer {
124
124
  rootCauses.layoutShifts[layoutShiftEvents.indexOf(event)] = r;
125
125
  }
126
126
 
127
- // Yeah this gatherer enabled it, and so you'd think it should disable it too...
128
- // ...but we don't give gatherers their own session so this stomps on others.
129
- // await driver.defaultSession.sendCommand('DOM.disable');
127
+ await driver.defaultSession.sendCommand('DOM.disable');
130
128
  await driver.defaultSession.sendCommand('CSS.disable');
131
129
 
132
130
  return rootCauses;
@@ -155,7 +155,7 @@ class TraceElements extends BaseGatherer {
155
155
  const {settings} = context;
156
156
  try {
157
157
  const responsivenessEvent = await Responsiveness.request({trace, settings}, context);
158
- if (!responsivenessEvent || responsivenessEvent.name === 'FallbackTiming') return;
158
+ if (!responsivenessEvent) return;
159
159
  return {nodeId: responsivenessEvent.args.data.nodeId};
160
160
  } catch {
161
161
  // Don't let responsiveness errors sink the rest of the gatherer.
@@ -17,6 +17,7 @@ declare class Trace extends BaseGatherer {
17
17
  * @param {LH.Gatherer.Context} passContext
18
18
  */
19
19
  stopSensitiveInstrumentation({ driver }: LH.Gatherer.Context): Promise<void>;
20
+ getDebugData(): import("../../index.js").Trace;
20
21
  getArtifact(): import("../../index.js").Trace;
21
22
  }
22
23
  import BaseGatherer from '../base-gatherer.js';
@@ -126,6 +126,10 @@ class Trace extends BaseGatherer {
126
126
  this._trace = await Trace.endTraceAndCollectEvents(driver.defaultSession);
127
127
  }
128
128
 
129
+ getDebugData() {
130
+ return this._trace;
131
+ }
132
+
129
133
  getArtifact() {
130
134
  return this._trace;
131
135
  }
@@ -110,31 +110,19 @@ async function _navigate(navigationContext) {
110
110
  * @return {Promise<{devtoolsLog?: LH.DevtoolsLog, records?: Array<LH.Artifacts.NetworkRequest>, trace?: LH.Trace}>}
111
111
  */
112
112
  async function _collectDebugData(navigationContext, phaseState) {
113
- const devtoolsLogArtifactDefn = phaseState.artifactDefinitions.find(
114
- definition => definition.gatherer.instance.meta.symbol === DevtoolsLog.symbol
115
- );
116
- const traceArtifactDefn = phaseState.artifactDefinitions.find(
117
- definition => definition.gatherer.instance.meta.symbol === Trace.symbol
118
- );
119
-
120
- const artifactDefinitions = [devtoolsLogArtifactDefn, traceArtifactDefn].filter(
121
- /**
122
- * @param {LH.Config.AnyArtifactDefn | undefined} defn
123
- * @return {defn is LH.Config.AnyArtifactDefn}
124
- */
125
- defn => Boolean(defn)
126
- );
127
- if (!artifactDefinitions.length) return {};
128
-
129
- await collectPhaseArtifacts({...phaseState, phase: 'getArtifact', artifactDefinitions});
130
- const getArtifactState = phaseState.artifactState.getArtifact;
131
-
132
- const devtoolsLogArtifactId = devtoolsLogArtifactDefn?.id;
133
- const devtoolsLog = devtoolsLogArtifactId && (await getArtifactState[devtoolsLogArtifactId]);
134
- const records = devtoolsLog && (await NetworkRecords.request(devtoolsLog, navigationContext));
113
+ let devtoolsLog;
114
+ let trace;
115
+
116
+ for (const definition of phaseState.artifactDefinitions) {
117
+ const {instance} = definition.gatherer;
118
+ if (instance instanceof DevtoolsLog) {
119
+ devtoolsLog = instance.getDebugData();
120
+ } else if (instance instanceof Trace) {
121
+ trace = instance.getDebugData();
122
+ }
123
+ }
135
124
 
136
- const traceArtifactId = traceArtifactDefn?.id;
137
- const trace = traceArtifactId && (await getArtifactState[traceArtifactId]);
125
+ const records = devtoolsLog && (await NetworkRecords.request(devtoolsLog, navigationContext));
138
126
 
139
127
  return {devtoolsLog, records, trace};
140
128
  }
@@ -277,44 +265,43 @@ async function navigationGather(page, requestor, options = {}) {
277
265
  const isCallback = typeof requestor === 'function';
278
266
 
279
267
  const runnerOptions = {resolvedConfig, computedCache};
280
- const artifacts = await Runner.gather(
281
- async () => {
282
- const normalizedRequestor = isCallback ? requestor : UrlUtils.normalizeUrl(requestor);
283
-
284
- /** @type {LH.Puppeteer.Browser|undefined} */
285
- let lhBrowser = undefined;
286
- /** @type {LH.Puppeteer.Page|undefined} */
287
- let lhPage = undefined;
288
-
289
- // For navigation mode, we shouldn't connect to a browser in audit mode,
290
- // therefore we connect to the browser in the gatherFn callback.
291
- if (!page) {
292
- const {hostname = DEFAULT_HOSTNAME, port = DEFAULT_PORT} = flags;
293
- lhBrowser = await puppeteer.connect({browserURL: `http://${hostname}:${port}`, defaultViewport: null});
294
- lhPage = await lhBrowser.newPage();
295
- page = lhPage;
296
- }
297
-
298
- const driver = new Driver(page);
299
- const context = {
300
- driver,
301
- lhBrowser,
302
- lhPage,
303
- page,
304
- resolvedConfig,
305
- requestor: normalizedRequestor,
306
- computedCache,
307
- };
308
- const {baseArtifacts} = await _setup(context);
309
-
310
- const artifacts = await _navigation({...context, baseArtifacts});
311
-
312
- await _cleanup(context);
313
-
314
- return finalizeArtifacts(baseArtifacts, artifacts);
315
- },
316
- runnerOptions
317
- );
268
+
269
+ const gatherFn = async () => {
270
+ const normalizedRequestor = isCallback ? requestor : UrlUtils.normalizeUrl(requestor);
271
+
272
+ /** @type {LH.Puppeteer.Browser|undefined} */
273
+ let lhBrowser = undefined;
274
+ /** @type {LH.Puppeteer.Page|undefined} */
275
+ let lhPage = undefined;
276
+
277
+ // For navigation mode, we shouldn't connect to a browser in audit mode,
278
+ // therefore we connect to the browser in the gatherFn callback.
279
+ if (!page) {
280
+ const {hostname = DEFAULT_HOSTNAME, port = DEFAULT_PORT} = flags;
281
+ lhBrowser = await puppeteer.connect({browserURL: `http://${hostname}:${port}`, defaultViewport: null});
282
+ lhPage = await lhBrowser.newPage();
283
+ page = lhPage;
284
+ }
285
+
286
+ const driver = new Driver(page);
287
+ const context = {
288
+ driver,
289
+ lhBrowser,
290
+ lhPage,
291
+ page,
292
+ resolvedConfig,
293
+ requestor: normalizedRequestor,
294
+ computedCache,
295
+ };
296
+ const {baseArtifacts} = await _setup(context);
297
+
298
+ const artifacts = await _navigation({...context, baseArtifacts});
299
+
300
+ await _cleanup(context);
301
+
302
+ return finalizeArtifacts(baseArtifacts, artifacts);
303
+ };
304
+ const artifacts = await Runner.gather(gatherFn, runnerOptions);
318
305
  return {artifacts, runnerOptions};
319
306
  }
320
307
 
@@ -6,6 +6,8 @@
6
6
 
7
7
  import EventEmitter from 'events';
8
8
 
9
+ import log from 'lighthouse-logger';
10
+
9
11
  import {LighthouseError} from '../lib/lh-error.js';
10
12
 
11
13
  // Controls how long to wait for a response after sending a DevTools protocol command.
@@ -107,6 +109,9 @@ class ProtocolSession extends CrdpEventEmitter {
107
109
  const resultPromise = this._cdpSession.send(method, ...params, {
108
110
  // Add 50ms to the Puppeteer timeout to ensure the Lighthouse timeout finishes first.
109
111
  timeout: timeoutMs + PPTR_BUFFER,
112
+ }).catch((error) => {
113
+ log.formatProtocol('method <= browser ERR', {method}, 'error');
114
+ throw LighthouseError.fromProtocolMessage(method, error);
110
115
  });
111
116
  const resultWithTimeoutPromise = Promise.race([resultPromise, timeoutPromise]);
112
117
 
@@ -30,35 +30,35 @@ async function snapshotGather(page, options = {}) {
30
30
  const url = await driver.url();
31
31
 
32
32
  const runnerOptions = {resolvedConfig, computedCache};
33
- const artifacts = await Runner.gather(
34
- async () => {
35
- const baseArtifacts =
33
+
34
+ const gatherFn = async () => {
35
+ const baseArtifacts =
36
36
  await getBaseArtifacts(resolvedConfig, driver, {gatherMode: 'snapshot'});
37
- baseArtifacts.URL = {
38
- finalDisplayedUrl: url,
39
- };
37
+ baseArtifacts.URL = {
38
+ finalDisplayedUrl: url,
39
+ };
40
+
41
+ const artifactDefinitions = resolvedConfig.artifacts || [];
42
+ const artifactState = getEmptyArtifactState();
43
+ await collectPhaseArtifacts({
44
+ phase: 'getArtifact',
45
+ gatherMode: 'snapshot',
46
+ driver,
47
+ page,
48
+ baseArtifacts,
49
+ artifactDefinitions,
50
+ artifactState,
51
+ computedCache,
52
+ settings: resolvedConfig.settings,
53
+ });
40
54
 
41
- const artifactDefinitions = resolvedConfig.artifacts || [];
42
- const artifactState = getEmptyArtifactState();
43
- await collectPhaseArtifacts({
44
- phase: 'getArtifact',
45
- gatherMode: 'snapshot',
46
- driver,
47
- page,
48
- baseArtifacts,
49
- artifactDefinitions,
50
- artifactState,
51
- computedCache,
52
- settings: resolvedConfig.settings,
53
- });
55
+ await driver.disconnect();
54
56
 
55
- await driver.disconnect();
57
+ const artifacts = await awaitArtifacts(artifactState);
58
+ return finalizeArtifacts(baseArtifacts, artifacts);
59
+ };
56
60
 
57
- const artifacts = await awaitArtifacts(artifactState);
58
- return finalizeArtifacts(baseArtifacts, artifacts);
59
- },
60
- runnerOptions
61
- );
61
+ const artifacts = await Runner.gather(gatherFn, runnerOptions);
62
62
  return {artifacts, runnerOptions};
63
63
  }
64
64
 
@@ -72,31 +72,30 @@ async function startTimespanGather(page, options = {}) {
72
72
  const finalDisplayedUrl = await driver.url();
73
73
 
74
74
  const runnerOptions = {resolvedConfig, computedCache};
75
- const artifacts = await Runner.gather(
76
- async () => {
77
- baseArtifacts.URL = {finalDisplayedUrl};
78
-
79
- await collectPhaseArtifacts({phase: 'stopSensitiveInstrumentation', ...phaseOptions});
80
- await collectPhaseArtifacts({phase: 'stopInstrumentation', ...phaseOptions});
81
-
82
- // bf-cache-failures can emit `Page.frameNavigated` at the end of the run.
83
- // This can cause us to issue protocol commands after the target closes.
84
- // We should disable our `Page.frameNavigated` handlers before that.
85
- await disableAsyncStacks();
86
-
87
- driver.defaultSession.off('Page.frameNavigated', onFrameNavigated);
88
- if (pageNavigationDetected) {
89
- baseArtifacts.LighthouseRunWarnings.push(str_(UIStrings.warningNavigationDetected));
90
- }
91
-
92
- await collectPhaseArtifacts({phase: 'getArtifact', ...phaseOptions});
93
- await driver.disconnect();
94
-
95
- const artifacts = await awaitArtifacts(artifactState);
96
- return finalizeArtifacts(baseArtifacts, artifacts);
97
- },
98
- runnerOptions
99
- );
75
+ const gatherFn = async () => {
76
+ baseArtifacts.URL = {finalDisplayedUrl};
77
+
78
+ await collectPhaseArtifacts({phase: 'stopSensitiveInstrumentation', ...phaseOptions});
79
+ await collectPhaseArtifacts({phase: 'stopInstrumentation', ...phaseOptions});
80
+
81
+ // bf-cache-failures can emit `Page.frameNavigated` at the end of the run.
82
+ // This can cause us to issue protocol commands after the target closes.
83
+ // We should disable our `Page.frameNavigated` handlers before that.
84
+ await disableAsyncStacks();
85
+
86
+ driver.defaultSession.off('Page.frameNavigated', onFrameNavigated);
87
+ if (pageNavigationDetected) {
88
+ baseArtifacts.LighthouseRunWarnings.push(str_(UIStrings.warningNavigationDetected));
89
+ }
90
+
91
+ await collectPhaseArtifacts({phase: 'getArtifact', ...phaseOptions});
92
+ await driver.disconnect();
93
+
94
+ const artifacts = await awaitArtifacts(artifactState);
95
+ return finalizeArtifacts(baseArtifacts, artifacts);
96
+ };
97
+
98
+ const artifacts = await Runner.gather(gatherFn, runnerOptions);
100
99
  return {artifacts, runnerOptions};
101
100
  },
102
101
  };
@@ -11,7 +11,7 @@ import url from 'url';
11
11
 
12
12
  import log from 'lighthouse-logger';
13
13
 
14
- import {Simulator} from './dependency-graph/simulator/simulator.js';
14
+ import {Simulator} from './lantern/simulator/simulator.js';
15
15
  import lanternTraceSaver from './lantern-trace-saver.js';
16
16
  import {MetricTraceEvents} from './traces/metric-trace-events.js';
17
17
  import {NetworkAnalysis} from '../computed/network-analysis.js';
@@ -4,8 +4,6 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- import {lighthouseVersion} from '../../shared/root.js';
8
-
9
7
  const NO_THROTTLING_METRICS = {
10
8
  latency: 0,
11
9
  downloadThroughput: 0,
@@ -29,7 +27,6 @@ function parseUseragentIntoMetadata(userAgent, formFactor) {
29
27
  const brands = [
30
28
  {brand: 'Chromium', version},
31
29
  {brand: 'Google Chrome', version},
32
- {brand: 'Lighthouse', version: lighthouseVersion},
33
30
  ];
34
31
 
35
32
  const motoGPowerDetails = {
@@ -2,7 +2,7 @@
2
2
  * A union of all types derived from BaseNode, allowing type check discrimination
3
3
  * based on `node.type`. If a new node type is created, it should be added here.
4
4
  */
5
- export type Node = import('./cpu-node.js').CPUNode | import('./network-node.js').NetworkNode;
5
+ export type Node<T = any> = import('./cpu-node.js').CPUNode<T> | import('./network-node.js').NetworkNode<T>;
6
6
  /**
7
7
  * @license
8
8
  * Copyright 2017 Google LLC
@@ -11,7 +11,8 @@ export type Node = import('./cpu-node.js').CPUNode | import('./network-node.js')
11
11
  /**
12
12
  * A union of all types derived from BaseNode, allowing type check discrimination
13
13
  * based on `node.type`. If a new node type is created, it should be added here.
14
- * @typedef {import('./cpu-node.js').CPUNode | import('./network-node.js').NetworkNode} Node
14
+ * @template [T=any]
15
+ * @typedef {import('./cpu-node.js').CPUNode<T> | import('./network-node.js').NetworkNode<T>} Node
15
16
  */
16
17
  /**
17
18
  * @fileoverview This class encapsulates logic for handling resources and tasks used to model the
@@ -25,7 +26,10 @@ export type Node = import('./cpu-node.js').CPUNode | import('./network-node.js')
25
26
  * This allows particular optimizations in this class so that we do no need to check for cycles as
26
27
  * these methods are called and we can always start traversal at the root node.
27
28
  */
28
- export class BaseNode {
29
+ /**
30
+ * @template [T=any]
31
+ */
32
+ export class BaseNode<T = any> {
29
33
  /**
30
34
  * Returns whether the given node has a cycle in its dependent graph by performing a DFS.
31
35
  * @param {Node} node
@@ -134,17 +138,17 @@ export class BaseNode {
134
138
  *
135
139
  * The `getNextNodes` function takes a visited node and returns which nodes to
136
140
  * visit next. It defaults to returning the node's dependents.
137
- * @param {(node: Node, traversalPath: Node[]) => void} callback
138
- * @param {function(Node): Node[]} [getNextNodes]
141
+ * @param {(node: Node<T>, traversalPath: Node<T>[]) => void} callback
142
+ * @param {function(Node<T>): Node<T>[]} [getNextNodes]
139
143
  */
140
- traverse(callback: (node: Node, traversalPath: Node[]) => void, getNextNodes?: ((arg0: Node) => Node[]) | undefined): void;
144
+ traverse(callback: (node: Node<T>, traversalPath: Node<T>[]) => void, getNextNodes?: ((arg0: Node<T>) => Node<T>[]) | undefined): void;
141
145
  /**
142
146
  * @see BaseNode.traverse
143
147
  * @param {function(Node): Node[]} [getNextNodes]
144
148
  */
145
149
  traverseGenerator(getNextNodes?: ((arg0: Node) => Node[]) | undefined): Generator<{
146
- node: Node;
147
- traversalPath: Node[];
150
+ node: Node<any>;
151
+ traversalPath: Node<any>[];
148
152
  }, void, unknown>;
149
153
  /**
150
154
  * @param {Node} node
@@ -7,7 +7,8 @@
7
7
  /**
8
8
  * A union of all types derived from BaseNode, allowing type check discrimination
9
9
  * based on `node.type`. If a new node type is created, it should be added here.
10
- * @typedef {import('./cpu-node.js').CPUNode | import('./network-node.js').NetworkNode} Node
10
+ * @template [T=any]
11
+ * @typedef {import('./cpu-node.js').CPUNode<T> | import('./network-node.js').NetworkNode<T>} Node
11
12
  */
12
13
 
13
14
  /**
@@ -22,6 +23,10 @@
22
23
  * This allows particular optimizations in this class so that we do no need to check for cycles as
23
24
  * these methods are called and we can always start traversal at the root node.
24
25
  */
26
+
27
+ /**
28
+ * @template [T=any]
29
+ */
25
30
  class BaseNode {
26
31
  /**
27
32
  * @param {string} id
@@ -256,8 +261,8 @@ class BaseNode {
256
261
  *
257
262
  * The `getNextNodes` function takes a visited node and returns which nodes to
258
263
  * visit next. It defaults to returning the node's dependents.
259
- * @param {(node: Node, traversalPath: Node[]) => void} callback
260
- * @param {function(Node): Node[]} [getNextNodes]
264
+ * @param {(node: Node<T>, traversalPath: Node<T>[]) => void} callback
265
+ * @param {function(Node<T>): Node<T>[]} [getNextNodes]
261
266
  */
262
267
  traverse(callback, getNextNodes) {
263
268
  for (const {node, traversalPath} of this.traverseGenerator(getNextNodes)) {
@@ -1,4 +1,8 @@
1
- export class CPUNode extends BaseNode {
1
+ /**
2
+ * @template [T=any]
3
+ * @extends {BaseNode<T>}
4
+ */
5
+ export class CPUNode<T = any> extends BaseNode<T> {
2
6
  /**
3
7
  * @param {LH.TraceEvent} parentEvent
4
8
  * @param {LH.TraceEvent[]=} childEvents
@@ -7,6 +7,10 @@
7
7
  import * as LH from '../../../types/lh.js';
8
8
  import {BaseNode} from './base-node.js';
9
9
 
10
+ /**
11
+ * @template [T=any]
12
+ * @extends {BaseNode<T>}
13
+ */
10
14
  class CPUNode extends BaseNode {
11
15
  /**
12
16
  * @param {LH.TraceEvent} parentEvent
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2024 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ /** @type {LH.Util.SelfMap<LH.Crdp.Network.ResourceType>} */
7
+ export const NetworkRequestTypes: LH.Util.SelfMap<LH.Crdp.Network.ResourceType>;
8
+ //# sourceMappingURL=lantern.d.ts.map
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2024 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ /** @type {LH.Util.SelfMap<LH.Crdp.Network.ResourceType>} */
8
+ const NetworkRequestTypes = {
9
+ XHR: 'XHR',
10
+ Fetch: 'Fetch',
11
+ EventSource: 'EventSource',
12
+ Script: 'Script',
13
+ Stylesheet: 'Stylesheet',
14
+ Image: 'Image',
15
+ Media: 'Media',
16
+ Font: 'Font',
17
+ Document: 'Document',
18
+ TextTrack: 'TextTrack',
19
+ WebSocket: 'WebSocket',
20
+ Other: 'Other',
21
+ Manifest: 'Manifest',
22
+ SignedExchange: 'SignedExchange',
23
+ Ping: 'Ping',
24
+ Preflight: 'Preflight',
25
+ CSPViolationReport: 'CSPViolationReport',
26
+ Prefetch: 'Prefetch',
27
+ };
28
+
29
+ export {
30
+ NetworkRequestTypes,
31
+ };