lighthouse 11.7.0-dev.20240408 → 11.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/CONTRIBUTING.md +2 -2
  2. package/cli/test/smokehouse/core-tests.js +2 -0
  3. package/core/audits/accessibility/duplicate-id-active.d.ts +10 -0
  4. package/core/audits/accessibility/duplicate-id-active.js +42 -0
  5. package/core/audits/accessibility/target-size.js +1 -0
  6. package/core/audits/byte-efficiency/byte-efficiency-audit.d.ts +16 -0
  7. package/core/audits/byte-efficiency/byte-efficiency-audit.js +38 -1
  8. package/core/audits/byte-efficiency/offscreen-images.d.ts +11 -0
  9. package/core/audits/byte-efficiency/offscreen-images.js +15 -0
  10. package/core/audits/dobetterweb/uses-http2.d.ts +13 -0
  11. package/core/audits/dobetterweb/uses-http2.js +34 -2
  12. package/core/audits/layout-shift-elements.d.ts +16 -0
  13. package/core/audits/layout-shift-elements.js +101 -0
  14. package/core/audits/no-unload-listeners.d.ts +16 -0
  15. package/core/audits/no-unload-listeners.js +86 -0
  16. package/core/audits/preload-fonts.d.ts +5 -1
  17. package/core/audits/preload-fonts.js +10 -1
  18. package/core/audits/script-elements-test-audit.d.ts +14 -0
  19. package/core/audits/script-elements-test-audit.js +29 -0
  20. package/core/audits/seo/is-crawlable.d.ts +1 -2
  21. package/core/audits/seo/plugins.d.ts +15 -0
  22. package/core/audits/seo/plugins.js +150 -0
  23. package/core/audits/seo/tap-targets.d.ts +50 -0
  24. package/core/audits/seo/tap-targets.js +352 -0
  25. package/core/audits/uses-rel-preload.d.ts +5 -1
  26. package/core/audits/uses-rel-preload.js +11 -1
  27. package/core/audits/work-during-interaction.d.ts +2 -2
  28. package/core/audits/work-during-interaction.js +2 -2
  29. package/core/computed/js-bundles.d.ts +1 -1
  30. package/core/computed/metrics/lantern-first-contentful-paint.d.ts +82 -13
  31. package/core/computed/metrics/lantern-first-contentful-paint.js +178 -15
  32. package/core/computed/metrics/lantern-first-meaningful-paint.d.ts +12 -13
  33. package/core/computed/metrics/lantern-first-meaningful-paint.js +49 -10
  34. package/core/computed/metrics/lantern-interactive.d.ts +21 -13
  35. package/core/computed/metrics/lantern-interactive.js +84 -11
  36. package/core/computed/metrics/lantern-largest-contentful-paint.d.ts +25 -13
  37. package/core/computed/metrics/lantern-largest-contentful-paint.js +80 -12
  38. package/core/computed/metrics/lantern-max-potential-fid.d.ts +24 -13
  39. package/core/computed/metrics/lantern-max-potential-fid.js +64 -11
  40. package/core/computed/metrics/lantern-metric.d.ts +18 -9
  41. package/core/computed/metrics/lantern-metric.js +31 -13
  42. package/core/computed/metrics/lantern-speed-index.d.ts +32 -13
  43. package/core/computed/metrics/lantern-speed-index.js +116 -12
  44. package/core/computed/metrics/lantern-total-blocking-time.d.ts +25 -13
  45. package/core/computed/metrics/lantern-total-blocking-time.js +94 -10
  46. package/core/computed/metrics/metric.js +3 -1
  47. package/core/computed/module-duplication.d.ts +1 -1
  48. package/core/computed/page-dependency-graph.js +1 -2
  49. package/core/config/default-config.js +74 -46
  50. package/core/config/experimental-config.js +0 -11
  51. package/core/config/metrics-to-audits.d.ts +19 -0
  52. package/core/config/metrics-to-audits.js +62 -0
  53. package/core/gather/gatherers/accessibility.js +3 -1
  54. package/core/gather/gatherers/global-listeners.d.ts +27 -0
  55. package/core/gather/gatherers/global-listeners.js +108 -0
  56. package/core/gather/gatherers/script-elements.d.ts +21 -0
  57. package/core/gather/gatherers/script-elements.js +100 -0
  58. package/core/gather/gatherers/seo/embedded-content.d.ts +10 -0
  59. package/core/gather/gatherers/seo/embedded-content.js +63 -0
  60. package/core/gather/gatherers/seo/tap-targets.d.ts +21 -0
  61. package/core/gather/gatherers/seo/tap-targets.js +389 -0
  62. package/core/gather/gatherers/trace-elements.d.ts +10 -0
  63. package/core/gather/gatherers/trace-elements.js +19 -0
  64. package/core/lib/lantern/page-dependency-graph.d.ts +4 -4
  65. package/core/lib/lantern/page-dependency-graph.js +5 -5
  66. package/core/lib/lighthouse-compatibility.js +10 -53
  67. package/dist/report/bundle.esm.js +1 -1
  68. package/dist/report/flow.js +14 -14
  69. package/dist/report/standalone.js +1 -1
  70. package/flow-report/src/summary/category.tsx +12 -10
  71. package/package.json +1 -1
  72. package/report/renderer/performance-category-renderer.d.ts +7 -0
  73. package/report/renderer/performance-category-renderer.js +11 -1
  74. package/report/renderer/report-utils.js +10 -13
  75. package/shared/localization/locales/ar-XB.json +64 -1
  76. package/shared/localization/locales/ar.json +64 -1
  77. package/shared/localization/locales/bg.json +64 -1
  78. package/shared/localization/locales/ca.json +64 -1
  79. package/shared/localization/locales/cs.json +64 -1
  80. package/shared/localization/locales/da.json +64 -1
  81. package/shared/localization/locales/de.json +64 -1
  82. package/shared/localization/locales/el.json +64 -1
  83. package/shared/localization/locales/en-GB.json +64 -1
  84. package/shared/localization/locales/en-US.json +65 -2
  85. package/shared/localization/locales/en-XA.json +64 -1
  86. package/shared/localization/locales/en-XL.json +65 -2
  87. package/shared/localization/locales/es-419.json +64 -1
  88. package/shared/localization/locales/es.json +64 -1
  89. package/shared/localization/locales/fi.json +64 -1
  90. package/shared/localization/locales/fil.json +64 -1
  91. package/shared/localization/locales/fr.json +64 -1
  92. package/shared/localization/locales/he.json +64 -1
  93. package/shared/localization/locales/hi.json +64 -1
  94. package/shared/localization/locales/hr.json +64 -1
  95. package/shared/localization/locales/hu.json +64 -1
  96. package/shared/localization/locales/id.json +64 -1
  97. package/shared/localization/locales/it.json +64 -1
  98. package/shared/localization/locales/ja.json +64 -1
  99. package/shared/localization/locales/ko.json +64 -1
  100. package/shared/localization/locales/lt.json +64 -1
  101. package/shared/localization/locales/lv.json +64 -1
  102. package/shared/localization/locales/nl.json +64 -1
  103. package/shared/localization/locales/no.json +64 -1
  104. package/shared/localization/locales/pl.json +64 -1
  105. package/shared/localization/locales/pt-PT.json +64 -1
  106. package/shared/localization/locales/pt.json +64 -1
  107. package/shared/localization/locales/ro.json +64 -1
  108. package/shared/localization/locales/ru.json +64 -1
  109. package/shared/localization/locales/sk.json +64 -1
  110. package/shared/localization/locales/sl.json +64 -1
  111. package/shared/localization/locales/sr-Latn.json +64 -1
  112. package/shared/localization/locales/sr.json +64 -1
  113. package/shared/localization/locales/sv.json +64 -1
  114. package/shared/localization/locales/ta.json +64 -1
  115. package/shared/localization/locales/te.json +64 -1
  116. package/shared/localization/locales/th.json +64 -1
  117. package/shared/localization/locales/tr.json +64 -1
  118. package/shared/localization/locales/uk.json +64 -1
  119. package/shared/localization/locales/vi.json +64 -1
  120. package/shared/localization/locales/zh-HK.json +64 -1
  121. package/shared/localization/locales/zh-TW.json +64 -1
  122. package/shared/localization/locales/zh.json +64 -1
  123. package/tsconfig.json +0 -1
  124. package/types/artifacts.d.ts +17 -3
  125. package/types/config.d.ts +1 -0
  126. package/types/lhr/audit-details.d.ts +4 -9
  127. package/types/lhr/lhr.d.ts +2 -0
  128. package/core/lib/lantern/metrics/first-contentful-paint.d.ts +0 -79
  129. package/core/lib/lantern/metrics/first-contentful-paint.js +0 -200
  130. package/core/lib/lantern/metrics/first-meaningful-paint.d.ts +0 -6
  131. package/core/lib/lantern/metrics/first-meaningful-paint.js +0 -66
  132. package/core/lib/lantern/metrics/interactive.d.ts +0 -26
  133. package/core/lib/lantern/metrics/interactive.js +0 -112
  134. package/core/lib/lantern/metrics/largest-contentful-paint.d.ts +0 -19
  135. package/core/lib/lantern/metrics/largest-contentful-paint.js +0 -108
  136. package/core/lib/lantern/metrics/max-potential-fid.d.ts +0 -30
  137. package/core/lib/lantern/metrics/max-potential-fid.js +0 -92
  138. package/core/lib/lantern/metrics/speed-index.d.ts +0 -38
  139. package/core/lib/lantern/metrics/speed-index.js +0 -145
  140. package/core/lib/lantern/metrics/total-blocking-time.d.ts +0 -31
  141. package/core/lib/lantern/metrics/total-blocking-time.js +0 -128
@@ -0,0 +1,108 @@
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;
@@ -0,0 +1,21 @@
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
@@ -0,0 +1,100 @@
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;
@@ -0,0 +1,10 @@
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
@@ -0,0 +1,63 @@
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;
@@ -0,0 +1,21 @@
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