lighthouse 10.4.0 → 11.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 (288) hide show
  1. package/CONTRIBUTING.md +1 -1
  2. package/cli/cli-flags.d.ts +1 -6
  3. package/cli/cli-flags.js +0 -5
  4. package/cli/run.js +3 -10
  5. package/cli/sentry-prompt.js +4 -2
  6. package/cli/test/smokehouse/core-tests.js +0 -2
  7. package/cli/test/smokehouse/frontends/smokehouse-bin.js +24 -14
  8. package/cli/test/smokehouse/lighthouse-runners/bundle.d.ts +1 -2
  9. package/cli/test/smokehouse/lighthouse-runners/bundle.js +12 -21
  10. package/cli/test/smokehouse/lighthouse-runners/cli.d.ts +1 -3
  11. package/cli/test/smokehouse/lighthouse-runners/cli.js +3 -7
  12. package/cli/test/smokehouse/lighthouse-runners/devtools.d.ts +1 -5
  13. package/cli/test/smokehouse/lighthouse-runners/devtools.js +1 -12
  14. package/cli/test/smokehouse/readme.md +0 -2
  15. package/cli/test/smokehouse/report-assert.d.ts +1 -3
  16. package/cli/test/smokehouse/report-assert.js +2 -19
  17. package/cli/test/smokehouse/smokehouse.js +3 -32
  18. package/core/audits/accessibility/aria-allowed-role.d.ts +10 -0
  19. package/core/audits/accessibility/aria-allowed-role.js +46 -0
  20. package/core/audits/accessibility/image-redundant-alt.d.ts +10 -0
  21. package/core/audits/accessibility/image-redundant-alt.js +45 -0
  22. package/core/audits/accessibility/label-content-name-mismatch.d.ts +10 -0
  23. package/core/audits/accessibility/label-content-name-mismatch.js +44 -0
  24. package/core/audits/accessibility/skip-link.d.ts +10 -0
  25. package/core/audits/accessibility/skip-link.js +43 -0
  26. package/core/audits/accessibility/table-duplicate-name.d.ts +10 -0
  27. package/core/audits/accessibility/table-duplicate-name.js +44 -0
  28. package/core/audits/accessibility/target-size.js +1 -1
  29. package/core/audits/byte-efficiency/duplicated-javascript.js +2 -2
  30. package/core/audits/byte-efficiency/render-blocking-resources.js +1 -0
  31. package/core/audits/dobetterweb/uses-http2.d.ts +18 -1
  32. package/core/audits/dobetterweb/uses-http2.js +62 -16
  33. package/core/audits/installable-manifest.d.ts +1 -5
  34. package/core/audits/installable-manifest.js +2 -7
  35. package/core/audits/largest-contentful-paint-element.d.ts +0 -6
  36. package/core/audits/largest-contentful-paint-element.js +13 -15
  37. package/core/audits/metrics/{experimental-interaction-to-next-paint.d.ts → interaction-to-next-paint.d.ts} +3 -3
  38. package/core/audits/metrics/{experimental-interaction-to-next-paint.js → interaction-to-next-paint.js} +3 -3
  39. package/core/audits/uses-rel-preconnect.js +23 -8
  40. package/core/audits/work-during-interaction.js +2 -2
  41. package/core/computed/processed-navigation.d.ts +1 -1
  42. package/core/config/config-helpers.d.ts +3 -3
  43. package/core/config/config-helpers.js +5 -12
  44. package/core/config/config.js +1 -7
  45. package/core/config/constants.d.ts +0 -2
  46. package/core/config/constants.js +2 -18
  47. package/core/config/default-config.js +59 -53
  48. package/core/config/filters.js +1 -1
  49. package/core/config/validation.d.ts +7 -12
  50. package/core/config/validation.js +16 -26
  51. package/core/gather/base-artifacts.d.ts +4 -4
  52. package/core/gather/base-artifacts.js +2 -6
  53. package/core/gather/base-gatherer.d.ts +12 -37
  54. package/core/gather/base-gatherer.js +7 -54
  55. package/core/gather/driver/dom.d.ts +4 -4
  56. package/core/gather/driver/dom.js +2 -2
  57. package/core/gather/driver/environment.d.ts +4 -4
  58. package/core/gather/driver/environment.js +2 -2
  59. package/core/gather/driver/execution-context.d.ts +12 -3
  60. package/core/gather/driver/execution-context.js +34 -3
  61. package/core/gather/driver/navigation.d.ts +2 -2
  62. package/core/gather/driver/navigation.js +2 -5
  63. package/core/gather/driver/network-monitor.d.ts +7 -6
  64. package/core/gather/driver/network-monitor.js +4 -4
  65. package/core/gather/driver/network.d.ts +2 -2
  66. package/core/gather/driver/network.js +1 -1
  67. package/core/gather/driver/prepare.d.ts +10 -10
  68. package/core/gather/driver/prepare.js +10 -10
  69. package/core/gather/driver/service-workers.d.ts +4 -4
  70. package/core/gather/driver/service-workers.js +2 -2
  71. package/core/gather/driver/storage.d.ts +6 -6
  72. package/core/gather/driver/storage.js +3 -3
  73. package/core/gather/driver/target-manager.d.ts +6 -5
  74. package/core/gather/driver/target-manager.js +3 -3
  75. package/core/gather/driver/wait-for-condition.d.ts +14 -14
  76. package/core/gather/driver/wait-for-condition.js +8 -8
  77. package/core/gather/driver.d.ts +9 -6
  78. package/core/gather/driver.js +14 -4
  79. package/core/gather/fetcher.d.ts +3 -3
  80. package/core/gather/fetcher.js +1 -1
  81. package/core/gather/gatherers/accessibility.d.ts +4 -4
  82. package/core/gather/gatherers/accessibility.js +8 -3
  83. package/core/gather/gatherers/anchor-elements.d.ts +4 -4
  84. package/core/gather/gatherers/anchor-elements.js +4 -4
  85. package/core/gather/gatherers/bf-cache-failures.d.ts +8 -14
  86. package/core/gather/gatherers/bf-cache-failures.js +5 -14
  87. package/core/gather/gatherers/cache-contents.d.ts +4 -4
  88. package/core/gather/gatherers/cache-contents.js +3 -3
  89. package/core/gather/gatherers/console-messages.d.ts +6 -6
  90. package/core/gather/gatherers/console-messages.js +4 -4
  91. package/core/gather/gatherers/css-usage.d.ts +14 -14
  92. package/core/gather/gatherers/css-usage.js +9 -9
  93. package/core/gather/gatherers/devtools-log-compat.d.ts +5 -5
  94. package/core/gather/gatherers/devtools-log-compat.js +4 -4
  95. package/core/gather/gatherers/devtools-log.d.ts +6 -6
  96. package/core/gather/gatherers/devtools-log.js +4 -4
  97. package/core/gather/gatherers/dobetterweb/doctype.d.ts +4 -4
  98. package/core/gather/gatherers/dobetterweb/doctype.js +3 -3
  99. package/core/gather/gatherers/dobetterweb/domstats.d.ts +4 -4
  100. package/core/gather/gatherers/dobetterweb/domstats.js +3 -3
  101. package/core/gather/gatherers/dobetterweb/optimized-images.d.ts +10 -22
  102. package/core/gather/gatherers/dobetterweb/optimized-images.js +10 -27
  103. package/core/gather/gatherers/dobetterweb/response-compression.d.ts +6 -12
  104. package/core/gather/gatherers/dobetterweb/response-compression.js +14 -21
  105. package/core/gather/gatherers/dobetterweb/tags-blocking-first-paint.d.ts +8 -14
  106. package/core/gather/gatherers/dobetterweb/tags-blocking-first-paint.js +5 -14
  107. package/core/gather/gatherers/full-page-screenshot.d.ts +10 -10
  108. package/core/gather/gatherers/full-page-screenshot.js +7 -10
  109. package/core/gather/gatherers/global-listeners.d.ts +4 -4
  110. package/core/gather/gatherers/global-listeners.js +3 -3
  111. package/core/gather/gatherers/iframe-elements.d.ts +4 -4
  112. package/core/gather/gatherers/iframe-elements.js +3 -3
  113. package/core/gather/gatherers/image-elements.d.ts +10 -10
  114. package/core/gather/gatherers/image-elements.js +6 -6
  115. package/core/gather/gatherers/inputs.d.ts +4 -4
  116. package/core/gather/gatherers/inputs.js +3 -3
  117. package/core/gather/gatherers/inspector-issues.d.ts +8 -19
  118. package/core/gather/gatherers/inspector-issues.js +9 -26
  119. package/core/gather/gatherers/installability-errors.d.ts +6 -6
  120. package/core/gather/gatherers/installability-errors.js +4 -4
  121. package/core/gather/gatherers/js-usage.d.ts +6 -6
  122. package/core/gather/gatherers/js-usage.js +4 -4
  123. package/core/gather/gatherers/link-elements.d.ts +8 -20
  124. package/core/gather/gatherers/link-elements.js +7 -24
  125. package/core/gather/gatherers/main-document-content.d.ts +4 -16
  126. package/core/gather/gatherers/main-document-content.js +5 -23
  127. package/core/gather/gatherers/meta-elements.d.ts +4 -4
  128. package/core/gather/gatherers/meta-elements.js +3 -3
  129. package/core/gather/gatherers/network-user-agent.d.ts +5 -5
  130. package/core/gather/gatherers/network-user-agent.js +4 -4
  131. package/core/gather/gatherers/script-elements.d.ts +6 -11
  132. package/core/gather/gatherers/script-elements.js +4 -13
  133. package/core/gather/gatherers/scripts.d.ts +7 -6
  134. package/core/gather/gatherers/scripts.js +7 -9
  135. package/core/gather/gatherers/seo/embedded-content.d.ts +4 -4
  136. package/core/gather/gatherers/seo/embedded-content.js +3 -3
  137. package/core/gather/gatherers/seo/font-size.d.ts +6 -6
  138. package/core/gather/gatherers/seo/font-size.js +5 -5
  139. package/core/gather/gatherers/seo/robots-txt.d.ts +4 -4
  140. package/core/gather/gatherers/seo/robots-txt.js +3 -3
  141. package/core/gather/gatherers/seo/tap-targets.d.ts +8 -8
  142. package/core/gather/gatherers/seo/tap-targets.js +5 -5
  143. package/core/gather/gatherers/service-worker.d.ts +4 -10
  144. package/core/gather/gatherers/service-worker.js +3 -15
  145. package/core/gather/gatherers/source-maps.d.ts +11 -23
  146. package/core/gather/gatherers/source-maps.js +22 -53
  147. package/core/gather/gatherers/stacks.d.ts +7 -7
  148. package/core/gather/gatherers/stacks.js +6 -6
  149. package/core/gather/gatherers/trace-compat.d.ts +5 -5
  150. package/core/gather/gatherers/trace-compat.js +4 -4
  151. package/core/gather/gatherers/trace-elements.d.ts +13 -25
  152. package/core/gather/gatherers/trace-elements.js +19 -32
  153. package/core/gather/gatherers/trace.d.ts +8 -8
  154. package/core/gather/gatherers/trace.js +5 -5
  155. package/core/gather/gatherers/viewport-dimensions.d.ts +4 -4
  156. package/core/gather/gatherers/viewport-dimensions.js +3 -3
  157. package/core/gather/gatherers/web-app-manifest.d.ts +8 -8
  158. package/core/gather/gatherers/web-app-manifest.js +5 -5
  159. package/core/gather/navigation-runner.d.ts +9 -9
  160. package/core/gather/navigation-runner.js +14 -8
  161. package/core/gather/runner-helpers.d.ts +3 -3
  162. package/core/gather/runner-helpers.js +12 -4
  163. package/core/gather/session.d.ts +2 -2
  164. package/core/gather/session.js +1 -1
  165. package/core/gather/snapshot-runner.d.ts +2 -2
  166. package/core/gather/snapshot-runner.js +1 -1
  167. package/core/gather/timespan-runner.d.ts +2 -2
  168. package/core/gather/timespan-runner.js +1 -1
  169. package/core/index.cjs +0 -7
  170. package/core/index.d.ts +0 -15
  171. package/core/index.js +2 -40
  172. package/core/lib/asset-saver.js +14 -4
  173. package/core/lib/axe.js +1 -1
  174. package/core/lib/dependency-graph/simulator/network-analyzer.d.ts +28 -12
  175. package/core/lib/dependency-graph/simulator/network-analyzer.js +128 -100
  176. package/core/lib/emulation.d.ts +14 -14
  177. package/core/lib/emulation.js +7 -7
  178. package/core/lib/navigation-error.js +5 -0
  179. package/core/lib/network-recorder.d.ts +2 -1
  180. package/core/lib/network-recorder.js +1 -0
  181. package/core/lib/network-request.js +12 -3
  182. package/core/lib/page-functions.d.ts +10 -2
  183. package/core/lib/page-functions.js +85 -8
  184. package/core/lib/sentry.js +9 -2
  185. package/core/lib/stack-packs.js +4 -0
  186. package/core/runner.d.ts +8 -30
  187. package/core/runner.js +8 -39
  188. package/core/user-flow.d.ts +4 -4
  189. package/core/user-flow.js +2 -2
  190. package/dist/report/bundle.esm.js +2221 -5832
  191. package/dist/report/flow.js +2631 -235
  192. package/dist/report/standalone.js +2586 -234
  193. package/flow-report/src/i18n/i18n.d.ts +2 -2
  194. package/package.json +17 -24
  195. package/readme.md +3 -1
  196. package/report/assets/templates.html +3 -1
  197. package/report/renderer/category-renderer.d.ts +3 -2
  198. package/report/renderer/category-renderer.js +8 -4
  199. package/report/renderer/components.js +11 -5
  200. package/report/renderer/pwa-category-renderer.js +1 -1
  201. package/report/renderer/report-ui-features.js +9 -6
  202. package/report/renderer/report-utils.d.ts +1 -1
  203. package/report/renderer/report-utils.js +2 -2
  204. package/report/renderer/topbar-features.js +3 -0
  205. package/shared/localization/locales/ar-XB.json +185 -44
  206. package/shared/localization/locales/ar.json +185 -44
  207. package/shared/localization/locales/bg.json +185 -44
  208. package/shared/localization/locales/ca.json +190 -49
  209. package/shared/localization/locales/cs.json +185 -44
  210. package/shared/localization/locales/da.json +185 -44
  211. package/shared/localization/locales/de.json +185 -44
  212. package/shared/localization/locales/el.json +185 -44
  213. package/shared/localization/locales/en-GB.json +185 -44
  214. package/shared/localization/locales/en-US.json +99 -45
  215. package/shared/localization/locales/en-XA.json +185 -44
  216. package/shared/localization/locales/en-XL.json +99 -45
  217. package/shared/localization/locales/es-419.json +185 -44
  218. package/shared/localization/locales/es.json +185 -44
  219. package/shared/localization/locales/fi.json +185 -44
  220. package/shared/localization/locales/fil.json +185 -44
  221. package/shared/localization/locales/fr.json +185 -44
  222. package/shared/localization/locales/he.json +186 -45
  223. package/shared/localization/locales/hi.json +185 -44
  224. package/shared/localization/locales/hr.json +185 -44
  225. package/shared/localization/locales/hu.json +185 -44
  226. package/shared/localization/locales/id.json +185 -44
  227. package/shared/localization/locales/it.json +185 -44
  228. package/shared/localization/locales/ja.json +185 -44
  229. package/shared/localization/locales/ko.json +185 -44
  230. package/shared/localization/locales/lt.json +185 -44
  231. package/shared/localization/locales/lv.json +185 -44
  232. package/shared/localization/locales/nl.json +185 -44
  233. package/shared/localization/locales/no.json +185 -44
  234. package/shared/localization/locales/pl.json +185 -44
  235. package/shared/localization/locales/pt-PT.json +185 -44
  236. package/shared/localization/locales/pt.json +190 -49
  237. package/shared/localization/locales/ro.json +185 -44
  238. package/shared/localization/locales/ru.json +185 -44
  239. package/shared/localization/locales/sk.json +185 -44
  240. package/shared/localization/locales/sl.json +185 -44
  241. package/shared/localization/locales/sr-Latn.json +185 -44
  242. package/shared/localization/locales/sr.json +185 -44
  243. package/shared/localization/locales/sv.json +185 -44
  244. package/shared/localization/locales/ta.json +185 -44
  245. package/shared/localization/locales/te.json +185 -44
  246. package/shared/localization/locales/th.json +185 -44
  247. package/shared/localization/locales/tr.json +185 -44
  248. package/shared/localization/locales/uk.json +185 -44
  249. package/shared/localization/locales/vi.json +185 -44
  250. package/shared/localization/locales/zh-HK.json +185 -44
  251. package/shared/localization/locales/zh-TW.json +185 -44
  252. package/shared/localization/locales/zh.json +185 -44
  253. package/third-party/esbuild-plugins-polyfills/LICENSE +3 -0
  254. package/third-party/esbuild-plugins-polyfills/README.md +7 -0
  255. package/third-party/esbuild-plugins-polyfills/esbuild-polyfills.d.ts +9 -0
  256. package/third-party/esbuild-plugins-polyfills/esbuild-polyfills.js +129 -0
  257. package/tsconfig.json +2 -1
  258. package/types/artifacts.d.ts +16 -45
  259. package/types/config.d.ts +10 -52
  260. package/types/externs.d.ts +0 -2
  261. package/types/gatherer.d.ts +24 -47
  262. package/types/internal/rxjs.d.ts +26 -0
  263. package/types/internal/smokehouse.d.ts +1 -3
  264. package/types/lh.d.ts +0 -2
  265. package/types/lhr/settings.d.ts +1 -1
  266. package/core/audits/metrics/first-contentful-paint-3g.d.ts +0 -15
  267. package/core/audits/metrics/first-contentful-paint-3g.js +0 -69
  268. package/core/audits/resource-summary.d.ts +0 -16
  269. package/core/audits/resource-summary.js +0 -104
  270. package/core/audits/service-worker.d.ts +0 -46
  271. package/core/audits/service-worker.js +0 -182
  272. package/core/gather/gatherers/gatherer.d.ts +0 -46
  273. package/core/gather/gatherers/gatherer.js +0 -58
  274. package/core/legacy/config/config.d.ts +0 -107
  275. package/core/legacy/config/config.js +0 -566
  276. package/core/legacy/config/legacy-default-config.d.ts +0 -4
  277. package/core/legacy/config/legacy-default-config.js +0 -87
  278. package/core/legacy/gather/connections/connection.d.ts +0 -77
  279. package/core/legacy/gather/connections/connection.js +0 -196
  280. package/core/legacy/gather/connections/cri.d.ts +0 -27
  281. package/core/legacy/gather/connections/cri.js +0 -162
  282. package/core/legacy/gather/connections/raw.d.ts +0 -20
  283. package/core/legacy/gather/connections/raw.js +0 -57
  284. package/core/legacy/gather/driver.d.ts +0 -216
  285. package/core/legacy/gather/driver.js +0 -480
  286. package/core/legacy/gather/gather-runner.d.ts +0 -166
  287. package/core/legacy/gather/gather-runner.js +0 -590
  288. package/types/internal/lighthouse-logger.d.ts +0 -34
@@ -1,566 +0,0 @@
1
- /**
2
- * @license Copyright 2016 The Lighthouse Authors. All Rights Reserved.
3
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
4
- * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
5
- */
6
-
7
- import path from 'path';
8
-
9
- import log from 'lighthouse-logger';
10
-
11
- import legacyDefaultConfig from './legacy-default-config.js';
12
- import * as constants from '../../config/constants.js';
13
- import * as format from '../../../shared/localization/format.js';
14
- import * as validation from '../../config/validation.js';
15
- import {Runner} from '../../runner.js';
16
- import {
17
- mergePlugins,
18
- mergeConfigFragment,
19
- resolveSettings,
20
- resolveAuditsToDefns,
21
- resolveGathererToDefn,
22
- deepClone,
23
- deepCloneConfigJson,
24
- } from '../../config/config-helpers.js';
25
- import {getModuleDirectory} from '../../../esm-utils.js';
26
-
27
- const defaultConfigPath = './legacy-default-config.js';
28
-
29
- /** @typedef {typeof import('../../gather/gatherers/gatherer.js').Gatherer} GathererConstructor */
30
- /** @typedef {InstanceType<GathererConstructor>} Gatherer */
31
-
32
- /**
33
- * Define with object literal so that tsc will require it to stay updated.
34
- * @type {Record<keyof LH.BaseArtifacts, ''>}
35
- */
36
- const BASE_ARTIFACT_BLANKS = {
37
- fetchTime: '',
38
- LighthouseRunWarnings: '',
39
- HostFormFactor: '',
40
- HostUserAgent: '',
41
- NetworkUserAgent: '',
42
- BenchmarkIndex: '',
43
- BenchmarkIndexes: '',
44
- GatherContext: '',
45
- traces: '',
46
- devtoolsLogs: '',
47
- settings: '',
48
- URL: '',
49
- Timing: '',
50
- PageLoadError: '',
51
- };
52
- const BASE_ARTIFACT_NAMES = Object.keys(BASE_ARTIFACT_BLANKS);
53
-
54
- // These were legacy base artifacts, but we need certain gatherers (e.g. bfcache) to run after them.
55
- // The order is controlled by the config, but still need to force them to run every time.
56
- const alwaysRunArtifactIds = [
57
- 'WebAppManifest',
58
- 'InstallabilityErrors',
59
- 'Stacks',
60
- 'FullPageScreenshot',
61
- ];
62
-
63
- /**
64
- * Certain gatherers are destructive to the page state.
65
- * We should ensure that these gatherers run after any custom gatherers.
66
- * The default priority should be 0.
67
- * TODO: Make this an official part of the config or design a different solution.
68
- * @type {Record<string, number|undefined>}
69
- */
70
- const internalGathererPriorities = {
71
- FullPageScreenshot: 1,
72
- BFCacheFailures: 1,
73
- };
74
-
75
- /**
76
- * @param {LegacyResolvedConfig['passes']} passes
77
- * @param {LegacyResolvedConfig['audits']} audits
78
- */
79
- function assertValidPasses(passes, audits) {
80
- if (!Array.isArray(passes)) {
81
- return;
82
- }
83
-
84
- const requestedGatherers = LegacyResolvedConfig.getGatherersRequestedByAudits(audits);
85
- // Base artifacts are provided by GatherRunner, so start foundGatherers with them.
86
- const foundGatherers = new Set(BASE_ARTIFACT_NAMES);
87
-
88
- // Log if we are running gathers that are not needed by the audits listed in the config
89
- passes.forEach((pass, passIndex) => {
90
- if (passIndex === 0 && pass.loadFailureMode !== 'fatal') {
91
- log.warn(`"${pass.passName}" is the first pass but was marked as non-fatal. ` +
92
- `The first pass will always be treated as loadFailureMode=fatal.`);
93
- pass.loadFailureMode = 'fatal';
94
- }
95
-
96
- pass.gatherers.forEach(gathererDefn => {
97
- const gatherer = gathererDefn.instance;
98
- foundGatherers.add(gatherer.name);
99
- const isGatherRequiredByAudits = requestedGatherers.has(gatherer.name);
100
- const isAlwaysRunArtifact = alwaysRunArtifactIds.includes(gatherer.name);
101
- if (!isGatherRequiredByAudits && !isAlwaysRunArtifact) {
102
- const msg = `${gatherer.name} gatherer requested, however no audit requires it.`;
103
- log.warn('config', msg);
104
- }
105
- });
106
- });
107
-
108
- // All required gatherers must be found in the config. Throw otherwise.
109
- for (const auditDefn of audits || []) {
110
- const auditMeta = auditDefn.implementation.meta;
111
- for (const requiredArtifact of auditMeta.requiredArtifacts) {
112
- if (!foundGatherers.has(requiredArtifact)) {
113
- throw new Error(`${requiredArtifact} gatherer, required by audit ${auditMeta.id}, ` +
114
- 'was not found in config.');
115
- }
116
- }
117
- }
118
-
119
- // Passes must have unique `passName`s. Throw otherwise.
120
- const usedNames = new Set();
121
- passes.forEach(pass => {
122
- const passName = pass.passName;
123
- if (usedNames.has(passName)) {
124
- throw new Error(`Passes must have unique names (repeated passName: ${passName}.`);
125
- }
126
- usedNames.add(passName);
127
- });
128
- }
129
-
130
- /**
131
- * @param {Gatherer} gathererInstance
132
- * @param {string=} gathererName
133
- */
134
- function assertValidGatherer(gathererInstance, gathererName) {
135
- gathererName = gathererName || gathererInstance.name || 'gatherer';
136
-
137
- if (typeof gathererInstance.beforePass !== 'function') {
138
- throw new Error(`${gathererName} has no beforePass() method.`);
139
- }
140
-
141
- if (typeof gathererInstance.pass !== 'function') {
142
- throw new Error(`${gathererName} has no pass() method.`);
143
- }
144
-
145
- if (typeof gathererInstance.afterPass !== 'function') {
146
- throw new Error(`${gathererName} has no afterPass() method.`);
147
- }
148
- }
149
-
150
- /**
151
- * @implements {LH.Config.LegacyResolvedConfig}
152
- */
153
- class LegacyResolvedConfig {
154
- /**
155
- * Resolves the provided config (inherits from extended config, if set), resolves
156
- * all referenced modules, and validates.
157
- * @param {LH.Config=} config If not provided, uses the default config.
158
- * @param {LH.Flags=} flags
159
- * @return {Promise<LegacyResolvedConfig>}
160
- */
161
- static async fromJson(config, flags) {
162
- const status = {msg: 'Create config', id: 'lh:init:config'};
163
- log.time(status, 'verbose');
164
- let configPath = flags?.configPath;
165
-
166
- if (!config) {
167
- config = legacyDefaultConfig;
168
- configPath = path.resolve(getModuleDirectory(import.meta), defaultConfigPath);
169
- }
170
-
171
- if (configPath && !path.isAbsolute(configPath)) {
172
- throw new Error('configPath must be an absolute path.');
173
- }
174
-
175
- // We don't want to mutate the original config object
176
- config = deepCloneConfigJson(config);
177
-
178
- // Extend the default config if specified
179
- if (config.extends) {
180
- if (config.extends !== 'lighthouse:default') {
181
- throw new Error('`lighthouse:default` is the only valid extension method.');
182
- }
183
- config = LegacyResolvedConfig.extendConfigJSON(
184
- deepCloneConfigJson(legacyDefaultConfig), config);
185
- }
186
-
187
- // The directory of the config path, if one was provided.
188
- const configDir = configPath ? path.dirname(configPath) : undefined;
189
-
190
- // Validate and merge in plugins (if any).
191
- config = await mergePlugins(config, configDir, flags);
192
-
193
- const settings = resolveSettings(config.settings || {}, flags);
194
-
195
- // Augment passes with necessary defaults and require gatherers.
196
- const passesWithDefaults = LegacyResolvedConfig.augmentPassesWithDefaults(config.passes);
197
- LegacyResolvedConfig.adjustDefaultPassForThrottling(settings, passesWithDefaults);
198
- const passes = await LegacyResolvedConfig.requireGatherers(passesWithDefaults, configDir);
199
-
200
- const audits = await LegacyResolvedConfig.requireAudits(config.audits, configDir);
201
-
202
- const resolvedConfig = new LegacyResolvedConfig(config, {settings, passes, audits});
203
- log.timeEnd(status);
204
- return resolvedConfig;
205
- }
206
-
207
- /**
208
- * @deprecated `LegacyResolvedConfig.fromJson` should be used instead.
209
- * @constructor
210
- * @param {LH.Config} config
211
- * @param {{settings: LH.Config.Settings, passes: ?LH.Config.Pass[], audits: ?LH.Config.AuditDefn[]}} opts
212
- */
213
- constructor(config, opts) {
214
- /** @type {LH.Config.Settings} */
215
- this.settings = opts.settings;
216
- /** @type {?Array<LH.Config.Pass>} */
217
- this.passes = opts.passes;
218
- /** @type {?Array<LH.Config.AuditDefn>} */
219
- this.audits = opts.audits;
220
- /** @type {?Record<string, LH.Config.Category>} */
221
- this.categories = config.categories || null;
222
- /** @type {?Record<string, LH.Config.Group>} */
223
- this.groups = config.groups || null;
224
-
225
- LegacyResolvedConfig.filterConfigIfNeeded(this);
226
-
227
- assertValidPasses(this.passes, this.audits);
228
- validation.assertValidCategories(this.categories, this.audits, this.groups);
229
- }
230
-
231
- /**
232
- * Provides a cleaned-up, stringified version of this config. Gatherer and
233
- * Audit `implementation` and `instance` do not survive this process.
234
- * @return {string}
235
- */
236
- getPrintString() {
237
- const jsonConfig = deepClone(this);
238
-
239
- if (jsonConfig.passes) {
240
- for (const pass of jsonConfig.passes) {
241
- for (const gathererDefn of pass.gatherers) {
242
- gathererDefn.implementation = undefined;
243
- // @ts-expect-error Breaking the Config.GathererDefn type.
244
- gathererDefn.instance = undefined;
245
- }
246
- }
247
- }
248
-
249
- if (jsonConfig.audits) {
250
- for (const auditDefn of jsonConfig.audits) {
251
- // @ts-expect-error Breaking the Config.AuditDefn type.
252
- auditDefn.implementation = undefined;
253
- if (Object.keys(auditDefn.options).length === 0) {
254
- // @ts-expect-error Breaking the Config.AuditDefn type.
255
- auditDefn.options = undefined;
256
- }
257
- }
258
- }
259
-
260
- // Printed config is more useful with localized strings.
261
- format.replaceIcuMessages(jsonConfig, jsonConfig.settings.locale);
262
-
263
- return JSON.stringify(jsonConfig, null, 2);
264
- }
265
-
266
- /**
267
- * @param {LH.Config} baseJSON The JSON of the configuration to extend
268
- * @param {LH.Config} extendJSON The JSON of the extensions
269
- * @return {LH.Config}
270
- */
271
- static extendConfigJSON(baseJSON, extendJSON) {
272
- if (extendJSON.passes && baseJSON.passes) {
273
- for (const pass of extendJSON.passes) {
274
- // use the default pass name if one is not specified
275
- const passName = pass.passName || constants.defaultPassConfig.passName;
276
- const basePass = baseJSON.passes.find(candidate => candidate.passName === passName);
277
-
278
- if (!basePass) {
279
- baseJSON.passes.push(pass);
280
- } else {
281
- mergeConfigFragment(basePass, pass);
282
- }
283
- }
284
-
285
- delete extendJSON.passes;
286
- }
287
-
288
- return mergeConfigFragment(baseJSON, extendJSON);
289
- }
290
-
291
- /**
292
- * @param {LH.Config['passes']} passes
293
- * @return {?Array<Required<LH.Config.PassJson>>}
294
- */
295
- static augmentPassesWithDefaults(passes) {
296
- if (!passes) {
297
- return null;
298
- }
299
-
300
- const {defaultPassConfig} = constants;
301
- return passes.map(pass => mergeConfigFragment(deepClone(defaultPassConfig), pass));
302
- }
303
-
304
- /**
305
- * Observed throttling methods (devtools/provided) require at least 5s of quiet for the metrics to
306
- * be computed. This method adjusts the quiet thresholds to the required minimums if necessary.
307
- * @param {LH.Config.Settings} settings
308
- * @param {?Array<Required<LH.Config.PassJson>>} passes
309
- */
310
- static adjustDefaultPassForThrottling(settings, passes) {
311
- if (!passes ||
312
- (settings.throttlingMethod !== 'devtools' && settings.throttlingMethod !== 'provided')) {
313
- return;
314
- }
315
-
316
- const defaultPass = passes.find(pass => pass.passName === 'defaultPass');
317
- if (!defaultPass) return;
318
- const overrides = constants.nonSimulatedPassConfigOverrides;
319
- defaultPass.pauseAfterFcpMs =
320
- Math.max(overrides.pauseAfterFcpMs, defaultPass.pauseAfterFcpMs);
321
- defaultPass.pauseAfterLoadMs =
322
- Math.max(overrides.pauseAfterLoadMs, defaultPass.pauseAfterLoadMs);
323
- defaultPass.cpuQuietThresholdMs =
324
- Math.max(overrides.cpuQuietThresholdMs, defaultPass.cpuQuietThresholdMs);
325
- defaultPass.networkQuietThresholdMs =
326
- Math.max(overrides.networkQuietThresholdMs, defaultPass.networkQuietThresholdMs);
327
- }
328
-
329
- /**
330
- * Filter out any unrequested items from the config, based on requested categories or audits.
331
- * @param {LegacyResolvedConfig} config
332
- */
333
- static filterConfigIfNeeded(config) {
334
- const settings = config.settings;
335
- // eslint-disable-next-line max-len
336
- if (!settings.onlyCategories && !settings.onlyAudits && !settings.skipAudits && !settings.disableFullPageScreenshot) {
337
- return;
338
- }
339
-
340
- // 1. Filter to just the chosen categories/audits
341
- const {categories, requestedAuditNames} =
342
- LegacyResolvedConfig.filterCategoriesAndAudits(config.categories, settings);
343
-
344
- // 2. Resolve which audits will need to run
345
- const audits = config.audits && config.audits.filter(auditDefn =>
346
- requestedAuditNames.has(auditDefn.implementation.meta.id));
347
-
348
- // 3. Resolve which gatherers will need to run
349
- const requestedGathererIds = LegacyResolvedConfig.getGatherersRequestedByAudits(audits);
350
- for (const gathererId of alwaysRunArtifactIds) {
351
- requestedGathererIds.add(gathererId);
352
- }
353
-
354
- // Remove FullPageScreenshot if we explicitly exclude it.
355
- if (settings.disableFullPageScreenshot) {
356
- requestedGathererIds.delete('FullPageScreenshot');
357
- }
358
-
359
- // 4. Filter to only the neccessary passes
360
- const passes =
361
- LegacyResolvedConfig.generatePassesNeededByGatherers(config.passes, requestedGathererIds);
362
-
363
- config.categories = categories;
364
- config.audits = audits;
365
- config.passes = passes;
366
- }
367
-
368
- /**
369
- * Filter out any unrequested categories or audits from the categories object.
370
- * @param {LegacyResolvedConfig['categories']} oldCategories
371
- * @param {LH.Config.Settings} settings
372
- * @return {{categories: LegacyResolvedConfig['categories'], requestedAuditNames: Set<string>}}
373
- */
374
- static filterCategoriesAndAudits(oldCategories, settings) {
375
- if (!oldCategories) {
376
- return {categories: null, requestedAuditNames: new Set()};
377
- }
378
-
379
- if (settings.onlyAudits && settings.skipAudits) {
380
- throw new Error('Cannot set both skipAudits and onlyAudits');
381
- }
382
-
383
- /** @type {NonNullable<LegacyResolvedConfig['categories']>} */
384
- const categories = {};
385
- const filterByIncludedCategory = !!settings.onlyCategories;
386
- const filterByIncludedAudit = !!settings.onlyAudits;
387
- const categoryIds = settings.onlyCategories || [];
388
- const auditIds = settings.onlyAudits || [];
389
- const skipAuditIds = settings.skipAudits || [];
390
-
391
- // warn if the category is not found
392
- categoryIds.forEach(categoryId => {
393
- if (!oldCategories[categoryId]) {
394
- log.warn('config', `unrecognized category in 'onlyCategories': ${categoryId}`);
395
- }
396
- });
397
-
398
- // warn if the audit is not found in a category or there are overlaps
399
- const auditsToValidate = new Set(auditIds.concat(skipAuditIds));
400
- for (const auditId of auditsToValidate) {
401
- const foundCategory = Object.keys(oldCategories).find(categoryId => {
402
- const auditRefs = oldCategories[categoryId].auditRefs;
403
- return !!auditRefs.find(candidate => candidate.id === auditId);
404
- });
405
-
406
- if (!foundCategory) {
407
- const parentKeyName = skipAuditIds.includes(auditId) ? 'skipAudits' : 'onlyAudits';
408
- log.warn('config', `unrecognized audit in '${parentKeyName}': ${auditId}`);
409
- } else if (auditIds.includes(auditId) && categoryIds.includes(foundCategory)) {
410
- log.warn('config', `${auditId} in 'onlyAudits' is already included by ` +
411
- `${foundCategory} in 'onlyCategories'`);
412
- }
413
- }
414
-
415
- const includedAudits = new Set(auditIds);
416
- skipAuditIds.forEach(id => includedAudits.delete(id));
417
-
418
- Object.keys(oldCategories).forEach(categoryId => {
419
- const category = deepClone(oldCategories[categoryId]);
420
-
421
- if (filterByIncludedCategory && filterByIncludedAudit) {
422
- // If we're filtering by category and audit, include the union of the two
423
- if (!categoryIds.includes(categoryId)) {
424
- category.auditRefs = category.auditRefs.filter(audit => auditIds.includes(audit.id));
425
- }
426
- } else if (filterByIncludedCategory) {
427
- // If we're filtering by just category, and the category is not included, skip it
428
- if (!categoryIds.includes(categoryId)) {
429
- return;
430
- }
431
- } else if (filterByIncludedAudit) {
432
- category.auditRefs = category.auditRefs.filter(audit => auditIds.includes(audit.id));
433
- }
434
-
435
- // always filter based on skipAuditIds
436
- category.auditRefs = category.auditRefs.filter(audit => !skipAuditIds.includes(audit.id));
437
-
438
- if (category.auditRefs.length) {
439
- categories[categoryId] = category;
440
- category.auditRefs.forEach(audit => includedAudits.add(audit.id));
441
- }
442
- });
443
-
444
- return {categories, requestedAuditNames: includedAudits};
445
- }
446
-
447
- /**
448
- * From some requested audits, return names of all required and optional artifacts
449
- * @param {LegacyResolvedConfig['audits']} audits
450
- * @return {Set<string>}
451
- */
452
- static getGatherersRequestedByAudits(audits) {
453
- // It's possible we weren't given any audits (but existing audit results), in which case
454
- // there is no need to do any work here.
455
- if (!audits) {
456
- return new Set();
457
- }
458
-
459
- const gatherers = new Set();
460
- for (const auditDefn of audits) {
461
- const {requiredArtifacts, __internalOptionalArtifacts} = auditDefn.implementation.meta;
462
- requiredArtifacts.forEach(artifact => gatherers.add(artifact));
463
- if (__internalOptionalArtifacts) {
464
- __internalOptionalArtifacts.forEach(artifact => gatherers.add(artifact));
465
- }
466
- }
467
- return gatherers;
468
- }
469
-
470
- /**
471
- * Filters to only requested passes and gatherers, returning a new passes array.
472
- * @param {LegacyResolvedConfig['passes']} passes
473
- * @param {Set<string>} requestedGatherers
474
- * @return {LegacyResolvedConfig['passes']}
475
- */
476
- static generatePassesNeededByGatherers(passes, requestedGatherers) {
477
- if (!passes) {
478
- return null;
479
- }
480
-
481
- const auditsNeedTrace = requestedGatherers.has('traces');
482
- const filteredPasses = passes.map(pass => {
483
- // remove any unncessary gatherers from within the passes
484
- pass.gatherers = pass.gatherers.filter(gathererDefn => {
485
- const gatherer = gathererDefn.instance;
486
- return requestedGatherers.has(gatherer.name);
487
- });
488
-
489
- // disable the trace if no audit requires a trace
490
- if (pass.recordTrace && !auditsNeedTrace) {
491
- const passName = pass.passName || 'unknown pass';
492
- log.warn('config', `Trace not requested by an audit, dropping trace in ${passName}`);
493
- pass.recordTrace = false;
494
- }
495
-
496
- return pass;
497
- }).filter(pass => {
498
- // remove any passes lacking concrete gatherers, unless they are dependent on the trace
499
- if (pass.recordTrace) return true;
500
- // Always keep defaultPass
501
- if (pass.passName === 'defaultPass') return true;
502
- return pass.gatherers.length > 0;
503
- });
504
- return filteredPasses;
505
- }
506
-
507
- /**
508
- * Take an array of audits and audit paths and require any paths (possibly
509
- * relative to the optional `configDir`) using `resolveModulePath`,
510
- * leaving only an array of AuditDefns.
511
- * @param {LH.Config['audits']} audits
512
- * @param {string=} configDir
513
- * @return {Promise<LegacyResolvedConfig['audits']>}
514
- */
515
- static async requireAudits(audits, configDir) {
516
- const status = {msg: 'Requiring audits', id: 'lh:config:requireAudits'};
517
- log.time(status, 'verbose');
518
- const auditDefns = await resolveAuditsToDefns(audits, configDir);
519
- log.timeEnd(status);
520
- return auditDefns;
521
- }
522
-
523
- /**
524
- * Takes an array of passes with every property now initialized except the
525
- * gatherers and requires them, (relative to the optional `configDir` if
526
- * provided) using `resolveModulePath`, returning an array of full Passes.
527
- * @param {?Array<Required<LH.Config.PassJson>>} passes
528
- * @param {string=} configDir
529
- * @return {Promise<LegacyResolvedConfig['passes']>}
530
- */
531
- static async requireGatherers(passes, configDir) {
532
- if (!passes) {
533
- return null;
534
- }
535
- const status = {msg: 'Requiring gatherers', id: 'lh:config:requireGatherers'};
536
- log.time(status, 'verbose');
537
-
538
- const coreList = Runner.getGathererList();
539
- const fullPassesPromises = passes.map(async (pass) => {
540
- const gathererDefns = await Promise.all(
541
- pass.gatherers
542
- .map(gatherer => resolveGathererToDefn(gatherer, coreList, configDir))
543
- );
544
-
545
- // De-dupe gatherers by artifact name because artifact IDs must be unique at runtime.
546
- const uniqueDefns = Array.from(
547
- new Map(gathererDefns.map(defn => [defn.instance.name, defn])).values()
548
- );
549
- uniqueDefns.forEach(gatherer => assertValidGatherer(gatherer.instance, gatherer.path));
550
-
551
- uniqueDefns.sort((a, b) => {
552
- const aPriority = internalGathererPriorities[a.instance.name] || 0;
553
- const bPriority = internalGathererPriorities[b.instance.name] || 0;
554
- return aPriority - bPriority;
555
- });
556
-
557
- return Object.assign(pass, {gatherers: uniqueDefns});
558
- });
559
- const fullPasses = await Promise.all(fullPassesPromises);
560
-
561
- log.timeEnd(status);
562
- return fullPasses;
563
- }
564
- }
565
-
566
- export {LegacyResolvedConfig};
@@ -1,4 +0,0 @@
1
- export default legacyDefaultConfig;
2
- /** @type {LH.Config} */
3
- declare const legacyDefaultConfig: LH.Config;
4
- //# sourceMappingURL=legacy-default-config.d.ts.map
@@ -1,87 +0,0 @@
1
- /**
2
- * @license Copyright 2018 The Lighthouse Authors. All Rights Reserved.
3
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
4
- * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
5
- */
6
-
7
- /**
8
- * @fileoverview Construct the legacy default config from the standard default config.
9
- */
10
-
11
- import defaultConfig from '../../config/default-config.js';
12
-
13
- /** @type {LH.Config} */
14
- const legacyDefaultConfig = JSON.parse(JSON.stringify(defaultConfig));
15
- if (!legacyDefaultConfig.categories) {
16
- throw new Error('Default config should always have categories');
17
- }
18
-
19
- // These properties are ignored in Legacy navigations.
20
- delete legacyDefaultConfig.artifacts;
21
-
22
- // These audits don't work in Legacy navigation mode so we remove them.
23
- const unsupportedAuditIds = [
24
- 'experimental-interaction-to-next-paint',
25
- 'uses-responsive-images-snapshot',
26
- 'work-during-interaction',
27
- ];
28
-
29
- legacyDefaultConfig.audits = legacyDefaultConfig.audits?.filter(audit =>
30
- !unsupportedAuditIds.find(auditId => audit.toString().endsWith(auditId)));
31
-
32
- legacyDefaultConfig.categories['performance'].auditRefs =
33
- legacyDefaultConfig.categories['performance'].auditRefs.filter(auditRef =>
34
- !unsupportedAuditIds.includes(auditRef.id));
35
-
36
- legacyDefaultConfig.passes = [{
37
- passName: 'defaultPass',
38
- recordTrace: true,
39
- useThrottling: true,
40
- pauseAfterFcpMs: 1000,
41
- pauseAfterLoadMs: 1000,
42
- networkQuietThresholdMs: 1000,
43
- cpuQuietThresholdMs: 1000,
44
- gatherers: [
45
- 'css-usage',
46
- 'js-usage',
47
- 'viewport-dimensions',
48
- 'console-messages',
49
- 'anchor-elements',
50
- 'image-elements',
51
- 'link-elements',
52
- 'meta-elements',
53
- 'script-elements',
54
- 'scripts',
55
- 'iframe-elements',
56
- 'inputs',
57
- 'main-document-content',
58
- 'global-listeners',
59
- 'dobetterweb/doctype',
60
- 'dobetterweb/domstats',
61
- 'dobetterweb/optimized-images',
62
- 'dobetterweb/response-compression',
63
- 'dobetterweb/tags-blocking-first-paint',
64
- 'seo/font-size',
65
- 'seo/embedded-content',
66
- 'seo/robots-txt',
67
- 'seo/tap-targets',
68
- 'accessibility',
69
- 'trace-elements',
70
- 'inspector-issues',
71
- 'source-maps',
72
- 'web-app-manifest',
73
- 'installability-errors',
74
- 'stacks',
75
- 'full-page-screenshot',
76
- 'bf-cache-failures',
77
- ],
78
- },
79
- {
80
- passName: 'offlinePass',
81
- loadFailureMode: 'ignore',
82
- gatherers: [
83
- 'service-worker',
84
- ],
85
- }];
86
-
87
- export default legacyDefaultConfig;