lighthouse 11.7.1 → 12.0.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 (272) hide show
  1. package/CONTRIBUTING.md +2 -2
  2. package/cli/bin.js +0 -7
  3. package/cli/cli-flags.d.ts +1 -5
  4. package/cli/cli-flags.js +4 -8
  5. package/cli/test/smokehouse/__snapshots__/report-assert-test.js.snap +14 -14
  6. package/cli/test/smokehouse/config/exclusions.js +3 -0
  7. package/cli/test/smokehouse/core-tests.js +6 -20
  8. package/cli/test/smokehouse/frontends/smokehouse-bin.js +2 -2
  9. package/core/audits/accessibility/aria-conditional-attr.d.ts +10 -0
  10. package/core/audits/accessibility/aria-conditional-attr.js +43 -0
  11. package/core/audits/accessibility/{duplicate-id-active.d.ts → aria-deprecated-role.d.ts} +3 -3
  12. package/core/audits/accessibility/aria-deprecated-role.js +43 -0
  13. package/core/audits/accessibility/aria-prohibited-attr.d.ts +10 -0
  14. package/core/audits/accessibility/aria-prohibited-attr.js +44 -0
  15. package/core/audits/accessibility/target-size.js +0 -1
  16. package/core/audits/byte-efficiency/byte-efficiency-audit.d.ts +0 -16
  17. package/core/audits/byte-efficiency/byte-efficiency-audit.js +1 -38
  18. package/core/audits/byte-efficiency/offscreen-images.d.ts +0 -11
  19. package/core/audits/byte-efficiency/offscreen-images.js +0 -15
  20. package/core/audits/byte-efficiency/render-blocking-resources.js +27 -26
  21. package/core/audits/byte-efficiency/unminified-css.js +2 -2
  22. package/core/audits/byte-efficiency/unused-css-rules.js +3 -1
  23. package/core/audits/dobetterweb/uses-http2.d.ts +0 -13
  24. package/core/audits/dobetterweb/uses-http2.js +4 -38
  25. package/core/audits/font-display.js +2 -2
  26. package/core/audits/layout-shifts.js +1 -1
  27. package/core/audits/preload-fonts.d.ts +1 -5
  28. package/core/audits/preload-fonts.js +1 -10
  29. package/core/audits/prioritize-lcp-image.js +2 -2
  30. package/core/audits/redirects-http.d.ts +19 -0
  31. package/core/audits/redirects-http.js +75 -0
  32. package/core/audits/resource-summary.d.ts +2 -0
  33. package/core/audits/resource-summary.js +5 -4
  34. package/core/audits/seo/is-crawlable.d.ts +2 -1
  35. package/core/audits/seo/link-text.js +12 -0
  36. package/core/audits/uses-rel-preload.d.ts +1 -5
  37. package/core/audits/uses-rel-preload.js +5 -15
  38. package/core/audits/work-during-interaction.d.ts +2 -2
  39. package/core/audits/work-during-interaction.js +2 -2
  40. package/core/computed/js-bundles.d.ts +1 -1
  41. package/core/computed/metrics/lantern-first-contentful-paint.d.ts +13 -82
  42. package/core/computed/metrics/lantern-first-contentful-paint.js +16 -178
  43. package/core/computed/metrics/lantern-first-meaningful-paint.d.ts +13 -12
  44. package/core/computed/metrics/lantern-first-meaningful-paint.js +11 -49
  45. package/core/computed/metrics/lantern-interactive.d.ts +13 -21
  46. package/core/computed/metrics/lantern-interactive.js +12 -84
  47. package/core/computed/metrics/lantern-largest-contentful-paint.d.ts +13 -25
  48. package/core/computed/metrics/lantern-largest-contentful-paint.js +13 -80
  49. package/core/computed/metrics/lantern-max-potential-fid.d.ts +13 -24
  50. package/core/computed/metrics/lantern-max-potential-fid.js +12 -64
  51. package/core/computed/metrics/lantern-metric.d.ts +14 -18
  52. package/core/computed/metrics/lantern-metric.js +34 -30
  53. package/core/computed/metrics/lantern-speed-index.d.ts +13 -32
  54. package/core/computed/metrics/lantern-speed-index.js +13 -116
  55. package/core/computed/metrics/lantern-total-blocking-time.d.ts +13 -25
  56. package/core/computed/metrics/lantern-total-blocking-time.js +10 -94
  57. package/core/computed/metrics/metric.js +1 -3
  58. package/core/computed/module-duplication.d.ts +1 -1
  59. package/core/computed/navigation-insights.d.ts +36 -0
  60. package/core/computed/navigation-insights.js +35 -0
  61. package/core/computed/page-dependency-graph.js +3 -7
  62. package/core/computed/resource-summary.d.ts +10 -12
  63. package/core/computed/resource-summary.js +12 -19
  64. package/core/computed/trace-engine-result.d.ts +16 -3
  65. package/core/computed/trace-engine-result.js +19 -14
  66. package/core/computed/unused-css.d.ts +3 -1
  67. package/core/computed/unused-css.js +6 -5
  68. package/core/config/config-helpers.js +0 -4
  69. package/core/config/constants.js +0 -1
  70. package/core/config/default-config.js +63 -142
  71. package/core/config/experimental-config.js +11 -0
  72. package/core/config/filters.js +0 -1
  73. package/core/gather/driver/navigation.js +4 -1
  74. package/core/gather/driver/prepare.js +1 -1
  75. package/core/gather/driver/target-manager.js +4 -3
  76. package/core/gather/driver/wait-for-condition.js +2 -3
  77. package/core/gather/driver.d.ts +12 -0
  78. package/core/gather/driver.js +27 -0
  79. package/core/gather/gatherers/accessibility.js +4 -6
  80. package/core/gather/gatherers/css-usage.d.ts +0 -21
  81. package/core/gather/gatherers/css-usage.js +9 -119
  82. package/core/gather/gatherers/root-causes.d.ts +2 -2
  83. package/core/gather/gatherers/root-causes.js +6 -5
  84. package/core/gather/gatherers/stylesheets.d.ts +26 -0
  85. package/core/gather/gatherers/stylesheets.js +138 -0
  86. package/core/gather/gatherers/trace-elements.d.ts +2 -12
  87. package/core/gather/gatherers/trace-elements.js +2 -21
  88. package/core/gather/navigation-runner.js +3 -1
  89. package/core/gather/session.d.ts +8 -0
  90. package/core/gather/session.js +14 -1
  91. package/core/lib/emulation.js +2 -2
  92. package/core/lib/i18n/i18n.d.ts +0 -1
  93. package/core/lib/i18n/i18n.js +0 -2
  94. package/core/lib/lantern/cpu-node.d.ts +7 -1
  95. package/core/lib/lantern/cpu-node.js +12 -2
  96. package/core/lib/lantern/lantern-error.d.ts +8 -0
  97. package/core/lib/lantern/lantern-error.js +9 -0
  98. package/core/lib/lantern/metric.js +2 -6
  99. package/core/lib/lantern/metrics/first-contentful-paint.d.ts +79 -0
  100. package/core/lib/lantern/metrics/first-contentful-paint.js +200 -0
  101. package/core/lib/lantern/metrics/first-meaningful-paint.d.ts +6 -0
  102. package/core/lib/lantern/metrics/first-meaningful-paint.js +64 -0
  103. package/core/lib/lantern/metrics/interactive.d.ts +26 -0
  104. package/core/lib/lantern/metrics/interactive.js +112 -0
  105. package/core/lib/lantern/metrics/largest-contentful-paint.d.ts +19 -0
  106. package/core/lib/lantern/metrics/largest-contentful-paint.js +108 -0
  107. package/core/lib/lantern/metrics/max-potential-fid.d.ts +30 -0
  108. package/core/lib/lantern/metrics/max-potential-fid.js +92 -0
  109. package/core/lib/lantern/metrics/speed-index.d.ts +38 -0
  110. package/core/lib/lantern/metrics/speed-index.js +144 -0
  111. package/core/lib/lantern/metrics/total-blocking-time.d.ts +31 -0
  112. package/core/lib/lantern/metrics/total-blocking-time.js +128 -0
  113. package/core/lib/lantern/network-node.js +28 -4
  114. package/core/lib/lantern/page-dependency-graph.d.ts +4 -4
  115. package/core/lib/lantern/page-dependency-graph.js +19 -7
  116. package/core/lib/lantern/simulator/connection-pool.d.ts +2 -12
  117. package/core/lib/lantern/simulator/connection-pool.js +3 -22
  118. package/core/lib/lantern/simulator/network-analyzer.js +1 -12
  119. package/core/lib/lantern/simulator/simulator.d.ts +2 -4
  120. package/core/lib/lantern/simulator/simulator.js +7 -14
  121. package/core/lib/lantern/types/lantern.d.ts +5 -3
  122. package/core/lib/lantern-trace-saver.js +0 -1
  123. package/core/lib/lh-error.d.ts +9 -0
  124. package/core/lib/lh-error.js +13 -3
  125. package/core/lib/lighthouse-compatibility.js +53 -10
  126. package/core/lib/navigation-error.js +3 -0
  127. package/core/lib/network-request.d.ts +1 -0
  128. package/core/lib/network-request.js +28 -0
  129. package/core/runner.js +18 -25
  130. package/dist/report/bundle.esm.js +11 -112
  131. package/dist/report/flow.js +16 -117
  132. package/dist/report/standalone.js +12 -113
  133. package/flow-report/src/help-dialog.tsx +0 -1
  134. package/flow-report/src/i18n/i18n.d.ts +0 -4
  135. package/flow-report/src/i18n/ui-strings.d.ts +0 -1
  136. package/flow-report/src/i18n/ui-strings.js +0 -2
  137. package/flow-report/src/summary/category.tsx +10 -12
  138. package/package.json +5 -5
  139. package/readme.md +4 -4
  140. package/report/assets/styles.css +1 -60
  141. package/report/assets/templates.html +0 -95
  142. package/report/renderer/category-renderer.js +1 -1
  143. package/report/renderer/components.d.ts +2 -2
  144. package/report/renderer/components.js +2 -103
  145. package/report/renderer/dom.d.ts +1 -1
  146. package/report/renderer/dom.js +1 -1
  147. package/report/renderer/performance-category-renderer.d.ts +0 -7
  148. package/report/renderer/performance-category-renderer.js +1 -32
  149. package/report/renderer/report-renderer.js +3 -13
  150. package/report/renderer/report-ui-features.js +1 -1
  151. package/report/renderer/report-utils.d.ts +0 -1
  152. package/report/renderer/report-utils.js +13 -13
  153. package/shared/localization/locales/ar-XB.json +62 -329
  154. package/shared/localization/locales/ar.json +62 -329
  155. package/shared/localization/locales/bg.json +62 -329
  156. package/shared/localization/locales/ca.json +62 -329
  157. package/shared/localization/locales/cs.json +62 -329
  158. package/shared/localization/locales/da.json +62 -329
  159. package/shared/localization/locales/de.json +62 -329
  160. package/shared/localization/locales/el.json +62 -329
  161. package/shared/localization/locales/en-GB.json +62 -329
  162. package/shared/localization/locales/en-US.json +41 -272
  163. package/shared/localization/locales/en-XA.json +62 -329
  164. package/shared/localization/locales/en-XL.json +41 -272
  165. package/shared/localization/locales/es-419.json +62 -329
  166. package/shared/localization/locales/es.json +62 -329
  167. package/shared/localization/locales/fi.json +62 -329
  168. package/shared/localization/locales/fil.json +61 -328
  169. package/shared/localization/locales/fr.json +62 -329
  170. package/shared/localization/locales/he.json +62 -329
  171. package/shared/localization/locales/hi.json +62 -329
  172. package/shared/localization/locales/hr.json +63 -330
  173. package/shared/localization/locales/hu.json +62 -329
  174. package/shared/localization/locales/id.json +62 -329
  175. package/shared/localization/locales/it.json +62 -329
  176. package/shared/localization/locales/ja.json +62 -329
  177. package/shared/localization/locales/ko.json +62 -329
  178. package/shared/localization/locales/lt.json +62 -329
  179. package/shared/localization/locales/lv.json +62 -329
  180. package/shared/localization/locales/nl.json +62 -329
  181. package/shared/localization/locales/no.json +62 -329
  182. package/shared/localization/locales/pl.json +61 -328
  183. package/shared/localization/locales/pt-PT.json +62 -329
  184. package/shared/localization/locales/pt.json +64 -331
  185. package/shared/localization/locales/ro.json +62 -329
  186. package/shared/localization/locales/ru.json +62 -329
  187. package/shared/localization/locales/sk.json +62 -329
  188. package/shared/localization/locales/sl.json +62 -329
  189. package/shared/localization/locales/sr-Latn.json +62 -329
  190. package/shared/localization/locales/sr.json +62 -329
  191. package/shared/localization/locales/sv.json +62 -329
  192. package/shared/localization/locales/ta.json +61 -328
  193. package/shared/localization/locales/te.json +62 -329
  194. package/shared/localization/locales/th.json +62 -329
  195. package/shared/localization/locales/tr.json +62 -329
  196. package/shared/localization/locales/uk.json +62 -329
  197. package/shared/localization/locales/vi.json +61 -328
  198. package/shared/localization/locales/zh-HK.json +62 -329
  199. package/shared/localization/locales/zh-TW.json +61 -328
  200. package/shared/localization/locales/zh.json +62 -329
  201. package/tsconfig.json +1 -3
  202. package/types/artifacts.d.ts +21 -110
  203. package/types/audit.d.ts +0 -10
  204. package/types/config.d.ts +0 -1
  205. package/types/externs.d.ts +0 -2
  206. package/types/gatherer.d.ts +3 -0
  207. package/types/internal/smokehouse.d.ts +1 -1
  208. package/types/lh.d.ts +0 -2
  209. package/types/lhr/audit-details.d.ts +9 -4
  210. package/types/lhr/lhr.d.ts +0 -4
  211. package/types/lhr/settings.d.ts +0 -4
  212. package/core/audits/accessibility/duplicate-id-active.js +0 -42
  213. package/core/audits/content-width.d.ts +0 -17
  214. package/core/audits/content-width.js +0 -76
  215. package/core/audits/installable-manifest.d.ts +0 -111
  216. package/core/audits/installable-manifest.js +0 -248
  217. package/core/audits/layout-shift-elements.d.ts +0 -16
  218. package/core/audits/layout-shift-elements.js +0 -101
  219. package/core/audits/manual/pwa-cross-browser.d.ts +0 -12
  220. package/core/audits/manual/pwa-cross-browser.js +0 -40
  221. package/core/audits/manual/pwa-each-page-has-url.d.ts +0 -12
  222. package/core/audits/manual/pwa-each-page-has-url.js +0 -38
  223. package/core/audits/manual/pwa-page-transitions.d.ts +0 -12
  224. package/core/audits/manual/pwa-page-transitions.js +0 -38
  225. package/core/audits/maskable-icon.d.ts +0 -25
  226. package/core/audits/maskable-icon.js +0 -70
  227. package/core/audits/multi-check-audit.d.ts +0 -28
  228. package/core/audits/multi-check-audit.js +0 -82
  229. package/core/audits/no-unload-listeners.d.ts +0 -16
  230. package/core/audits/no-unload-listeners.js +0 -86
  231. package/core/audits/performance-budget.d.ts +0 -39
  232. package/core/audits/performance-budget.js +0 -154
  233. package/core/audits/script-elements-test-audit.d.ts +0 -14
  234. package/core/audits/script-elements-test-audit.js +0 -29
  235. package/core/audits/seo/plugins.d.ts +0 -15
  236. package/core/audits/seo/plugins.js +0 -150
  237. package/core/audits/seo/tap-targets.d.ts +0 -50
  238. package/core/audits/seo/tap-targets.js +0 -352
  239. package/core/audits/splash-screen.d.ts +0 -37
  240. package/core/audits/splash-screen.js +0 -98
  241. package/core/audits/themed-omnibox.d.ts +0 -42
  242. package/core/audits/themed-omnibox.js +0 -102
  243. package/core/audits/timing-budget.d.ts +0 -43
  244. package/core/audits/timing-budget.js +0 -175
  245. package/core/computed/manifest-values.d.ts +0 -24
  246. package/core/computed/manifest-values.js +0 -136
  247. package/core/config/budget.d.ts +0 -74
  248. package/core/config/budget.js +0 -340
  249. package/core/config/metrics-to-audits.d.ts +0 -19
  250. package/core/config/metrics-to-audits.js +0 -62
  251. package/core/gather/driver/service-workers.d.ts +0 -16
  252. package/core/gather/driver/service-workers.js +0 -52
  253. package/core/gather/gatherers/dobetterweb/tags-blocking-first-paint.d.ts +0 -47
  254. package/core/gather/gatherers/dobetterweb/tags-blocking-first-paint.js +0 -233
  255. package/core/gather/gatherers/global-listeners.d.ts +0 -27
  256. package/core/gather/gatherers/global-listeners.js +0 -108
  257. package/core/gather/gatherers/installability-errors.d.ts +0 -17
  258. package/core/gather/gatherers/installability-errors.js +0 -56
  259. package/core/gather/gatherers/script-elements.d.ts +0 -21
  260. package/core/gather/gatherers/script-elements.js +0 -100
  261. package/core/gather/gatherers/seo/embedded-content.d.ts +0 -10
  262. package/core/gather/gatherers/seo/embedded-content.js +0 -63
  263. package/core/gather/gatherers/seo/tap-targets.d.ts +0 -21
  264. package/core/gather/gatherers/seo/tap-targets.js +0 -389
  265. package/core/gather/gatherers/service-worker.d.ts +0 -10
  266. package/core/gather/gatherers/service-worker.js +0 -32
  267. package/core/gather/gatherers/web-app-manifest.d.ts +0 -32
  268. package/core/gather/gatherers/web-app-manifest.js +0 -106
  269. package/report/renderer/pwa-category-renderer.d.ts +0 -55
  270. package/report/renderer/pwa-category-renderer.js +0 -184
  271. package/third-party/chromium-synchronization/installability-errors-test.js +0 -79
  272. package/types/lhr/budget.d.ts +0 -60
@@ -1,233 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright 2016 Google LLC
4
- * SPDX-License-Identifier: Apache-2.0
5
- */
6
- /**
7
- * @fileoverview
8
- * Identifies stylesheets, HTML Imports, and scripts that potentially block
9
- * the first paint of the page by running several scripts in the page context.
10
- * Candidate blocking tags are collected by querying for all script tags in
11
- * the head of the page and all link tags that are either matching media
12
- * stylesheets or non-async HTML imports. These are then compared to the
13
- * network requests to ensure they were initiated by the parser and not
14
- * injected with script. To avoid false positives from strategies like
15
- * (http://filamentgroup.github.io/loadCSS/test/preload.html), a separate
16
- * script is run to flag all links that at one point were rel=preload.
17
- */
18
-
19
-
20
- import {NetworkRecords} from '../../../computed/network-records.js';
21
- import DevtoolsLog from '../devtools-log.js';
22
- import BaseGatherer from '../../base-gatherer.js';
23
-
24
- /* global document, window, HTMLLinkElement, SVGScriptElement */
25
-
26
- /** @typedef {{href: string, media: string, msSinceHTMLEnd: number, matches: boolean}} MediaChange */
27
- /** @typedef {{tagName: 'LINK', url: string, href: string, rel: string, media: string, disabled: boolean, mediaChanges: Array<MediaChange>}} LinkTag */
28
- /** @typedef {{tagName: 'SCRIPT', url: string, src: string}} ScriptTag */
29
-
30
- /* c8 ignore start */
31
- function installMediaListener() {
32
- // @ts-expect-error - inserted in page to track media changes.
33
- window.___linkMediaChanges = [];
34
- Object.defineProperty(HTMLLinkElement.prototype, 'media', {
35
- set: function(val) {
36
- /** @type {MediaChange} */
37
- const mediaChange = {
38
- href: this.href,
39
- media: val,
40
- msSinceHTMLEnd: Date.now() - performance.timing.responseEnd,
41
- matches: window.matchMedia(val).matches,
42
- };
43
- // @ts-expect-error - `___linkMediaChanges` created above.
44
- window.___linkMediaChanges.push(mediaChange);
45
-
46
- this.setAttribute('media', val);
47
- },
48
- });
49
- }
50
- /* c8 ignore stop */
51
-
52
- /**
53
- * @return {Promise<Array<LinkTag | ScriptTag>>}
54
- */
55
- /* c8 ignore start */
56
- async function collectTagsThatBlockFirstPaint() {
57
- /** @type {Array<MediaChange>} */
58
- // @ts-expect-error - `___linkMediaChanges` created in `installMediaListener`.
59
- const linkMediaChanges = window.___linkMediaChanges;
60
-
61
- try {
62
- /** @type {Array<LinkTag>} */
63
- const linkTags = [...document.querySelectorAll('link')]
64
- .filter(linkTag => {
65
- // Ignore malformed links with no href (e.g. `<link rel="stylesheet" href="">`)
66
- // The resolved `linkTag.href` will be the main document, but the main document
67
- // should never be render blocking.
68
- if (!linkTag.getAttribute('href')) return false;
69
-
70
- // Filter stylesheet/HTML imports that block rendering.
71
- // https://www.igvita.com/2012/06/14/debunking-responsive-css-performance-myths/
72
- // https://www.w3.org/TR/html-imports/#dfn-import-async-attribute
73
- const blockingStylesheet = linkTag.rel === 'stylesheet' &&
74
- window.matchMedia(linkTag.media).matches && !linkTag.disabled;
75
- const blockingImport = linkTag.rel === 'import' && !linkTag.hasAttribute('async');
76
- return blockingStylesheet || blockingImport;
77
- })
78
- .map(tag => {
79
- return {
80
- tagName: 'LINK',
81
- url: tag.href,
82
- href: tag.href,
83
- rel: tag.rel,
84
- media: tag.media,
85
- disabled: tag.disabled,
86
- mediaChanges: linkMediaChanges.filter(item => item.href === tag.href),
87
- };
88
- });
89
-
90
- /** @type {Array<ScriptTag>} */
91
- const scriptTags = [...document.querySelectorAll('head script[src]')]
92
- .filter(/** @return {scriptTag is HTMLScriptElement} */ scriptTag => {
93
- // SVGScriptElement can't appear in <head> (it'll be kicked to <body>), but keep tsc happy.
94
- // https://html.spec.whatwg.org/multipage/semantics.html#the-head-element
95
- if (scriptTag instanceof SVGScriptElement) return false;
96
-
97
- return (
98
- !scriptTag.hasAttribute('async') &&
99
- !scriptTag.hasAttribute('defer') &&
100
- !/^data:/.test(scriptTag.src) &&
101
- !/^blob:/.test(scriptTag.src) &&
102
- scriptTag.getAttribute('type') !== 'module'
103
- );
104
- })
105
- .map(tag => {
106
- return {
107
- tagName: 'SCRIPT',
108
- url: tag.src,
109
- src: tag.src,
110
- };
111
- });
112
-
113
- return [...linkTags, ...scriptTags];
114
- } catch (e) {
115
- const friendly = 'Unable to gather Scripts/Stylesheets/HTML Imports on the page';
116
- throw new Error(`${friendly}: ${e.message}`);
117
- }
118
- }
119
- /* c8 ignore stop */
120
-
121
- class TagsBlockingFirstPaint extends BaseGatherer {
122
- /** @type {LH.Gatherer.GathererMeta<'DevtoolsLog'>} */
123
- meta = {
124
- supportedModes: ['navigation'],
125
- dependencies: {DevtoolsLog: DevtoolsLog.symbol},
126
- };
127
-
128
- /**
129
- * @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
130
- * @return {Map<string, LH.Artifacts.NetworkRequest>}
131
- */
132
- static _filteredAndIndexedByUrl(networkRecords) {
133
- /** @type {Map<string, LH.Artifacts.NetworkRequest>} */
134
- const result = new Map();
135
-
136
- for (const record of networkRecords) {
137
- if (!record.finished) continue;
138
-
139
- const isParserGenerated = record.initiator.type === 'parser';
140
- // A stylesheet only blocks script if it was initiated by the parser
141
- // https://html.spec.whatwg.org/multipage/semantics.html#interactions-of-styling-and-scripting
142
- const isParserScriptOrStyle = /(css|script)/.test(record.mimeType) && isParserGenerated;
143
- const isFailedRequest = record.failed;
144
- const isHtml = record.mimeType && record.mimeType.includes('html');
145
-
146
- // Filter stylesheet, javascript, and html import mimetypes.
147
- // Include 404 scripts/links generated by the parser because they are likely blocking.
148
- if (isHtml || isParserScriptOrStyle || (isFailedRequest && isParserGenerated)) {
149
- result.set(record.url, record);
150
- }
151
- }
152
-
153
- return result;
154
- }
155
-
156
- /**
157
- * @param {LH.Gatherer.Driver} driver
158
- * @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
159
- * @return {Promise<Array<LH.Artifacts.TagBlockingFirstPaint>>}
160
- */
161
- static async findBlockingTags(driver, networkRecords) {
162
- const firstRequestEndTime = networkRecords.reduce(
163
- (min, record) => Math.min(min, record.networkEndTime),
164
- Infinity
165
- );
166
- const tags = await driver.executionContext.evaluate(collectTagsThatBlockFirstPaint, {args: []});
167
- const requests = TagsBlockingFirstPaint._filteredAndIndexedByUrl(networkRecords);
168
-
169
- /** @type {Array<LH.Artifacts.TagBlockingFirstPaint>} */
170
- const result = [];
171
- for (const tag of tags) {
172
- const request = requests.get(tag.url);
173
- if (!request || request.isLinkPreload) continue;
174
-
175
- let endTime = request.networkEndTime;
176
- let mediaChanges;
177
-
178
- if (tag.tagName === 'LINK') {
179
- // Even if the request was initially blocking or appeared to be blocking once the
180
- // page was loaded, the media attribute could have been changed during load, capping the
181
- // amount of time it was render blocking. See https://github.com/GoogleChrome/lighthouse/issues/2832.
182
- const timesResourceBecameNonBlocking = tag.mediaChanges
183
- .filter(change => !change.matches)
184
- .map(change => change.msSinceHTMLEnd);
185
- if (timesResourceBecameNonBlocking.length > 0) {
186
- const earliestNonBlockingTime = Math.min(...timesResourceBecameNonBlocking);
187
- const lastTimeResourceWasBlocking = Math.max(
188
- request.networkRequestTime,
189
- firstRequestEndTime + earliestNonBlockingTime / 1000
190
- );
191
- endTime = Math.min(endTime, lastTimeResourceWasBlocking);
192
- }
193
-
194
- mediaChanges = tag.mediaChanges;
195
- }
196
-
197
- const {tagName, url} = tag;
198
-
199
- result.push({
200
- tag: {tagName, url, mediaChanges},
201
- transferSize: request.transferSize,
202
- startTime: request.networkRequestTime,
203
- endTime,
204
- });
205
-
206
- // Prevent duplicates from showing up again
207
- requests.delete(tag.url);
208
- }
209
-
210
- return result;
211
- }
212
-
213
- /**
214
- * @param {LH.Gatherer.Context} context
215
- */
216
- async startSensitiveInstrumentation(context) {
217
- const {executionContext} = context.driver;
218
- // Don't return return value of `evaluateOnNewDocument`.
219
- await executionContext.evaluateOnNewDocument(installMediaListener, {args: []});
220
- }
221
-
222
- /**
223
- * @param {LH.Gatherer.Context<'DevtoolsLog'>} context
224
- * @return {Promise<LH.Artifacts['TagsBlockingFirstPaint']>}
225
- */
226
- async getArtifact(context) {
227
- const devtoolsLog = context.dependencies.DevtoolsLog;
228
- const networkRecords = await NetworkRecords.request(devtoolsLog, context);
229
- return TagsBlockingFirstPaint.findBlockingTags(context.driver, networkRecords);
230
- }
231
- }
232
-
233
- export default TagsBlockingFirstPaint;
@@ -1,27 +0,0 @@
1
- export default GlobalListeners;
2
- declare class GlobalListeners extends BaseGatherer {
3
- /**
4
- * @param {LH.Crdp.DOMDebugger.EventListener} listener
5
- * @return {listener is {type: 'pagehide'|'unload'|'visibilitychange'} & LH.Crdp.DOMDebugger.EventListener}
6
- */
7
- static _filterForAllowlistedTypes(listener: LH.Crdp.DOMDebugger.EventListener): listener is {
8
- type: 'pagehide' | 'unload' | 'visibilitychange';
9
- } & import("devtools-protocol").Protocol.DOMDebugger.EventListener;
10
- /**
11
- * @param { LH.Artifacts.GlobalListener } listener
12
- * @return { string }
13
- */
14
- getListenerIndentifier(listener: LH.Artifacts.GlobalListener): string;
15
- /**
16
- * @param { LH.Artifacts['GlobalListeners'] } listeners
17
- * @return { LH.Artifacts['GlobalListeners'] }
18
- */
19
- dedupeListeners(listeners: LH.Artifacts['GlobalListeners']): LH.Artifacts['GlobalListeners'];
20
- /**
21
- * @param {LH.Gatherer.Context} passContext
22
- * @return {Promise<LH.Artifacts['GlobalListeners']>}
23
- */
24
- getArtifact(passContext: LH.Gatherer.Context): Promise<LH.Artifacts['GlobalListeners']>;
25
- }
26
- import BaseGatherer from '../base-gatherer.js';
27
- //# sourceMappingURL=global-listeners.d.ts.map
@@ -1,108 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright 2020 Google LLC
4
- * SPDX-License-Identifier: Apache-2.0
5
- */
6
-
7
- /**
8
- * @fileoverview
9
- * A gatherer to collect information about the event listeners registered on the
10
- * global object. For now, the scope is narrowed to events that occur on and
11
- * around page unload, but this can be expanded in the future.
12
- */
13
-
14
- import log from 'lighthouse-logger';
15
-
16
- import BaseGatherer from '../base-gatherer.js';
17
-
18
- class GlobalListeners extends BaseGatherer {
19
- /** @type {LH.Gatherer.GathererMeta} */
20
- meta = {
21
- supportedModes: ['snapshot', 'timespan', 'navigation'],
22
- };
23
-
24
- /**
25
- * @param {LH.Crdp.DOMDebugger.EventListener} listener
26
- * @return {listener is {type: 'pagehide'|'unload'|'visibilitychange'} & LH.Crdp.DOMDebugger.EventListener}
27
- */
28
- static _filterForAllowlistedTypes(listener) {
29
- return listener.type === 'pagehide' ||
30
- listener.type === 'unload' ||
31
- listener.type === 'visibilitychange';
32
- }
33
-
34
- /**
35
- * @param { LH.Artifacts.GlobalListener } listener
36
- * @return { string }
37
- */
38
- getListenerIndentifier(listener) {
39
- return `${listener.type}:${listener.scriptId}:${listener.columnNumber}:${listener.lineNumber}`;
40
- }
41
-
42
- /**
43
- * @param { LH.Artifacts['GlobalListeners'] } listeners
44
- * @return { LH.Artifacts['GlobalListeners'] }
45
- */
46
- dedupeListeners(listeners) {
47
- const seenListeners = new Set();
48
- return listeners.filter(listener => {
49
- const id = this.getListenerIndentifier(listener);
50
- if (!seenListeners.has(id)) {
51
- seenListeners.add(id);
52
- return true;
53
- } else {
54
- return false;
55
- }
56
- });
57
- }
58
-
59
- /**
60
- * @param {LH.Gatherer.Context} passContext
61
- * @return {Promise<LH.Artifacts['GlobalListeners']>}
62
- */
63
- async getArtifact(passContext) {
64
- const session = passContext.driver.defaultSession;
65
-
66
- /** @type {Array<LH.Artifacts.GlobalListener>} */
67
- const listeners = [];
68
-
69
- for (const executionContext of passContext.driver.targetManager.mainFrameExecutionContexts()) {
70
- // Get a RemoteObject handle to `window`.
71
- let objectId;
72
- try {
73
- const {result} = await session.sendCommand('Runtime.evaluate', {
74
- expression: 'window',
75
- returnByValue: false,
76
- uniqueContextId: executionContext.uniqueId,
77
- });
78
- if (!result.objectId) {
79
- throw new Error('Error fetching information about the global object');
80
- }
81
- objectId = result.objectId;
82
- } catch (err) {
83
- // Execution context is no longer valid, but don't let that fail the gatherer.
84
- log.warn('Execution context is no longer valid', executionContext, err);
85
- continue;
86
- }
87
-
88
- // And get all its listeners of interest.
89
- const response = await session.sendCommand('DOMDebugger.getEventListeners', {objectId});
90
- for (const listener of response.listeners) {
91
- if (GlobalListeners._filterForAllowlistedTypes(listener)) {
92
- const {type, scriptId, lineNumber, columnNumber} = listener;
93
- listeners.push({
94
- type,
95
- scriptId,
96
- lineNumber,
97
- columnNumber,
98
- });
99
- }
100
- }
101
- }
102
-
103
- // Dedupe listeners with same underlying data.
104
- return this.dedupeListeners(listeners);
105
- }
106
- }
107
-
108
- export default GlobalListeners;
@@ -1,17 +0,0 @@
1
- export default InstallabilityErrors;
2
- declare class InstallabilityErrors extends BaseGatherer {
3
- /**
4
- * Creates an Artifacts.InstallabilityErrors, tranforming data from the protocol
5
- * for old versions of Chrome.
6
- * @param {LH.Gatherer.ProtocolSession} session
7
- * @return {Promise<LH.Artifacts['InstallabilityErrors']>}
8
- */
9
- static getInstallabilityErrors(session: LH.Gatherer.ProtocolSession): Promise<LH.Artifacts['InstallabilityErrors']>;
10
- /**
11
- * @param {LH.Gatherer.Context} context
12
- * @return {Promise<LH.Artifacts['InstallabilityErrors']>}
13
- */
14
- getArtifact(context: LH.Gatherer.Context): Promise<LH.Artifacts['InstallabilityErrors']>;
15
- }
16
- import BaseGatherer from '../base-gatherer.js';
17
- //# sourceMappingURL=installability-errors.d.ts.map
@@ -1,56 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright 2021 Google LLC
4
- * SPDX-License-Identifier: Apache-2.0
5
- */
6
-
7
- import log from 'lighthouse-logger';
8
-
9
- import BaseGatherer from '../base-gatherer.js';
10
-
11
- class InstallabilityErrors extends BaseGatherer {
12
- /** @type {LH.Gatherer.GathererMeta} */
13
- meta = {
14
- supportedModes: ['snapshot', 'navigation'],
15
- };
16
-
17
- /**
18
- * Creates an Artifacts.InstallabilityErrors, tranforming data from the protocol
19
- * for old versions of Chrome.
20
- * @param {LH.Gatherer.ProtocolSession} session
21
- * @return {Promise<LH.Artifacts['InstallabilityErrors']>}
22
- */
23
- static async getInstallabilityErrors(session) {
24
- const status = {
25
- msg: 'Get webapp installability errors',
26
- id: 'lh:gather:getInstallabilityErrors',
27
- };
28
- log.time(status);
29
- const response = await session.sendCommand('Page.getInstallabilityErrors');
30
-
31
- const errors = response.installabilityErrors;
32
-
33
- log.timeEnd(status);
34
- return {errors};
35
- }
36
-
37
- /**
38
- * @param {LH.Gatherer.Context} context
39
- * @return {Promise<LH.Artifacts['InstallabilityErrors']>}
40
- */
41
- async getArtifact(context) {
42
- const driver = context.driver;
43
-
44
- try {
45
- return await InstallabilityErrors.getInstallabilityErrors(driver.defaultSession);
46
- } catch {
47
- return {
48
- errors: [
49
- {errorId: 'protocol-timeout', errorArguments: []},
50
- ],
51
- };
52
- }
53
- }
54
- }
55
-
56
- export default InstallabilityErrors;
@@ -1,21 +0,0 @@
1
- export default ScriptElements;
2
- /**
3
- * @fileoverview Gets JavaScript file contents.
4
- */
5
- declare class ScriptElements extends BaseGatherer {
6
- /** @type {LH.Gatherer.GathererMeta<'DevtoolsLog'>} */
7
- meta: LH.Gatherer.GathererMeta<'DevtoolsLog'>;
8
- /**
9
- * @param {LH.Gatherer.Context} context
10
- * @param {LH.Artifacts.NetworkRequest[]} networkRecords
11
- * @return {Promise<LH.Artifacts['ScriptElements']>}
12
- */
13
- _getArtifact(context: LH.Gatherer.Context, networkRecords: LH.Artifacts.NetworkRequest[]): Promise<LH.Artifacts['ScriptElements']>;
14
- /**
15
- * @param {LH.Gatherer.Context<'DevtoolsLog'>} context
16
- */
17
- getArtifact(context: LH.Gatherer.Context<'DevtoolsLog'>): Promise<import("../../index.js").Artifacts.ScriptElement[]>;
18
- }
19
- import BaseGatherer from '../base-gatherer.js';
20
- import { NetworkRequest } from '../../lib/network-request.js';
21
- //# sourceMappingURL=script-elements.d.ts.map
@@ -1,100 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright 2017 Google LLC
4
- * SPDX-License-Identifier: Apache-2.0
5
- */
6
-
7
- import BaseGatherer from '../base-gatherer.js';
8
- import {NetworkRecords} from '../../computed/network-records.js';
9
- import {NetworkRequest} from '../../lib/network-request.js';
10
- import {pageFunctions} from '../../lib/page-functions.js';
11
- import DevtoolsLog from './devtools-log.js';
12
-
13
- /* global getNodeDetails */
14
-
15
- /**
16
- * @return {LH.Artifacts['ScriptElements']}
17
- */
18
- /* c8 ignore start */
19
- function collectAllScriptElements() {
20
- /** @type {HTMLScriptElement[]} */
21
- // @ts-expect-error - getElementsInDocument put into scope via stringification
22
- const scripts = getElementsInDocument('script'); // eslint-disable-line no-undef
23
-
24
- return scripts.map(script => {
25
- return {
26
- type: script.type || null,
27
- src: script.src || null,
28
- id: script.id || null,
29
- async: script.async,
30
- defer: script.defer,
31
- source: script.closest('head') ? 'head' : 'body',
32
- // @ts-expect-error - getNodeDetails put into scope via stringification
33
- node: getNodeDetails(script),
34
- };
35
- });
36
- }
37
- /* c8 ignore stop */
38
-
39
- /**
40
- * @fileoverview Gets JavaScript file contents.
41
- */
42
- class ScriptElements extends BaseGatherer {
43
- /** @type {LH.Gatherer.GathererMeta<'DevtoolsLog'>} */
44
- meta = {
45
- supportedModes: ['timespan', 'navigation'],
46
- dependencies: {DevtoolsLog: DevtoolsLog.symbol},
47
- };
48
-
49
- /**
50
- * @param {LH.Gatherer.Context} context
51
- * @param {LH.Artifacts.NetworkRequest[]} networkRecords
52
- * @return {Promise<LH.Artifacts['ScriptElements']>}
53
- */
54
- async _getArtifact(context, networkRecords) {
55
- const executionContext = context.driver.executionContext;
56
-
57
- const scripts = await executionContext.evaluate(collectAllScriptElements, {
58
- args: [],
59
- useIsolation: true,
60
- deps: [
61
- pageFunctions.getNodeDetails,
62
- pageFunctions.getElementsInDocument,
63
- ],
64
- });
65
-
66
- const scriptRecords = networkRecords
67
- .filter(record => record.resourceType === NetworkRequest.TYPES.Script)
68
- .filter(record => record.sessionTargetType === 'page');
69
-
70
- for (let i = 0; i < scriptRecords.length; i++) {
71
- const record = scriptRecords[i];
72
-
73
- const matchedScriptElement = scripts.find(script => script.src === record.url);
74
- if (!matchedScriptElement) {
75
- scripts.push({
76
- type: null,
77
- src: record.url,
78
- id: null,
79
- async: false,
80
- defer: false,
81
- source: 'network',
82
- node: null,
83
- });
84
- }
85
- }
86
-
87
- return scripts;
88
- }
89
-
90
- /**
91
- * @param {LH.Gatherer.Context<'DevtoolsLog'>} context
92
- */
93
- async getArtifact(context) {
94
- const devtoolsLog = context.dependencies.DevtoolsLog;
95
- const networkRecords = await NetworkRecords.request(devtoolsLog, context);
96
- return this._getArtifact(context, networkRecords);
97
- }
98
- }
99
-
100
- export default ScriptElements;
@@ -1,10 +0,0 @@
1
- export default EmbeddedContent;
2
- declare class EmbeddedContent extends BaseGatherer {
3
- /**
4
- * @param {LH.Gatherer.Context} passContext
5
- * @return {Promise<LH.Artifacts['EmbeddedContent']>}
6
- */
7
- getArtifact(passContext: LH.Gatherer.Context): Promise<LH.Artifacts['EmbeddedContent']>;
8
- }
9
- import BaseGatherer from '../../base-gatherer.js';
10
- //# sourceMappingURL=embedded-content.d.ts.map
@@ -1,63 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright 2018 Google LLC
4
- * SPDX-License-Identifier: Apache-2.0
5
- */
6
-
7
- /* globals getElementsInDocument getNodeDetails */
8
-
9
- import BaseGatherer from '../../base-gatherer.js';
10
- import {pageFunctions} from '../../../lib/page-functions.js';
11
-
12
- /**
13
- * @return {LH.Artifacts.EmbeddedContentInfo[]}
14
- */
15
- function getEmbeddedContent() {
16
- const functions = /** @type {typeof pageFunctions} */ ({
17
- // @ts-expect-error - getElementsInDocument put into scope via stringification
18
- getElementsInDocument,
19
- // @ts-expect-error - getNodeDetails put into scope via stringification
20
- getNodeDetails,
21
- });
22
-
23
- const selector = 'object, embed, applet';
24
- const elements = functions.getElementsInDocument(selector);
25
- return elements
26
- .map(node => ({
27
- tagName: node.tagName,
28
- type: node.getAttribute('type'),
29
- src: node.getAttribute('src'),
30
- data: node.getAttribute('data'),
31
- code: node.getAttribute('code'),
32
- params: Array.from(node.children)
33
- .filter(el => el.tagName === 'PARAM')
34
- .map(el => ({
35
- name: el.getAttribute('name') || '',
36
- value: el.getAttribute('value') || '',
37
- })),
38
- node: functions.getNodeDetails(node),
39
- }));
40
- }
41
-
42
- class EmbeddedContent extends BaseGatherer {
43
- /** @type {LH.Gatherer.GathererMeta} */
44
- meta = {
45
- supportedModes: ['snapshot', 'navigation'],
46
- };
47
-
48
- /**
49
- * @param {LH.Gatherer.Context} passContext
50
- * @return {Promise<LH.Artifacts['EmbeddedContent']>}
51
- */
52
- getArtifact(passContext) {
53
- return passContext.driver.executionContext.evaluate(getEmbeddedContent, {
54
- args: [],
55
- deps: [
56
- pageFunctions.getElementsInDocument,
57
- pageFunctions.getNodeDetails,
58
- ],
59
- });
60
- }
61
- }
62
-
63
- export default EmbeddedContent;
@@ -1,21 +0,0 @@
1
- export default TapTargets;
2
- declare class TapTargets extends BaseGatherer {
3
- /**
4
- * @param {LH.Gatherer.ProtocolSession} session
5
- * @param {string} className
6
- * @return {Promise<string>}
7
- */
8
- addStyleRule(session: LH.Gatherer.ProtocolSession, className: string): Promise<string>;
9
- /**
10
- * @param {LH.Gatherer.ProtocolSession} session
11
- * @param {string} styleSheetId
12
- */
13
- removeStyleRule(session: LH.Gatherer.ProtocolSession, styleSheetId: string): Promise<void>;
14
- /**
15
- * @param {LH.Gatherer.Context} passContext
16
- * @return {Promise<LH.Artifacts.TapTarget[]>} All visible tap targets with their positions and sizes
17
- */
18
- getArtifact(passContext: LH.Gatherer.Context): Promise<LH.Artifacts.TapTarget[]>;
19
- }
20
- import BaseGatherer from '../../base-gatherer.js';
21
- //# sourceMappingURL=tap-targets.d.ts.map