lighthouse 9.5.0-dev.20220607 → 9.6.2

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 (262) hide show
  1. package/dist/report/bundle.esm.js +467 -520
  2. package/dist/report/flow.js +22 -22
  3. package/dist/report/standalone.js +19 -19
  4. package/flow-report/src/summary/category.tsx +1 -1
  5. package/flow-report/src/topbar.tsx +2 -10
  6. package/flow-report/src/util.ts +1 -1
  7. package/flow-report/test/topbar-test.tsx +8 -7
  8. package/jest.config.js +1 -1
  9. package/lighthouse-cli/.eslintrc.cjs +4 -3
  10. package/lighthouse-cli/bin.js +1 -0
  11. package/lighthouse-cli/cli-flags.js +4 -3
  12. package/lighthouse-cli/commands/commands.js +1 -0
  13. package/lighthouse-cli/commands/list-audits.js +1 -0
  14. package/lighthouse-cli/commands/list-locales.js +1 -0
  15. package/lighthouse-cli/commands/list-trace-categories.js +1 -0
  16. package/lighthouse-cli/index.js +1 -0
  17. package/lighthouse-cli/printer.js +1 -0
  18. package/lighthouse-cli/run.js +24 -9
  19. package/lighthouse-cli/sentry-prompt.js +1 -0
  20. package/lighthouse-cli/test/smokehouse/core-tests.js +1 -0
  21. package/lighthouse-cli/test/smokehouse/frontends/back-compat-util.js +1 -0
  22. package/lighthouse-cli/test/smokehouse/frontends/lib.js +1 -0
  23. package/lighthouse-cli/test/smokehouse/frontends/node.js +1 -0
  24. package/lighthouse-cli/test/smokehouse/frontends/smokehouse-bin.js +1 -0
  25. package/lighthouse-cli/test/smokehouse/lib/child-process-error.js +1 -0
  26. package/lighthouse-cli/test/smokehouse/lib/concurrent-mapper.js +1 -0
  27. package/lighthouse-cli/test/smokehouse/lib/local-console.js +1 -0
  28. package/lighthouse-cli/test/smokehouse/lighthouse-runners/bundle.js +23 -109
  29. package/lighthouse-cli/test/smokehouse/lighthouse-runners/cli.js +3 -2
  30. package/lighthouse-cli/test/smokehouse/lighthouse-runners/devtools.js +19 -28
  31. package/lighthouse-cli/test/smokehouse/report-assert.js +4 -3
  32. package/lighthouse-cli/test/smokehouse/smokehouse.js +1 -1
  33. package/lighthouse-cli/test/smokehouse/version-check-test.js +3 -0
  34. package/lighthouse-cli/test/smokehouse/version-check.js +1 -0
  35. package/lighthouse-core/audits/accessibility/accesskeys.js +1 -1
  36. package/lighthouse-core/audits/accessibility/aria-allowed-attr.js +1 -1
  37. package/lighthouse-core/audits/accessibility/aria-command-name.js +1 -1
  38. package/lighthouse-core/audits/accessibility/aria-hidden-body.js +1 -1
  39. package/lighthouse-core/audits/accessibility/aria-hidden-focus.js +1 -1
  40. package/lighthouse-core/audits/accessibility/aria-input-field-name.js +1 -1
  41. package/lighthouse-core/audits/accessibility/aria-meter-name.js +1 -1
  42. package/lighthouse-core/audits/accessibility/aria-progressbar-name.js +1 -1
  43. package/lighthouse-core/audits/accessibility/aria-required-attr.js +1 -1
  44. package/lighthouse-core/audits/accessibility/aria-required-children.js +1 -1
  45. package/lighthouse-core/audits/accessibility/aria-required-parent.js +1 -1
  46. package/lighthouse-core/audits/accessibility/aria-roles.js +1 -1
  47. package/lighthouse-core/audits/accessibility/aria-toggle-field-name.js +1 -1
  48. package/lighthouse-core/audits/accessibility/aria-tooltip-name.js +1 -1
  49. package/lighthouse-core/audits/accessibility/aria-treeitem-name.js +1 -1
  50. package/lighthouse-core/audits/accessibility/aria-valid-attr-value.js +1 -1
  51. package/lighthouse-core/audits/accessibility/aria-valid-attr.js +1 -1
  52. package/lighthouse-core/audits/accessibility/button-name.js +1 -1
  53. package/lighthouse-core/audits/accessibility/bypass.js +1 -1
  54. package/lighthouse-core/audits/accessibility/color-contrast.js +1 -1
  55. package/lighthouse-core/audits/accessibility/definition-list.js +1 -1
  56. package/lighthouse-core/audits/accessibility/dlitem.js +1 -1
  57. package/lighthouse-core/audits/accessibility/document-title.js +1 -1
  58. package/lighthouse-core/audits/accessibility/duplicate-id-active.js +1 -1
  59. package/lighthouse-core/audits/accessibility/duplicate-id-aria.js +1 -1
  60. package/lighthouse-core/audits/accessibility/form-field-multiple-labels.js +1 -1
  61. package/lighthouse-core/audits/accessibility/frame-title.js +1 -1
  62. package/lighthouse-core/audits/accessibility/heading-order.js +1 -1
  63. package/lighthouse-core/audits/accessibility/html-has-lang.js +1 -1
  64. package/lighthouse-core/audits/accessibility/html-lang-valid.js +1 -1
  65. package/lighthouse-core/audits/accessibility/image-alt.js +1 -1
  66. package/lighthouse-core/audits/accessibility/input-image-alt.js +1 -1
  67. package/lighthouse-core/audits/accessibility/label.js +1 -1
  68. package/lighthouse-core/audits/accessibility/link-name.js +1 -1
  69. package/lighthouse-core/audits/accessibility/list.js +1 -1
  70. package/lighthouse-core/audits/accessibility/listitem.js +5 -5
  71. package/lighthouse-core/audits/accessibility/meta-refresh.js +1 -1
  72. package/lighthouse-core/audits/accessibility/meta-viewport.js +1 -1
  73. package/lighthouse-core/audits/accessibility/object-alt.js +1 -1
  74. package/lighthouse-core/audits/accessibility/tabindex.js +1 -1
  75. package/lighthouse-core/audits/accessibility/td-headers-attr.js +1 -1
  76. package/lighthouse-core/audits/accessibility/th-has-data-cells.js +1 -1
  77. package/lighthouse-core/audits/accessibility/valid-lang.js +1 -1
  78. package/lighthouse-core/audits/accessibility/video-caption.js +1 -1
  79. package/lighthouse-core/audits/byte-efficiency/byte-efficiency-audit.js +1 -2
  80. package/lighthouse-core/audits/byte-efficiency/duplicated-javascript.js +12 -11
  81. package/lighthouse-core/audits/byte-efficiency/efficient-animated-content.js +1 -1
  82. package/lighthouse-core/audits/byte-efficiency/legacy-javascript.js +24 -22
  83. package/lighthouse-core/audits/byte-efficiency/offscreen-images.js +2 -3
  84. package/lighthouse-core/audits/byte-efficiency/render-blocking-resources.js +3 -2
  85. package/lighthouse-core/audits/byte-efficiency/unminified-css.js +5 -3
  86. package/lighthouse-core/audits/byte-efficiency/unminified-javascript.js +11 -10
  87. package/lighthouse-core/audits/byte-efficiency/unused-css-rules.js +1 -0
  88. package/lighthouse-core/audits/byte-efficiency/unused-javascript.js +8 -11
  89. package/lighthouse-core/audits/byte-efficiency/uses-responsive-images.js +1 -1
  90. package/lighthouse-core/audits/byte-efficiency/uses-text-compression.js +1 -1
  91. package/lighthouse-core/audits/deprecations.js +598 -8
  92. package/lighthouse-core/audits/diagnostics.js +3 -4
  93. package/lighthouse-core/audits/dobetterweb/doctype.js +9 -20
  94. package/lighthouse-core/audits/dobetterweb/geolocation-on-start.js +1 -1
  95. package/lighthouse-core/audits/dobetterweb/no-document-write.js +1 -1
  96. package/lighthouse-core/audits/dobetterweb/notification-on-start.js +1 -1
  97. package/lighthouse-core/audits/dobetterweb/uses-http2.js +1 -2
  98. package/lighthouse-core/audits/dobetterweb/uses-passive-event-listeners.js +1 -1
  99. package/lighthouse-core/audits/errors-in-console.js +2 -2
  100. package/lighthouse-core/audits/long-tasks.js +2 -3
  101. package/lighthouse-core/audits/metrics/first-contentful-paint-3g.js +2 -2
  102. package/lighthouse-core/audits/metrics/first-contentful-paint.js +2 -3
  103. package/lighthouse-core/audits/metrics/first-meaningful-paint.js +2 -3
  104. package/lighthouse-core/audits/metrics/interactive.js +2 -3
  105. package/lighthouse-core/audits/metrics/largest-contentful-paint.js +2 -3
  106. package/lighthouse-core/audits/metrics/max-potential-fid.js +2 -3
  107. package/lighthouse-core/audits/metrics/speed-index.js +2 -3
  108. package/lighthouse-core/audits/metrics/total-blocking-time.js +2 -3
  109. package/lighthouse-core/audits/metrics.js +2 -3
  110. package/lighthouse-core/audits/no-unload-listeners.js +15 -7
  111. package/lighthouse-core/audits/predictive-perf.js +1 -2
  112. package/lighthouse-core/audits/preload-lcp-image.js +3 -3
  113. package/lighthouse-core/audits/redirects.js +1 -1
  114. package/lighthouse-core/audits/script-treemap-data.js +45 -45
  115. package/lighthouse-core/audits/seo/http-status-code.js +4 -2
  116. package/lighthouse-core/audits/seo/link-text.js +0 -2
  117. package/lighthouse-core/audits/server-response-time.js +17 -2
  118. package/lighthouse-core/audits/service-worker.js +2 -7
  119. package/lighthouse-core/audits/timing-budget.js +2 -3
  120. package/lighthouse-core/audits/uses-rel-preconnect.js +1 -1
  121. package/lighthouse-core/audits/uses-rel-preload.js +1 -1
  122. package/lighthouse-core/audits/valid-source-maps.js +14 -12
  123. package/lighthouse-core/audits/violation-audit.js +1 -1
  124. package/lighthouse-core/audits/work-during-interaction.js +2 -2
  125. package/lighthouse-core/computed/critical-request-chains.js +9 -5
  126. package/lighthouse-core/computed/js-bundles.js +11 -11
  127. package/lighthouse-core/computed/main-resource.js +2 -3
  128. package/lighthouse-core/computed/metrics/first-contentful-paint-all-frames.js +1 -1
  129. package/lighthouse-core/computed/metrics/first-contentful-paint.js +1 -1
  130. package/lighthouse-core/computed/metrics/first-meaningful-paint.js +1 -1
  131. package/lighthouse-core/computed/metrics/interactive.js +1 -1
  132. package/lighthouse-core/computed/metrics/lantern-first-contentful-paint.js +1 -1
  133. package/lighthouse-core/computed/metrics/lantern-first-meaningful-paint.js +1 -1
  134. package/lighthouse-core/computed/metrics/lantern-interactive.js +1 -1
  135. package/lighthouse-core/computed/metrics/lantern-largest-contentful-paint.js +1 -1
  136. package/lighthouse-core/computed/metrics/lantern-max-potential-fid.js +1 -1
  137. package/lighthouse-core/computed/metrics/lantern-metric.js +5 -3
  138. package/lighthouse-core/computed/metrics/lantern-speed-index.js +1 -1
  139. package/lighthouse-core/computed/metrics/lantern-total-blocking-time.js +1 -1
  140. package/lighthouse-core/computed/metrics/largest-contentful-paint-all-frames.js +1 -1
  141. package/lighthouse-core/computed/metrics/largest-contentful-paint.js +1 -1
  142. package/lighthouse-core/computed/metrics/max-potential-fid.js +1 -1
  143. package/lighthouse-core/computed/metrics/metric.js +0 -1
  144. package/lighthouse-core/computed/metrics/speed-index.js +1 -1
  145. package/lighthouse-core/computed/metrics/timing-summary.js +6 -13
  146. package/lighthouse-core/computed/metrics/total-blocking-time.js +1 -1
  147. package/lighthouse-core/computed/module-duplication.js +5 -6
  148. package/lighthouse-core/computed/page-dependency-graph.js +28 -55
  149. package/lighthouse-core/computed/resource-summary.js +5 -5
  150. package/lighthouse-core/computed/unused-css.js +7 -6
  151. package/lighthouse-core/computed/unused-javascript-summary.js +36 -16
  152. package/lighthouse-core/config/budget.js +2 -2
  153. package/lighthouse-core/config/default-config.js +1 -2
  154. package/lighthouse-core/fraggle-rock/api.js +1 -1
  155. package/lighthouse-core/fraggle-rock/config/default-config.js +0 -3
  156. package/lighthouse-core/fraggle-rock/gather/base-artifacts.js +3 -6
  157. package/lighthouse-core/fraggle-rock/gather/driver.js +2 -2
  158. package/lighthouse-core/fraggle-rock/gather/navigation-runner.js +26 -51
  159. package/lighthouse-core/fraggle-rock/gather/runner-helpers.js +3 -0
  160. package/lighthouse-core/fraggle-rock/gather/session.js +22 -23
  161. package/lighthouse-core/fraggle-rock/gather/snapshot-runner.js +4 -5
  162. package/lighthouse-core/fraggle-rock/gather/timespan-runner.js +6 -6
  163. package/lighthouse-core/gather/connections/cri.js +1 -5
  164. package/lighthouse-core/gather/driver/execution-context.js +2 -5
  165. package/lighthouse-core/gather/driver/navigation.js +10 -13
  166. package/lighthouse-core/gather/driver/network-monitor.js +3 -16
  167. package/lighthouse-core/gather/driver.js +1 -6
  168. package/lighthouse-core/gather/fetcher.js +210 -34
  169. package/lighthouse-core/gather/gather-runner.js +17 -13
  170. package/lighthouse-core/gather/gatherers/accessibility.js +4 -16
  171. package/lighthouse-core/gather/gatherers/console-messages.js +2 -4
  172. package/lighthouse-core/gather/gatherers/dobetterweb/doctype.js +2 -4
  173. package/lighthouse-core/gather/gatherers/full-page-screenshot.js +2 -3
  174. package/lighthouse-core/gather/gatherers/iframe-elements.js +1 -4
  175. package/lighthouse-core/gather/gatherers/image-elements.js +0 -2
  176. package/lighthouse-core/gather/gatherers/js-usage.js +87 -12
  177. package/lighthouse-core/gather/gatherers/link-elements.js +14 -12
  178. package/lighthouse-core/gather/gatherers/main-document-content.js +8 -8
  179. package/lighthouse-core/gather/gatherers/script-elements.js +56 -7
  180. package/lighthouse-core/gather/gatherers/seo/robots-txt.js +30 -2
  181. package/lighthouse-core/gather/gatherers/source-maps.js +1 -8
  182. package/lighthouse-core/gather/gatherers/web-app-manifest.js +2 -2
  183. package/lighthouse-core/index.js +2 -26
  184. package/lighthouse-core/lib/cdt/generated/SourceMap.js +1 -1
  185. package/lighthouse-core/lib/dependency-graph/simulator/network-analyzer.js +29 -8
  186. package/lighthouse-core/lib/navigation-error.js +4 -13
  187. package/lighthouse-core/lib/page-functions.js +1 -3
  188. package/lighthouse-core/lib/script-helpers.js +6 -11
  189. package/lighthouse-core/lib/url-shim.js +2 -2
  190. package/lighthouse-core/runner.js +5 -0
  191. package/lighthouse-core/scripts/manual-chrome-launcher.js +1 -0
  192. package/lighthouse-core/util-commonjs.js +6 -8
  193. package/package.json +13 -13
  194. package/readme.md +1 -1
  195. package/report/.eslintrc.cjs +1 -3
  196. package/report/assets/styles.css +5 -10
  197. package/report/assets/templates.html +9 -10
  198. package/report/clients/bundle.js +1 -0
  199. package/report/clients/standalone.js +1 -0
  200. package/report/generator/report-generator.js +21 -46
  201. package/report/renderer/api.js +2 -0
  202. package/report/renderer/category-renderer.js +24 -20
  203. package/report/renderer/components.js +304 -303
  204. package/report/renderer/crc-details-renderer.js +24 -21
  205. package/report/renderer/details-renderer.js +12 -12
  206. package/report/renderer/dom.js +7 -6
  207. package/report/renderer/drop-down-menu.js +1 -0
  208. package/report/renderer/element-screenshot-renderer.js +5 -1
  209. package/report/renderer/features-util.js +1 -0
  210. package/report/renderer/i18n.js +62 -118
  211. package/report/renderer/logger.js +1 -0
  212. package/report/renderer/open-tab.js +3 -1
  213. package/report/renderer/performance-category-renderer.js +11 -10
  214. package/report/renderer/pwa-category-renderer.js +4 -3
  215. package/report/renderer/report-renderer.js +17 -17
  216. package/report/renderer/report-ui-features.js +1 -0
  217. package/report/renderer/snippet-renderer.js +3 -2
  218. package/report/renderer/swap-locale-feature.js +1 -0
  219. package/report/renderer/text-encoding.js +1 -0
  220. package/report/renderer/topbar-features.js +1 -0
  221. package/report/renderer/util.js +6 -7
  222. package/report/test/clients/bundle-test.js +5 -0
  223. package/report/test/generator/file-namer-test.js +1 -0
  224. package/report/test/generator/report-generator-test.js +20 -25
  225. package/report/test/renderer/category-renderer-test.js +4 -3
  226. package/report/test/renderer/components-test.js +3 -0
  227. package/report/test/renderer/crc-details-renderer-test.js +3 -0
  228. package/report/test/renderer/details-renderer-test.js +3 -49
  229. package/report/test/renderer/dom-test.js +3 -0
  230. package/report/test/renderer/element-screenshot-renderer-test.js +6 -3
  231. package/report/test/renderer/i18n-test.js +25 -70
  232. package/report/test/renderer/performance-category-renderer-test.js +5 -14
  233. package/report/test/renderer/pwa-category-renderer-test.js +4 -3
  234. package/report/test/renderer/report-renderer-axe-test.js +4 -3
  235. package/report/test/renderer/report-renderer-test.js +4 -3
  236. package/report/test/renderer/report-ui-features-test.js +4 -3
  237. package/report/test/renderer/snippet-renderer-test.js +3 -0
  238. package/report/test/renderer/text-encoding-test.js +3 -0
  239. package/report/test/renderer/util-test.js +5 -4
  240. package/report/test-assets/faux-psi.js +1 -2
  241. package/shared/localization/format.js +3 -7
  242. package/shared/localization/locales/en-US.json +238 -55
  243. package/shared/localization/locales/en-XL.json +238 -55
  244. package/shared/test/localization/format-test.js +2 -8
  245. package/shared/test/localization/locales-test.js +2 -0
  246. package/shared/test/localization/swap-locale-test.js +2 -0
  247. package/third-party/chromium-synchronization/inspector-issueAdded-types-test.js +2 -0
  248. package/third-party/chromium-synchronization/installability-errors-test.js +2 -0
  249. package/tsconfig.json +0 -1
  250. package/types/artifacts.d.ts +8 -47
  251. package/types/config.d.ts +0 -2
  252. package/types/externs.d.ts +2 -3
  253. package/types/gatherer.d.ts +2 -1
  254. package/types/global-lh.d.ts +0 -3
  255. package/types/lhr/lhr.d.ts +2 -2
  256. package/types/lhr/treemap.d.ts +1 -0
  257. package/changelog.md +0 -5902
  258. package/lighthouse-core/audits/script-elements-test-audit.js +0 -30
  259. package/lighthouse-core/gather/gatherers/scripts.js +0 -154
  260. package/lighthouse-core/scripts/package.json +0 -4
  261. package/report/test/.eslintrc.cjs +0 -11
  262. package/shared/test/localization/.eslintrc.cjs +0 -11
@@ -8,14 +8,13 @@
8
8
  const makeComputedArtifact = require('./computed-artifact.js');
9
9
  const NetworkNode = require('../lib/dependency-graph/network-node.js');
10
10
  const CPUNode = require('../lib/dependency-graph/cpu-node.js');
11
+ const NetworkAnalyzer = require('../lib/dependency-graph/simulator/network-analyzer.js');
11
12
  const TracingProcessor = require('../lib/tracehouse/trace-processor.js');
12
13
  const NetworkRequest = require('../lib/network-request.js');
13
14
  const ProcessedTrace = require('./processed-trace.js');
14
15
  const NetworkRecords = require('./network-records.js');
15
- const NetworkAnalyzer = require('../lib/dependency-graph/simulator/network-analyzer.js');
16
16
 
17
17
  /** @typedef {import('../lib/dependency-graph/base-node.js').Node} Node */
18
- /** @typedef {Omit<LH.Artifacts['URL'], 'initialUrl'|'finalUrl'>} URLArtifact */
19
18
 
20
19
  // Shorter tasks have negligible impact on simulation results.
21
20
  const SIGNIFICANT_DUR_THRESHOLD_MS = 10;
@@ -389,25 +388,34 @@ class PageDependencyGraph {
389
388
  /**
390
389
  * @param {LH.Artifacts.ProcessedTrace} processedTrace
391
390
  * @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
392
- * @param {URLArtifact} URL
393
391
  * @return {Node}
394
392
  */
395
- static createGraph(processedTrace, networkRecords, URL) {
393
+ static createGraph(processedTrace, networkRecords) {
396
394
  const networkNodeOutput = PageDependencyGraph.getNetworkNodeOutput(networkRecords);
397
395
  const cpuNodes = PageDependencyGraph.getCPUNodes(processedTrace);
398
- const {requestedUrl, mainDocumentUrl} = URL;
399
- if (!requestedUrl) throw new Error('requestedUrl is required to get the root request');
400
- if (!mainDocumentUrl) throw new Error('mainDocumentUrl is required to get the main resource');
401
-
402
- const rootRequest = NetworkAnalyzer.findResourceForUrl(networkRecords, requestedUrl);
403
- if (!rootRequest) throw new Error('rootRequest not found');
404
- const rootNode = networkNodeOutput.idToNodeMap.get(rootRequest.requestId);
405
- if (!rootNode) throw new Error('rootNode not found');
406
396
 
407
- const mainDocumentRequest = NetworkAnalyzer.findResourceForUrl(networkRecords, mainDocumentUrl);
408
- if (!mainDocumentRequest) throw new Error('mainDocumentRequest not found');
397
+ // The main document request is the earliest network request *of type document*.
398
+ // This will be different from the root request when there are server redirects.
399
+ const mainDocumentRequest = NetworkAnalyzer.findMainDocument(networkRecords);
409
400
  const mainDocumentNode = networkNodeOutput.idToNodeMap.get(mainDocumentRequest.requestId);
410
- if (!mainDocumentNode) throw new Error('mainDocumentNode not found');
401
+ if (!mainDocumentNode) {
402
+ // mainDocumentNode should always be found.
403
+ throw new Error('mainDocumentNode not found.');
404
+ }
405
+
406
+ // The root request is the earliest request in the main document redirect chain.
407
+ // Will be undefined if there were no redirects.
408
+ const rootRequest = mainDocumentNode.record.redirects?.[0];
409
+
410
+ let rootNode;
411
+ if (rootRequest) {
412
+ // rootNode should always be found.
413
+ rootNode = rootRequest && networkNodeOutput.idToNodeMap.get(rootRequest.requestId);
414
+ if (!rootNode) throw new Error('rootNode not found');
415
+ } else {
416
+ // Use main document as root if there were no redirects.
417
+ rootNode = mainDocumentNode;
418
+ }
411
419
 
412
420
  PageDependencyGraph.linkNetworkNodes(rootNode, networkNodeOutput);
413
421
  PageDependencyGraph.linkCPUNodes(rootNode, networkNodeOutput, cpuNodes);
@@ -453,58 +461,23 @@ class PageDependencyGraph {
453
461
  }
454
462
 
455
463
  /**
456
- * Recalculate `artifacts.URL` for clients that don't provide it.
457
- *
458
- * @param {LH.DevtoolsLog} devtoolsLog
459
- * @param {LH.Artifacts.NetworkRequest[]} networkRecords
460
- * @param {LH.Artifacts.ProcessedTrace} processedTrace
461
- * @return {URLArtifact}
462
- */
463
- static getDocumentUrls(devtoolsLog, networkRecords, processedTrace) {
464
- const mainFrameId = processedTrace.mainFrameIds.frameId;
465
-
466
- /** @type {string|undefined} */
467
- let requestedUrl;
468
- /** @type {string|undefined} */
469
- let mainDocumentUrl;
470
- for (const event of devtoolsLog) {
471
- if (event.method === 'Page.frameNavigated' && event.params.frame.id === mainFrameId) {
472
- const {url} = event.params.frame;
473
- // Only set requestedUrl on the first main frame navigation.
474
- if (!requestedUrl) requestedUrl = url;
475
- mainDocumentUrl = url;
476
- }
477
- }
478
- if (!requestedUrl || !mainDocumentUrl) throw new Error('No main frame navigations found');
479
-
480
- const initialRequest = NetworkAnalyzer.findResourceForUrl(networkRecords, requestedUrl);
481
- if (initialRequest?.redirects?.length) requestedUrl = initialRequest.redirects[0].url;
482
-
483
- return {requestedUrl, mainDocumentUrl};
484
- }
485
-
486
- /**
487
- * @param {{trace: LH.Trace, devtoolsLog: LH.DevtoolsLog, URL: LH.Artifacts['URL']}} data
464
+ * @param {{trace: LH.Trace, devtoolsLog: LH.DevtoolsLog}} data
488
465
  * @param {LH.Artifacts.ComputedContext} context
489
466
  * @return {Promise<Node>}
490
467
  */
491
468
  static async compute_(data, context) {
492
- const {trace, devtoolsLog} = data;
469
+ const trace = data.trace;
470
+ const devtoolsLog = data.devtoolsLog;
493
471
  const [processedTrace, networkRecords] = await Promise.all([
494
472
  ProcessedTrace.request(trace, context),
495
473
  NetworkRecords.request(devtoolsLog, context),
496
474
  ]);
497
475
 
498
- // COMPAT: Backport for pre-10.0 clients that don't pass the URL artifact here (e.g. pubads).
499
- // Calculates the URL artifact from the processed trace and DT log.
500
- const URL = data.URL ||
501
- PageDependencyGraph.getDocumentUrls(devtoolsLog, networkRecords, processedTrace);
502
-
503
- return PageDependencyGraph.createGraph(processedTrace, networkRecords, URL);
476
+ return PageDependencyGraph.createGraph(processedTrace, networkRecords);
504
477
  }
505
478
  }
506
479
 
507
- module.exports = makeComputedArtifact(PageDependencyGraph, ['devtoolsLog', 'trace', 'URL']);
480
+ module.exports = makeComputedArtifact(PageDependencyGraph, ['devtoolsLog', 'trace']);
508
481
 
509
482
  /**
510
483
  * @typedef {Object} NetworkNodeOutput
@@ -35,11 +35,11 @@ class ResourceSummary {
35
35
 
36
36
  /**
37
37
  * @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
38
- * @param {LH.Artifacts.URL} URLArtifact
38
+ * @param {string} mainResourceURL
39
39
  * @param {ImmutableObject<LH.Budget[]|null>} budgets
40
40
  * @return {Record<LH.Budget.ResourceType, ResourceEntry>}
41
41
  */
42
- static summarize(networkRecords, URLArtifact, budgets) {
42
+ static summarize(networkRecords, mainResourceURL, budgets) {
43
43
  /** @type {Record<LH.Budget.ResourceType, ResourceEntry>} */
44
44
  const resourceSummary = {
45
45
  'stylesheet': {count: 0, resourceSize: 0, transferSize: 0},
@@ -52,13 +52,13 @@ class ResourceSummary {
52
52
  'total': {count: 0, resourceSize: 0, transferSize: 0},
53
53
  'third-party': {count: 0, resourceSize: 0, transferSize: 0},
54
54
  };
55
- const budget = Budget.getMatchingBudget(budgets, URLArtifact.mainDocumentUrl);
55
+ const budget = Budget.getMatchingBudget(budgets, mainResourceURL);
56
56
  /** @type {ReadonlyArray<string>} */
57
57
  let firstPartyHosts = [];
58
58
  if (budget?.options?.firstPartyHostnames) {
59
59
  firstPartyHosts = budget.options.firstPartyHostnames;
60
60
  } else {
61
- const rootDomain = Util.getRootDomain(URLArtifact.finalUrl);
61
+ const rootDomain = Util.getRootDomain(mainResourceURL);
62
62
  firstPartyHosts = [`*.${rootDomain}`];
63
63
  }
64
64
 
@@ -107,7 +107,7 @@ class ResourceSummary {
107
107
  */
108
108
  static async compute_(data, context) {
109
109
  const networkRecords = await NetworkRecords.request(data.devtoolsLog, context);
110
- return ResourceSummary.summarize(networkRecords, data.URL, data.budgets);
110
+ return ResourceSummary.summarize(networkRecords, data.URL.finalUrl, data.budgets);
111
111
  }
112
112
  }
113
113
 
@@ -120,11 +120,12 @@ class UnusedCSS {
120
120
 
121
121
  /**
122
122
  * @param {StyleSheetInfo} stylesheetInfo The stylesheetInfo object.
123
+ * @param {string} pageUrl The URL of the page, used to identify inline styles.
123
124
  * @return {LH.Audit.ByteEfficiencyItem}
124
125
  */
125
- static mapSheetToResult(stylesheetInfo) {
126
+ static mapSheetToResult(stylesheetInfo, pageUrl) {
126
127
  let url = stylesheetInfo.header.sourceURL;
127
- if (!url || stylesheetInfo.header.isInline) {
128
+ if (!url || url === pageUrl) {
128
129
  const contentPreview = UnusedCSS.determineContentPreview(stylesheetInfo.content);
129
130
  url = contentPreview;
130
131
  }
@@ -134,20 +135,20 @@ class UnusedCSS {
134
135
  }
135
136
 
136
137
  /**
137
- * @param {{CSSUsage: LH.Artifacts['CSSUsage'], devtoolsLog: LH.DevtoolsLog}} data
138
+ * @param {{CSSUsage: LH.Artifacts['CSSUsage'], URL: LH.Artifacts['URL'], devtoolsLog: LH.DevtoolsLog}} data
138
139
  * @param {LH.Artifacts.ComputedContext} context
139
140
  * @return {Promise<LH.Audit.ByteEfficiencyItem[]>}
140
141
  */
141
142
  static async compute_(data, context) {
142
- const {CSSUsage, devtoolsLog} = data;
143
+ const {CSSUsage, URL, devtoolsLog} = data;
143
144
  const networkRecords = await NetworkRecords.request(devtoolsLog, context);
144
145
  const indexedSheets = UnusedCSS.indexStylesheetsById(CSSUsage.stylesheets, networkRecords);
145
146
  UnusedCSS.indexUsedRules(CSSUsage.rules, indexedSheets);
146
147
 
147
148
  const items = Object.keys(indexedSheets)
148
- .map(sheetId => UnusedCSS.mapSheetToResult(indexedSheets[sheetId]));
149
+ .map(sheetId => UnusedCSS.mapSheetToResult(indexedSheets[sheetId], URL.finalUrl));
149
150
  return items;
150
151
  }
151
152
  }
152
153
 
153
- module.exports = makeComputedArtifact(UnusedCSS, ['CSSUsage', 'devtoolsLog']);
154
+ module.exports = makeComputedArtifact(UnusedCSS, ['CSSUsage', 'URL', 'devtoolsLog']);
@@ -16,14 +16,14 @@ const makeComputedArtifact = require('./computed-artifact.js');
16
16
 
17
17
  /**
18
18
  * @typedef ComputeInput
19
- * @property {string} scriptId
20
- * @property {Omit<LH.Crdp.Profiler.ScriptCoverage, 'url'>} scriptCoverage
19
+ * @property {string} url
20
+ * @property {Array<Omit<LH.Crdp.Profiler.ScriptCoverage, 'url'>>} scriptCoverages
21
21
  * @property {LH.Artifacts.Bundle=} bundle
22
22
  */
23
23
 
24
24
  /**
25
25
  * @typedef Summary
26
- * @property {string} scriptId
26
+ * @property {string} url
27
27
  * @property {number} wastedBytes
28
28
  * @property {number} totalBytes
29
29
  * @property {number} wastedBytes
@@ -68,24 +68,43 @@ class UnusedJavascriptSummary {
68
68
  }
69
69
 
70
70
  /**
71
- * @param {string} scriptId
72
- * @param {WasteData} wasteData
71
+ * @param {string} url
72
+ * @param {ReturnType<typeof UnusedJavascriptSummary.determineLengths>} lengths
73
73
  * @return {Summary}
74
74
  */
75
- static createItem(scriptId, wasteData) {
76
- const wastedRatio = (wasteData.unusedLength / wasteData.contentLength) || 0;
77
- const wastedBytes = Math.round(wasteData.contentLength * wastedRatio);
75
+ static createItem(url, lengths) {
76
+ const wastedRatio = (lengths.unused / lengths.content) || 0;
77
+ const wastedBytes = Math.round(lengths.content * wastedRatio);
78
78
 
79
79
  return {
80
- scriptId,
81
- totalBytes: wasteData.contentLength,
80
+ url,
81
+ totalBytes: lengths.content,
82
82
  wastedBytes,
83
83
  wastedPercent: 100 * wastedRatio,
84
84
  };
85
85
  }
86
86
 
87
87
  /**
88
- * @param {WasteData} wasteData
88
+ * @param {WasteData[]} wasteData
89
+ */
90
+ static determineLengths(wasteData) {
91
+ let unused = 0;
92
+ let content = 0;
93
+ // TODO: this is right for multiple script tags in an HTML document,
94
+ // but may be wrong for multiple frames using the same script resource.
95
+ for (const usage of wasteData) {
96
+ unused += usage.unusedLength;
97
+ content += usage.contentLength;
98
+ }
99
+
100
+ return {
101
+ content,
102
+ unused,
103
+ };
104
+ }
105
+
106
+ /**
107
+ * @param {WasteData[]} wasteData
89
108
  * @param {LH.Artifacts.Bundle} bundle
90
109
  */
91
110
  static createSourceWastedBytes(wasteData, bundle) {
@@ -112,7 +131,7 @@ class UnusedJavascriptSummary {
112
131
  mapping.lastColumnNumber - 1 :
113
132
  lineLengths[mapping.lineNumber];
114
133
  for (let i = mapping.columnNumber; i <= lastColumnOfMapping; i++) {
115
- if (wasteData.unusedByIndex[offset] === 1) {
134
+ if (wasteData.every(data => data.unusedByIndex[offset] === 1)) {
116
135
  const key = mapping.sourceURL || '(unmapped)';
117
136
  files[key] = (files[key] || 0) + 1;
118
137
  }
@@ -136,10 +155,11 @@ class UnusedJavascriptSummary {
136
155
  * @return {Promise<Summary>}
137
156
  */
138
157
  static async compute_(data) {
139
- const {scriptId, scriptCoverage, bundle} = data;
158
+ const {url, scriptCoverages, bundle} = data;
140
159
 
141
- const wasteData = UnusedJavascriptSummary.computeWaste(scriptCoverage);
142
- const item = UnusedJavascriptSummary.createItem(scriptId, wasteData);
160
+ const wasteData = scriptCoverages.map(UnusedJavascriptSummary.computeWaste);
161
+ const lengths = UnusedJavascriptSummary.determineLengths(wasteData);
162
+ const item = UnusedJavascriptSummary.createItem(url, lengths);
143
163
  if (!bundle) return item;
144
164
 
145
165
  return {
@@ -151,5 +171,5 @@ class UnusedJavascriptSummary {
151
171
 
152
172
  module.exports = makeComputedArtifact(
153
173
  UnusedJavascriptSummary,
154
- ['bundle', 'scriptCoverage', 'scriptId']
174
+ ['bundle', 'scriptCoverages', 'url']
155
175
  );
@@ -137,11 +137,11 @@ class Budget {
137
137
  * If multiple budgets match based on thier 'path' property,
138
138
  * then the last-listed of those budgets is returned.
139
139
  * @param {Immutable<Array<LH.Budget>>|null} budgets
140
- * @param {string|undefined} url
140
+ * @param {string} url
141
141
  * @return {Immutable<LH.Budget> | undefined} budget
142
142
  */
143
143
  static getMatchingBudget(budgets, url) {
144
- if (budgets === null || url === undefined) return;
144
+ if (budgets === null) return;
145
145
 
146
146
  // Applies the LAST matching budget.
147
147
  for (let i = budgets.length - 1; i >= 0; i--) {
@@ -41,7 +41,7 @@ const UIStrings = {
41
41
  /** Description of the Accessibility category. This is displayed at the top of a list of audits focused on making web content accessible to all users. No character length limits. 'improve the accessibility of your web app' becomes link text to additional documentation. */
42
42
  a11yCategoryDescription: 'These checks highlight opportunities to [improve the accessibility of your web app](https://web.dev/lighthouse-accessibility/). Only a subset of accessibility issues can be automatically detected so manual testing is also encouraged.',
43
43
  /** Description of the Accessibility manual checks category. This description is displayed above a list of accessibility audits that currently have no automated test and so must be verified manually by the user. No character length limits. 'conducting an accessibility review' becomes link text to additional documentation. */
44
- a11yCategoryManualDescription: 'These items address areas which an automated testing tool cannot cover. Learn more in our guide on [conducting an accessibility review](https://web.dev/how-to-review/).',
44
+ a11yCategoryManualDescription: 'These items address areas which an automated testing tool cannot cover. Learn more in our guide on [conducting an accessibility review](https://developers.google.com/web/fundamentals/accessibility/how-to-review).',
45
45
  /** Title of the best practices section of the Accessibility category. Within this section are audits with descriptive titles that highlight common accessibility best practices. */
46
46
  a11yBestPracticesGroupTitle: 'Best practices',
47
47
  /** Description of the best practices section within the Accessibility category. Within this section are audits with descriptive titles that highlight common accessibility best practices. */
@@ -143,7 +143,6 @@ const defaultConfig = {
143
143
  'link-elements',
144
144
  'meta-elements',
145
145
  'script-elements',
146
- 'scripts',
147
146
  'iframe-elements',
148
147
  'inputs',
149
148
  'main-document-content',
@@ -13,7 +13,7 @@ const {generateFlowReportHtml} = require('../../report/generator/report-generato
13
13
  const Runner = require('../runner.js');
14
14
 
15
15
  /**
16
- * @param {LH.Puppeteer.Page} page
16
+ * @param {import('puppeteer').Page} page
17
17
  * @param {ConstructorParameters<LH.UserFlow>[1]} [options]
18
18
  */
19
19
  async function startFlow(page, options) {
@@ -70,7 +70,6 @@ const artifacts = {
70
70
  RobotsTxt: '',
71
71
  ServiceWorker: '',
72
72
  ScriptElements: '',
73
- Scripts: '',
74
73
  SourceMaps: '',
75
74
  Stacks: '',
76
75
  TagsBlockingFirstPaint: '',
@@ -120,7 +119,6 @@ const defaultConfig = {
120
119
  {id: artifacts.RobotsTxt, gatherer: 'seo/robots-txt'},
121
120
  {id: artifacts.ServiceWorker, gatherer: 'service-worker'},
122
121
  {id: artifacts.ScriptElements, gatherer: 'script-elements'},
123
- {id: artifacts.Scripts, gatherer: 'scripts'},
124
122
  {id: artifacts.SourceMaps, gatherer: 'source-maps'},
125
123
  {id: artifacts.Stacks, gatherer: 'stacks'},
126
124
  {id: artifacts.TagsBlockingFirstPaint, gatherer: 'dobetterweb/tags-blocking-first-paint'},
@@ -175,7 +173,6 @@ const defaultConfig = {
175
173
  artifacts.RobotsTxt,
176
174
  artifacts.ServiceWorker,
177
175
  artifacts.ScriptElements,
178
- artifacts.Scripts,
179
176
  artifacts.SourceMaps,
180
177
  artifacts.Stacks,
181
178
  artifacts.TagsBlockingFirstPaint,
@@ -35,10 +35,7 @@ async function getBaseArtifacts(config, driver, context) {
35
35
  HostFormFactor: userAgent.includes('Android') || userAgent.includes('Mobile') ?
36
36
  'mobile' : 'desktop',
37
37
  // Contextual artifacts whose collection changes based on gather mode.
38
- URL: {
39
- initialUrl: '',
40
- finalUrl: '',
41
- },
38
+ URL: {requestedUrl: '', finalUrl: ''},
42
39
  PageLoadError: null,
43
40
  GatherContext: context,
44
41
  // Artifacts that have been replaced by regular gatherers in Fraggle Rock.
@@ -86,11 +83,11 @@ function finalizeArtifacts(baseArtifacts, gathererArtifacts) {
86
83
  artifacts.LighthouseRunWarnings = deduplicateWarnings(warnings);
87
84
 
88
85
  if (artifacts.PageLoadError && !artifacts.URL.finalUrl) {
89
- artifacts.URL.finalUrl = artifacts.URL.requestedUrl || artifacts.URL.initialUrl;
86
+ artifacts.URL.finalUrl = artifacts.URL.requestedUrl;
90
87
  }
91
88
 
92
89
  // Check that the runner remembered to mutate the special-case URL artifact.
93
- if (!artifacts.URL.initialUrl) throw new Error('Runner did not set initialUrl');
90
+ if (!artifacts.URL.requestedUrl) throw new Error('Runner did not set requestedUrl');
94
91
  if (!artifacts.URL.finalUrl) throw new Error('Runner did not set finalUrl');
95
92
 
96
93
  return artifacts;
@@ -35,7 +35,7 @@ const defaultSession = {
35
35
  /** @implements {LH.Gatherer.FRTransitionalDriver} */
36
36
  class Driver {
37
37
  /**
38
- * @param {LH.Puppeteer.Page} page
38
+ * @param {import('puppeteer').Page} page
39
39
  */
40
40
  constructor(page) {
41
41
  this._page = page;
@@ -74,7 +74,7 @@ class Driver {
74
74
  const session = await this._page.target().createCDPSession();
75
75
  this._session = this.defaultSession = new ProtocolSession(session);
76
76
  this._executionContext = new ExecutionContext(this._session);
77
- this._fetcher = new Fetcher(this._session);
77
+ this._fetcher = new Fetcher(this._session, this._executionContext);
78
78
  log.timeEnd(status);
79
79
  }
80
80
 
@@ -5,7 +5,6 @@
5
5
  */
6
6
  'use strict';
7
7
 
8
- const puppeteer = require('puppeteer-core');
9
8
  const log = require('lighthouse-logger');
10
9
  const Driver = require('./driver.js');
11
10
  const Runner = require('../../runner.js');
@@ -44,20 +43,18 @@ const NetworkRecords = require('../../computed/network-records.js');
44
43
 
45
44
  /** @typedef {Omit<Parameters<typeof collectPhaseArtifacts>[0], 'phase'>} PhaseState */
46
45
 
47
- const DEFAULT_HOSTNAME = '127.0.0.1';
48
- const DEFAULT_PORT = 9222;
49
-
50
46
  /**
51
- * @param {{driver: Driver, config: LH.Config.FRConfig, options?: InternalOptions}} args
47
+ * @param {{driver: Driver, config: LH.Config.FRConfig, requestor: LH.NavigationRequestor, options?: InternalOptions}} args
52
48
  * @return {Promise<{baseArtifacts: LH.FRBaseArtifacts}>}
53
49
  */
54
- async function _setup({driver, config, options}) {
50
+ async function _setup({driver, config, requestor, options}) {
55
51
  await driver.connect();
56
52
  if (!options?.skipAboutBlank) {
57
53
  await gotoURL(driver, defaultNavigationConfig.blankPage, {waitUntil: ['navigated']});
58
54
  }
59
55
 
60
56
  const baseArtifacts = await getBaseArtifacts(config, driver, {gatherMode: 'navigation'});
57
+ if (typeof requestor === 'string') baseArtifacts.URL.requestedUrl = requestor;
61
58
 
62
59
  await prepare.prepareTargetForNavigationMode(driver, config.settings);
63
60
 
@@ -93,32 +90,25 @@ async function _cleanupNavigation({driver}) {
93
90
 
94
91
  /**
95
92
  * @param {NavigationContext} navigationContext
96
- * @return {Promise<{requestedUrl: string, mainDocumentUrl: string, navigationError: LH.LighthouseError | undefined, warnings: Array<LH.IcuMessage>}>}
93
+ * @return {Promise<{requestedUrl: string, finalUrl: string, navigationError: LH.LighthouseError | undefined, warnings: Array<LH.IcuMessage>}>}
97
94
  */
98
95
  async function _navigate(navigationContext) {
99
96
  const {driver, config, requestor} = navigationContext;
100
97
 
101
98
  try {
102
- const {requestedUrl, mainDocumentUrl, warnings} = await gotoURL(driver, requestor, {
99
+ const {requestedUrl, finalUrl, warnings} = await gotoURL(driver, requestor, {
103
100
  ...navigationContext.navigation,
104
101
  debugNavigation: config.settings.debugNavigation,
105
102
  maxWaitForFcp: config.settings.maxWaitForFcp,
106
103
  maxWaitForLoad: config.settings.maxWaitForLoad,
107
104
  waitUntil: navigationContext.navigation.pauseAfterFcpMs ? ['fcp', 'load'] : ['load'],
108
105
  });
109
- return {requestedUrl, mainDocumentUrl, navigationError: undefined, warnings};
106
+ return {requestedUrl, finalUrl, navigationError: undefined, warnings};
110
107
  } catch (err) {
111
108
  if (!(err instanceof LighthouseError)) throw err;
112
109
  if (err.code !== 'NO_FCP' && err.code !== 'PAGE_HUNG') throw err;
113
110
  if (typeof requestor !== 'string') throw err;
114
-
115
- // TODO: Make the urls optional here so we don't need to throw an error with a callback requestor.
116
- return {
117
- requestedUrl: requestor,
118
- mainDocumentUrl: requestor,
119
- navigationError: err,
120
- warnings: [],
121
- };
111
+ return {requestedUrl: requestor, finalUrl: requestor, navigationError: err, warnings: []};
122
112
  }
123
113
  }
124
114
 
@@ -162,7 +152,7 @@ async function _collectDebugData(navigationContext, phaseState) {
162
152
  * @param {PhaseState} phaseState
163
153
  * @param {Awaited<ReturnType<typeof _setupNavigation>>} setupResult
164
154
  * @param {Awaited<ReturnType<typeof _navigate>>} navigateResult
165
- * @return {Promise<{artifacts: Partial<LH.GathererArtifacts>, warnings: Array<LH.IcuMessage>, pageLoadError: LH.LighthouseError | undefined}>}
155
+ * @return {Promise<{requestedUrl: string, finalUrl: string, artifacts: Partial<LH.GathererArtifacts>, warnings: Array<LH.IcuMessage>, pageLoadError: LH.LighthouseError | undefined}>}
166
156
  */
167
157
  async function _computeNavigationResult(
168
158
  navigationContext,
@@ -170,12 +160,12 @@ async function _computeNavigationResult(
170
160
  setupResult,
171
161
  navigateResult
172
162
  ) {
173
- const {navigationError, mainDocumentUrl} = navigateResult;
163
+ const {navigationError, finalUrl} = navigateResult;
174
164
  const warnings = [...setupResult.warnings, ...navigateResult.warnings];
175
165
  const debugData = await _collectDebugData(navigationContext, phaseState);
176
166
  const pageLoadError = debugData.records
177
167
  ? getPageLoadError(navigationError, {
178
- url: mainDocumentUrl,
168
+ url: finalUrl,
179
169
  loadFailureMode: navigationContext.navigation.loadFailureMode,
180
170
  networkRecords: debugData.records,
181
171
  })
@@ -193,6 +183,8 @@ async function _computeNavigationResult(
193
183
  if (debugData.trace) artifacts.traces = {[pageLoadErrorId]: debugData.trace};
194
184
 
195
185
  return {
186
+ requestedUrl: navigateResult.requestedUrl,
187
+ finalUrl,
196
188
  pageLoadError,
197
189
  artifacts,
198
190
  warnings: [...warnings, pageLoadError.friendlyMessage],
@@ -202,6 +194,8 @@ async function _computeNavigationResult(
202
194
 
203
195
  const artifacts = await awaitArtifacts(phaseState.artifactState);
204
196
  return {
197
+ requestedUrl: navigateResult.requestedUrl,
198
+ finalUrl,
205
199
  artifacts,
206
200
  warnings,
207
201
  pageLoadError: undefined,
@@ -215,9 +209,8 @@ async function _computeNavigationResult(
215
209
  */
216
210
  async function _navigation(navigationContext) {
217
211
  const artifactState = getEmptyArtifactState();
218
- const initialUrl = await navigationContext.driver.url();
219
212
  const phaseState = {
220
- url: initialUrl,
213
+ url: await navigationContext.driver.url(),
221
214
  gatherMode: /** @type {const} */ ('navigation'),
222
215
  driver: navigationContext.driver,
223
216
  computedCache: navigationContext.computedCache,
@@ -231,19 +224,7 @@ async function _navigation(navigationContext) {
231
224
  await collectPhaseArtifacts({phase: 'startInstrumentation', ...phaseState});
232
225
  await collectPhaseArtifacts({phase: 'startSensitiveInstrumentation', ...phaseState});
233
226
  const navigateResult = await _navigate(navigationContext);
234
-
235
- // Every required url is initialized to an empty string in `getBaseArtifacts`.
236
- // If we haven't set all the required urls yet, set them here.
237
- if (!Object.values(phaseState.baseArtifacts).every(Boolean)) {
238
- phaseState.baseArtifacts.URL = {
239
- initialUrl,
240
- requestedUrl: navigateResult.requestedUrl,
241
- mainDocumentUrl: navigateResult.mainDocumentUrl,
242
- finalUrl: navigateResult.mainDocumentUrl,
243
- };
244
- }
245
- phaseState.url = navigateResult.mainDocumentUrl;
246
-
227
+ phaseState.url = navigateResult.finalUrl;
247
228
  await collectPhaseArtifacts({phase: 'stopSensitiveInstrumentation', ...phaseState});
248
229
  await collectPhaseArtifacts({phase: 'stopInstrumentation', ...phaseState});
249
230
  await _cleanupNavigation(navigationContext);
@@ -281,6 +262,11 @@ async function _navigations({driver, config, requestor, baseArtifacts, computedC
281
262
  artifacts.PageLoadError = navigationResult.pageLoadError;
282
263
  shouldHaltNavigations = true;
283
264
  }
265
+
266
+ artifacts.URL = {
267
+ requestedUrl: navigationResult.requestedUrl,
268
+ finalUrl: navigationResult.finalUrl,
269
+ };
284
270
  }
285
271
 
286
272
  LighthouseRunWarnings.push(...navigationResult.warnings);
@@ -302,12 +288,12 @@ async function _cleanup({requestedUrl, driver, config}) {
302
288
  }
303
289
 
304
290
  /**
305
- * @param {LH.NavigationRequestor|undefined} requestor
306
- * @param {{page?: LH.Puppeteer.Page, config?: LH.Config.Json, configContext?: LH.Config.FRContext}} options
291
+ * @param {LH.NavigationRequestor} requestor
292
+ * @param {{page: import('puppeteer').Page, config?: LH.Config.Json, configContext?: LH.Config.FRContext}} options
307
293
  * @return {Promise<LH.Gatherer.FRGatherResult>}
308
294
  */
309
295
  async function navigationGather(requestor, options) {
310
- const {configContext = {}} = options;
296
+ const {page, configContext = {}} = options;
311
297
  log.setLevel(configContext.logLevel || 'error');
312
298
 
313
299
  const {config} = initializeConfig(options.config, {...configContext, gatherMode: 'navigation'});
@@ -317,29 +303,18 @@ async function navigationGather(requestor, options) {
317
303
  };
318
304
 
319
305
  // We can't trigger the navigation through user interaction if we reset the page before starting.
320
- const isCallback = typeof requestor === 'function';
321
- if (isCallback) {
306
+ if (typeof requestor !== 'string') {
322
307
  internalOptions.skipAboutBlank = true;
323
308
  }
324
309
 
325
310
  const runnerOptions = {config, computedCache};
326
311
  const artifacts = await Runner.gather(
327
312
  async () => {
328
- let {page} = options;
329
-
330
- // For navigation mode, we shouldn't connect to a browser in audit mode,
331
- // therefore we connect to the browser in the gatherFn callback.
332
- if (!page) {
333
- const {hostname = DEFAULT_HOSTNAME, port = DEFAULT_PORT} = configContext;
334
- const browser = await puppeteer.connect({browserURL: `http://${hostname}:${port}`});
335
- page = await browser.newPage();
336
- }
337
-
338
313
  const driver = new Driver(page);
339
314
  const context = {
340
315
  driver,
341
316
  config,
342
- requestor: isCallback ? requestor : URL.normalizeUrl(requestor),
317
+ requestor: typeof requestor === 'string' ? URL.normalizeUrl(requestor) : requestor,
343
318
  options: internalOptions,
344
319
  };
345
320
  const {baseArtifacts} = await _setup(context);
@@ -15,6 +15,7 @@
15
15
  * @property {LH.Gatherer.GatherMode} gatherMode
16
16
  * @property {Map<string, LH.ArbitraryEqualityMap>} computedCache
17
17
  * @property {LH.Config.Settings} settings
18
+ * @property {string} url
18
19
  */
19
20
 
20
21
  /** @typedef {Record<string, Promise<any>>} IntermediateArtifacts */
@@ -74,6 +75,7 @@ async function collectPhaseArtifacts(options) {
74
75
  gatherMode,
75
76
  computedCache,
76
77
  settings,
78
+ url,
77
79
  } = options;
78
80
  const priorPhase = phaseToPriorPhase[phase];
79
81
  const priorPhaseArtifacts = (priorPhase && artifactState[priorPhase]) || {};
@@ -90,6 +92,7 @@ async function collectPhaseArtifacts(options) {
90
92
  : /** @type {Dependencies} */ ({});
91
93
 
92
94
  return gatherer[phase]({
95
+ url,
93
96
  gatherMode,
94
97
  driver,
95
98
  baseArtifacts,