lighthouse 12.3.0 → 12.4.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 (142) hide show
  1. package/cli/test/smokehouse/core-tests.js +4 -0
  2. package/core/audits/audit.d.ts +5 -0
  3. package/core/audits/audit.js +12 -0
  4. package/core/audits/bootup-time.js +0 -2
  5. package/core/audits/byte-efficiency/duplicated-javascript.d.ts +4 -5
  6. package/core/audits/byte-efficiency/duplicated-javascript.js +9 -5
  7. package/core/audits/byte-efficiency/legacy-javascript.d.ts +2 -2
  8. package/core/audits/byte-efficiency/legacy-javascript.js +17 -5
  9. package/core/audits/byte-efficiency/polyfill-graph-data.json +48 -49
  10. package/core/audits/byte-efficiency/total-byte-weight.js +0 -2
  11. package/core/audits/clickjacking-mitigation.d.ts +42 -0
  12. package/core/audits/clickjacking-mitigation.js +139 -0
  13. package/core/audits/dobetterweb/dom-size.js +0 -2
  14. package/core/audits/insights/README.md +3 -0
  15. package/core/audits/insights/cls-culprits-insight.d.ts +25 -0
  16. package/core/audits/insights/cls-culprits-insight.js +137 -0
  17. package/core/audits/insights/document-latency-insight.d.ts +11 -0
  18. package/core/audits/insights/document-latency-insight.js +48 -0
  19. package/core/audits/insights/dom-size-insight.d.ts +11 -0
  20. package/core/audits/insights/dom-size-insight.js +85 -0
  21. package/core/audits/insights/font-display-insight.d.ts +11 -0
  22. package/core/audits/insights/font-display-insight.js +53 -0
  23. package/core/audits/insights/forced-reflow-insight.d.ts +11 -0
  24. package/core/audits/insights/forced-reflow-insight.js +52 -0
  25. package/core/audits/insights/image-delivery-insight.d.ts +11 -0
  26. package/core/audits/insights/image-delivery-insight.js +83 -0
  27. package/core/audits/insights/insight-audit.d.ts +23 -0
  28. package/core/audits/insights/insight-audit.js +133 -0
  29. package/core/audits/insights/interaction-to-next-paint-insight.d.ts +11 -0
  30. package/core/audits/insights/interaction-to-next-paint-insight.js +71 -0
  31. package/core/audits/insights/lcp-discovery-insight.d.ts +11 -0
  32. package/core/audits/insights/lcp-discovery-insight.js +48 -0
  33. package/core/audits/insights/lcp-phases-insight.d.ts +16 -0
  34. package/core/audits/insights/lcp-phases-insight.js +87 -0
  35. package/core/audits/insights/long-critical-network-tree-insight.d.ts +11 -0
  36. package/core/audits/insights/long-critical-network-tree-insight.js +53 -0
  37. package/core/audits/insights/render-blocking-insight.d.ts +11 -0
  38. package/core/audits/insights/render-blocking-insight.js +57 -0
  39. package/core/audits/insights/slow-css-selector-insight.d.ts +11 -0
  40. package/core/audits/insights/slow-css-selector-insight.js +52 -0
  41. package/core/audits/insights/third-parties-insight.d.ts +28 -0
  42. package/core/audits/insights/third-parties-insight.js +90 -0
  43. package/core/audits/insights/viewport-insight.d.ts +11 -0
  44. package/core/audits/insights/viewport-insight.js +54 -0
  45. package/core/audits/layout-shifts.d.ts +0 -1
  46. package/core/audits/layout-shifts.js +18 -21
  47. package/core/audits/mainthread-work-breakdown.js +0 -2
  48. package/core/audits/seo/is-crawlable.d.ts +1 -0
  49. package/core/audits/server-response-time.js +0 -1
  50. package/core/computed/metrics/lantern-metric.js +5 -1
  51. package/core/computed/trace-engine-result.js +71 -17
  52. package/core/config/default-config.js +37 -1
  53. package/core/gather/gatherers/inspector-issues.js +3 -0
  54. package/core/gather/gatherers/trace-elements.d.ts +10 -2
  55. package/core/gather/gatherers/trace-elements.js +89 -12
  56. package/core/lib/bf-cache-strings.d.ts +7 -4
  57. package/core/lib/bf-cache-strings.js +174 -140
  58. package/core/lib/cdt/generated/ParsedURL.d.ts +1 -0
  59. package/core/lib/cdt/generated/ParsedURL.js +16 -4
  60. package/core/lib/cdt/generated/SourceMap.d.ts +32 -5
  61. package/core/lib/cdt/generated/SourceMap.js +192 -100
  62. package/core/lib/deprecations-strings.d.ts +78 -98
  63. package/core/lib/deprecations-strings.js +23 -41
  64. package/core/lib/i18n/i18n.d.ts +1 -0
  65. package/core/lib/i18n/i18n.js +2 -0
  66. package/core/lib/trace-engine.d.ts +1 -0
  67. package/core/lib/trace-engine.js +2 -0
  68. package/core/runner.js +2 -0
  69. package/dist/report/bundle.esm.js +196 -9
  70. package/dist/report/flow.js +197 -10
  71. package/dist/report/standalone.js +197 -10
  72. package/flow-report/src/i18n/i18n.d.ts +2 -0
  73. package/package.json +15 -13
  74. package/readme.md +3 -0
  75. package/report/assets/styles.css +179 -5
  76. package/report/assets/templates.html +14 -0
  77. package/report/renderer/components.js +9 -3
  78. package/report/renderer/details-renderer.d.ts +5 -0
  79. package/report/renderer/details-renderer.js +24 -0
  80. package/report/renderer/dom.d.ts +12 -1
  81. package/report/renderer/dom.js +26 -1
  82. package/report/renderer/i18n-formatter.d.ts +1 -1
  83. package/report/renderer/performance-category-renderer.d.ts +10 -0
  84. package/report/renderer/performance-category-renderer.js +81 -20
  85. package/report/renderer/report-utils.d.ts +1 -0
  86. package/report/renderer/report-utils.js +2 -0
  87. package/report/renderer/topbar-features.js +7 -0
  88. package/shared/localization/locales/ar-XB.json +74 -26
  89. package/shared/localization/locales/ar.json +76 -28
  90. package/shared/localization/locales/bg.json +74 -26
  91. package/shared/localization/locales/ca.json +74 -26
  92. package/shared/localization/locales/cs.json +74 -26
  93. package/shared/localization/locales/da.json +74 -26
  94. package/shared/localization/locales/de.json +75 -27
  95. package/shared/localization/locales/el.json +74 -26
  96. package/shared/localization/locales/en-GB.json +74 -26
  97. package/shared/localization/locales/en-US.json +288 -30
  98. package/shared/localization/locales/en-XA.json +48 -24
  99. package/shared/localization/locales/en-XL.json +288 -30
  100. package/shared/localization/locales/es-419.json +74 -26
  101. package/shared/localization/locales/es.json +74 -26
  102. package/shared/localization/locales/fi.json +74 -26
  103. package/shared/localization/locales/fil.json +75 -27
  104. package/shared/localization/locales/fr.json +74 -26
  105. package/shared/localization/locales/he.json +82 -34
  106. package/shared/localization/locales/hi.json +74 -26
  107. package/shared/localization/locales/hr.json +75 -27
  108. package/shared/localization/locales/hu.json +74 -26
  109. package/shared/localization/locales/id.json +74 -26
  110. package/shared/localization/locales/it.json +85 -37
  111. package/shared/localization/locales/ja.json +75 -27
  112. package/shared/localization/locales/ko.json +75 -27
  113. package/shared/localization/locales/lt.json +75 -27
  114. package/shared/localization/locales/lv.json +74 -26
  115. package/shared/localization/locales/nl.json +74 -26
  116. package/shared/localization/locales/no.json +75 -27
  117. package/shared/localization/locales/pl.json +74 -26
  118. package/shared/localization/locales/pt-PT.json +74 -26
  119. package/shared/localization/locales/pt.json +74 -26
  120. package/shared/localization/locales/ro.json +74 -26
  121. package/shared/localization/locales/ru.json +74 -26
  122. package/shared/localization/locales/sk.json +74 -26
  123. package/shared/localization/locales/sl.json +74 -26
  124. package/shared/localization/locales/sr-Latn.json +74 -26
  125. package/shared/localization/locales/sr.json +74 -26
  126. package/shared/localization/locales/sv.json +74 -26
  127. package/shared/localization/locales/ta.json +74 -26
  128. package/shared/localization/locales/te.json +74 -26
  129. package/shared/localization/locales/th.json +76 -28
  130. package/shared/localization/locales/tr.json +74 -26
  131. package/shared/localization/locales/uk.json +74 -26
  132. package/shared/localization/locales/vi.json +74 -26
  133. package/shared/localization/locales/zh-HK.json +75 -27
  134. package/shared/localization/locales/zh-TW.json +74 -26
  135. package/shared/localization/locales/zh.json +74 -26
  136. package/third-party/chromium-synchronization/inspector-issueAdded-types-test.js +3 -0
  137. package/types/artifacts.d.ts +5 -3
  138. package/types/audit.d.ts +2 -0
  139. package/types/lhr/audit-details.d.ts +13 -1
  140. package/types/lhr/audit-result.d.ts +2 -0
  141. package/core/gather/gatherers/root-causes.d.ts +0 -19
  142. package/core/gather/gatherers/root-causes.js +0 -144
@@ -0,0 +1,11 @@
1
+ export default InteractionToNextPaintInsight;
2
+ declare class InteractionToNextPaintInsight extends Audit {
3
+ /**
4
+ * @param {LH.Artifacts} artifacts
5
+ * @param {LH.Audit.Context} context
6
+ * @return {Promise<LH.Audit.Product>}
7
+ */
8
+ static audit(artifacts: LH.Artifacts, context: LH.Audit.Context): Promise<LH.Audit.Product>;
9
+ }
10
+ import { Audit } from '../audit.js';
11
+ //# sourceMappingURL=interaction-to-next-paint-insight.d.ts.map
@@ -0,0 +1,71 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/InteractionToNextPaint.js';
8
+
9
+ import {Audit} from '../audit.js';
10
+ import * as i18n from '../../lib/i18n/i18n.js';
11
+ import {adaptInsightToAuditProduct, maybeMakeNodeElementTable} from './insight-audit.js';
12
+
13
+ // eslint-disable-next-line max-len
14
+ const str_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/InteractionToNextPaint.js', UIStrings);
15
+
16
+ class InteractionToNextPaintInsight extends Audit {
17
+ /**
18
+ * @return {LH.Audit.Meta}
19
+ */
20
+ static get meta() {
21
+ return {
22
+ id: 'interaction-to-next-paint-insight',
23
+ title: str_(UIStrings.title),
24
+ failureTitle: str_(UIStrings.title),
25
+ description: str_(UIStrings.description),
26
+ guidanceLevel: 3,
27
+ requiredArtifacts: ['traces', 'TraceElements'],
28
+ replacesAudits: ['work-during-interaction'],
29
+ };
30
+ }
31
+
32
+ /**
33
+ * @param {LH.Artifacts} artifacts
34
+ * @param {LH.Audit.Context} context
35
+ * @return {Promise<LH.Audit.Product>}
36
+ */
37
+ static async audit(artifacts, context) {
38
+ return adaptInsightToAuditProduct(artifacts, context, 'InteractionToNextPaint', (insight) => {
39
+ const event = insight.longestInteractionEvent;
40
+ if (!event) {
41
+ // TODO: show UIStrings.noInteractions?
42
+ return;
43
+ }
44
+
45
+ /** @type {LH.Audit.Details.Table['headings']} */
46
+ const headings = [
47
+ {key: 'label', valueType: 'text', label: str_(UIStrings.phase)},
48
+ {key: 'duration', valueType: 'ms', label: str_(i18n.UIStrings.columnDuration)},
49
+ ];
50
+
51
+ /** @type {LH.Audit.Details.Table['items']} */
52
+ const items = [
53
+ /* eslint-disable max-len */
54
+ {phase: 'inputDelay', label: str_(UIStrings.inputDelay), duration: event.inputDelay / 1000},
55
+ {phase: 'processingDuration', label: str_(UIStrings.processingDuration), duration: event.mainThreadHandling / 1000},
56
+ {phase: 'presentationDelay', label: str_(UIStrings.presentationDelay), duration: event.presentationDelay / 1000},
57
+ /* eslint-enable max-len */
58
+ ];
59
+
60
+ return Audit.makeListDetails([
61
+ maybeMakeNodeElementTable(
62
+ artifacts.TraceElements,
63
+ event.args.data.beginEvent.args.data.nodeId,
64
+ str_(i18n.UIStrings.columnElement)),
65
+ Audit.makeTableDetails(headings, items),
66
+ ].filter(table => !!table));
67
+ });
68
+ }
69
+ }
70
+
71
+ export default InteractionToNextPaintInsight;
@@ -0,0 +1,11 @@
1
+ export default LCPDiscoveryInsight;
2
+ declare class LCPDiscoveryInsight extends Audit {
3
+ /**
4
+ * @param {LH.Artifacts} artifacts
5
+ * @param {LH.Audit.Context} context
6
+ * @return {Promise<LH.Audit.Product>}
7
+ */
8
+ static audit(artifacts: LH.Artifacts, context: LH.Audit.Context): Promise<LH.Audit.Product>;
9
+ }
10
+ import { Audit } from '../audit.js';
11
+ //# sourceMappingURL=lcp-discovery-insight.d.ts.map
@@ -0,0 +1,48 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/LCPDiscovery.js';
8
+
9
+ import {Audit} from '../audit.js';
10
+ import * as i18n from '../../lib/i18n/i18n.js';
11
+ import {adaptInsightToAuditProduct} from './insight-audit.js';
12
+
13
+ // eslint-disable-next-line max-len
14
+ const str_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/LCPDiscovery.js', UIStrings);
15
+
16
+ class LCPDiscoveryInsight extends Audit {
17
+ /**
18
+ * @return {LH.Audit.Meta}
19
+ */
20
+ static get meta() {
21
+ return {
22
+ id: 'lcp-discovery-insight',
23
+ title: str_(UIStrings.title),
24
+ failureTitle: str_(UIStrings.title),
25
+ description: str_(UIStrings.description),
26
+ guidanceLevel: 3,
27
+ requiredArtifacts: ['traces', 'TraceElements'],
28
+ replacesAudits: ['prioritize-lcp-image', 'lcp-lazy-loaded'],
29
+ };
30
+ }
31
+
32
+ /**
33
+ * @param {LH.Artifacts} artifacts
34
+ * @param {LH.Audit.Context} context
35
+ * @return {Promise<LH.Audit.Product>}
36
+ */
37
+ static async audit(artifacts, context) {
38
+ return adaptInsightToAuditProduct(artifacts, context, 'LCPDiscovery', (insight) => {
39
+ if (!insight.checklist) {
40
+ return;
41
+ }
42
+
43
+ return Audit.makeChecklistDetails(insight.checklist);
44
+ });
45
+ }
46
+ }
47
+
48
+ export default LCPDiscoveryInsight;
@@ -0,0 +1,16 @@
1
+ export default LCPPhasesInsight;
2
+ declare class LCPPhasesInsight extends Audit {
3
+ /**
4
+ * @param {Required<import('@paulirish/trace_engine/models/trace/insights/LCPPhases.js').LCPPhasesInsightModel>['phases']} phases
5
+ * @return {LH.Audit.Details.Table}
6
+ */
7
+ static makePhaseTable(phases: Required<import("@paulirish/trace_engine/models/trace/insights/LCPPhases.js").LCPPhasesInsightModel>["phases"]): LH.Audit.Details.Table;
8
+ /**
9
+ * @param {LH.Artifacts} artifacts
10
+ * @param {LH.Audit.Context} context
11
+ * @return {Promise<LH.Audit.Product>}
12
+ */
13
+ static audit(artifacts: LH.Artifacts, context: LH.Audit.Context): Promise<LH.Audit.Product>;
14
+ }
15
+ import { Audit } from '../audit.js';
16
+ //# sourceMappingURL=lcp-phases-insight.d.ts.map
@@ -0,0 +1,87 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/LCPPhases.js';
8
+
9
+ import {Audit} from '../audit.js';
10
+ import * as i18n from '../../lib/i18n/i18n.js';
11
+ import {adaptInsightToAuditProduct, maybeMakeNodeElementTable} from './insight-audit.js';
12
+
13
+ // eslint-disable-next-line max-len
14
+ const str_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/LCPPhases.js', UIStrings);
15
+
16
+ class LCPPhasesInsight extends Audit {
17
+ /**
18
+ * @return {LH.Audit.Meta}
19
+ */
20
+ static get meta() {
21
+ return {
22
+ id: 'lcp-phases-insight',
23
+ title: str_(UIStrings.title),
24
+ failureTitle: str_(UIStrings.title),
25
+ description: str_(UIStrings.description),
26
+ guidanceLevel: 3,
27
+ requiredArtifacts: ['traces', 'TraceElements'],
28
+ replacesAudits: ['largest-contentful-paint-element'],
29
+ };
30
+ }
31
+
32
+ /**
33
+ * @param {Required<import('@paulirish/trace_engine/models/trace/insights/LCPPhases.js').LCPPhasesInsightModel>['phases']} phases
34
+ * @return {LH.Audit.Details.Table}
35
+ */
36
+ static makePhaseTable(phases) {
37
+ const {ttfb, loadDelay, loadTime, renderDelay} = phases;
38
+
39
+ /** @type {LH.Audit.Details.Table['headings']} */
40
+ const headings = [
41
+ {key: 'label', valueType: 'text', label: str_(UIStrings.phase)},
42
+ {key: 'duration', valueType: 'ms', label: str_(i18n.UIStrings.columnDuration)},
43
+ ];
44
+
45
+ /** @type {LH.Audit.Details.Table['items']} */
46
+ let items = [
47
+ /* eslint-disable max-len */
48
+ {phase: 'timeToFirstByte', label: str_(UIStrings.timeToFirstByte), duration: ttfb},
49
+ {phase: 'resourceLoadDelay', label: str_(UIStrings.resourceLoadDelay), duration: loadDelay},
50
+ {phase: 'resourceLoadDuration', label: str_(UIStrings.resourceLoadDuration), duration: loadTime},
51
+ {phase: 'elementRenderDelay', label: str_(UIStrings.elementRenderDelay), duration: renderDelay},
52
+ /* eslint-enable max-len */
53
+ ];
54
+
55
+ if (loadDelay === undefined) {
56
+ items = items.filter(item => item.phase !== 'resourceLoadDelay');
57
+ }
58
+ if (loadTime === undefined) {
59
+ items = items.filter(item => item.phase !== 'resourceLoadDuration');
60
+ }
61
+
62
+ return Audit.makeTableDetails(headings, items);
63
+ }
64
+
65
+ /**
66
+ * @param {LH.Artifacts} artifacts
67
+ * @param {LH.Audit.Context} context
68
+ * @return {Promise<LH.Audit.Product>}
69
+ */
70
+ static async audit(artifacts, context) {
71
+ return adaptInsightToAuditProduct(artifacts, context, 'LCPPhases', (insight) => {
72
+ if (!insight.phases) {
73
+ return;
74
+ }
75
+
76
+ return Audit.makeListDetails([
77
+ maybeMakeNodeElementTable(
78
+ artifacts.TraceElements,
79
+ insight.lcpEvent?.args.data?.nodeId,
80
+ str_(i18n.UIStrings.columnElement)),
81
+ LCPPhasesInsight.makePhaseTable(insight.phases),
82
+ ].filter(table => table !== undefined));
83
+ });
84
+ }
85
+ }
86
+
87
+ export default LCPPhasesInsight;
@@ -0,0 +1,11 @@
1
+ export default LongCriticalNetworkTreeInsight;
2
+ declare class LongCriticalNetworkTreeInsight extends Audit {
3
+ /**
4
+ * @param {LH.Artifacts} artifacts
5
+ * @param {LH.Audit.Context} context
6
+ * @return {Promise<LH.Audit.Product>}
7
+ */
8
+ static audit(artifacts: LH.Artifacts, context: LH.Audit.Context): Promise<LH.Audit.Product>;
9
+ }
10
+ import { Audit } from '../audit.js';
11
+ //# sourceMappingURL=long-critical-network-tree-insight.d.ts.map
@@ -0,0 +1,53 @@
1
+ /* eslint-disable no-unused-vars */ // TODO: remove once implemented.
2
+
3
+ /**
4
+ * @license
5
+ * Copyright 2025 Google LLC
6
+ * SPDX-License-Identifier: Apache-2.0
7
+ */
8
+
9
+ import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/LongCriticalNetworkTree.js';
10
+
11
+ import {Audit} from '../audit.js';
12
+ import * as i18n from '../../lib/i18n/i18n.js';
13
+ import {adaptInsightToAuditProduct, makeNodeItemForNodeId} from './insight-audit.js';
14
+
15
+ // eslint-disable-next-line max-len
16
+ const str_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/LongCriticalNetworkTree.js', UIStrings);
17
+
18
+ class LongCriticalNetworkTreeInsight extends Audit {
19
+ /**
20
+ * @return {LH.Audit.Meta}
21
+ */
22
+ static get meta() {
23
+ return {
24
+ id: 'long-critical-network-tree-insight',
25
+ title: str_(UIStrings.title),
26
+ failureTitle: str_(UIStrings.title),
27
+ description: str_(UIStrings.description),
28
+ guidanceLevel: 3,
29
+ requiredArtifacts: ['traces', 'TraceElements'],
30
+ replacesAudits: ['critical-request-chains'],
31
+ };
32
+ }
33
+
34
+ /**
35
+ * @param {LH.Artifacts} artifacts
36
+ * @param {LH.Audit.Context} context
37
+ * @return {Promise<LH.Audit.Product>}
38
+ */
39
+ static async audit(artifacts, context) {
40
+ // TODO: implement.
41
+ return adaptInsightToAuditProduct(artifacts, context, 'LongCriticalNetworkTree', (insight) => {
42
+ /** @type {LH.Audit.Details.Table['headings']} */
43
+ const headings = [
44
+ ];
45
+ /** @type {LH.Audit.Details.Table['items']} */
46
+ const items = [
47
+ ];
48
+ return Audit.makeTableDetails(headings, items);
49
+ });
50
+ }
51
+ }
52
+
53
+ export default LongCriticalNetworkTreeInsight;
@@ -0,0 +1,11 @@
1
+ export default RenderBlockingInsight;
2
+ declare class RenderBlockingInsight extends Audit {
3
+ /**
4
+ * @param {LH.Artifacts} artifacts
5
+ * @param {LH.Audit.Context} context
6
+ * @return {Promise<LH.Audit.Product>}
7
+ */
8
+ static audit(artifacts: LH.Artifacts, context: LH.Audit.Context): Promise<LH.Audit.Product>;
9
+ }
10
+ import { Audit } from '../audit.js';
11
+ //# sourceMappingURL=render-blocking-insight.d.ts.map
@@ -0,0 +1,57 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/RenderBlocking.js';
8
+
9
+ import {Audit} from '../audit.js';
10
+ import * as i18n from '../../lib/i18n/i18n.js';
11
+ import {adaptInsightToAuditProduct} from './insight-audit.js';
12
+
13
+ // eslint-disable-next-line max-len
14
+ const str_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/RenderBlocking.js', UIStrings);
15
+
16
+ class RenderBlockingInsight extends Audit {
17
+ /**
18
+ * @return {LH.Audit.Meta}
19
+ */
20
+ static get meta() {
21
+ return {
22
+ id: 'render-blocking-insight',
23
+ title: str_(UIStrings.title),
24
+ failureTitle: str_(UIStrings.title),
25
+ description: str_(UIStrings.description),
26
+ guidanceLevel: 3,
27
+ requiredArtifacts: ['traces', 'TraceElements'],
28
+ replacesAudits: ['render-blocking-resources'],
29
+ };
30
+ }
31
+
32
+ /**
33
+ * @param {LH.Artifacts} artifacts
34
+ * @param {LH.Audit.Context} context
35
+ * @return {Promise<LH.Audit.Product>}
36
+ */
37
+ static async audit(artifacts, context) {
38
+ // TODO: show UIStrings.noRenderBlocking if nothing was blocking?
39
+ return adaptInsightToAuditProduct(artifacts, context, 'RenderBlocking', (insight) => {
40
+ /** @type {LH.Audit.Details.Table['headings']} */
41
+ const headings = [
42
+ {key: 'url', valueType: 'url', label: str_(i18n.UIStrings.columnURL)},
43
+ {key: 'totalBytes', valueType: 'bytes', label: str_(i18n.UIStrings.columnTransferSize)},
44
+ {key: 'wastedMs', valueType: 'timespanMs', label: str_(i18n.UIStrings.columnWastedMs)},
45
+ ];
46
+ /** @type {LH.Audit.Details.Table['items']} */
47
+ const items = insight.renderBlockingRequests.map(request => ({
48
+ url: request.args.data.url,
49
+ totalBytes: request.args.data.encodedDataLength,
50
+ wastedMs: insight.requestIdToWastedMs?.get(request.args.data.requestId),
51
+ }));
52
+ return Audit.makeTableDetails(headings, items);
53
+ });
54
+ }
55
+ }
56
+
57
+ export default RenderBlockingInsight;
@@ -0,0 +1,11 @@
1
+ export default SlowCSSSelectorInsight;
2
+ declare class SlowCSSSelectorInsight extends Audit {
3
+ /**
4
+ * @param {LH.Artifacts} artifacts
5
+ * @param {LH.Audit.Context} context
6
+ * @return {Promise<LH.Audit.Product>}
7
+ */
8
+ static audit(artifacts: LH.Artifacts, context: LH.Audit.Context): Promise<LH.Audit.Product>;
9
+ }
10
+ import { Audit } from '../audit.js';
11
+ //# sourceMappingURL=slow-css-selector-insight.d.ts.map
@@ -0,0 +1,52 @@
1
+ /* eslint-disable no-unused-vars */ // TODO: remove once implemented.
2
+
3
+ /**
4
+ * @license
5
+ * Copyright 2025 Google LLC
6
+ * SPDX-License-Identifier: Apache-2.0
7
+ */
8
+
9
+ import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/SlowCSSSelector.js';
10
+
11
+ import {Audit} from '../audit.js';
12
+ import * as i18n from '../../lib/i18n/i18n.js';
13
+ import {adaptInsightToAuditProduct, makeNodeItemForNodeId} from './insight-audit.js';
14
+
15
+ // eslint-disable-next-line max-len
16
+ const str_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/SlowCSSSelector.js', UIStrings);
17
+
18
+ class SlowCSSSelectorInsight extends Audit {
19
+ /**
20
+ * @return {LH.Audit.Meta}
21
+ */
22
+ static get meta() {
23
+ return {
24
+ id: 'slow-css-selector-insight',
25
+ title: str_(UIStrings.title),
26
+ failureTitle: str_(UIStrings.title),
27
+ description: str_(UIStrings.description),
28
+ guidanceLevel: 3,
29
+ requiredArtifacts: ['traces', 'TraceElements'],
30
+ };
31
+ }
32
+
33
+ /**
34
+ * @param {LH.Artifacts} artifacts
35
+ * @param {LH.Audit.Context} context
36
+ * @return {Promise<LH.Audit.Product>}
37
+ */
38
+ static async audit(artifacts, context) {
39
+ // TODO: implement.
40
+ return adaptInsightToAuditProduct(artifacts, context, 'SlowCSSSelector', (insight) => {
41
+ /** @type {LH.Audit.Details.Table['headings']} */
42
+ const headings = [
43
+ ];
44
+ /** @type {LH.Audit.Details.Table['items']} */
45
+ const items = [
46
+ ];
47
+ return Audit.makeTableDetails(headings, items);
48
+ });
49
+ }
50
+ }
51
+
52
+ export default SlowCSSSelectorInsight;
@@ -0,0 +1,28 @@
1
+ export default ThirdPartiesInsight;
2
+ export type URLSummary = {
3
+ transferSize: number;
4
+ mainThreadTime: number;
5
+ url: string | LH.IcuMessage;
6
+ };
7
+ /**
8
+ * @typedef URLSummary
9
+ * @property {number} transferSize
10
+ * @property {number} mainThreadTime
11
+ * @property {string | LH.IcuMessage} url
12
+ */
13
+ declare class ThirdPartiesInsight extends Audit {
14
+ /**
15
+ * @param {LH.Artifacts.Entity} entity
16
+ * @param {import('@paulirish/trace_engine/models/trace/insights/ThirdParties.js').ThirdPartiesInsightModel} insight
17
+ * @return {Array<URLSummary>}
18
+ */
19
+ static makeSubItems(entity: LH.Artifacts.Entity, insight: import("@paulirish/trace_engine/models/trace/insights/ThirdParties.js").ThirdPartiesInsightModel): Array<URLSummary>;
20
+ /**
21
+ * @param {LH.Artifacts} artifacts
22
+ * @param {LH.Audit.Context} context
23
+ * @return {Promise<LH.Audit.Product>}
24
+ */
25
+ static audit(artifacts: LH.Artifacts, context: LH.Audit.Context): Promise<LH.Audit.Product>;
26
+ }
27
+ import { Audit } from '../audit.js';
28
+ //# sourceMappingURL=third-parties-insight.d.ts.map
@@ -0,0 +1,90 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/ThirdParties.js';
8
+
9
+ import {Audit} from '../audit.js';
10
+ import * as i18n from '../../lib/i18n/i18n.js';
11
+ import {adaptInsightToAuditProduct} from './insight-audit.js';
12
+
13
+ // eslint-disable-next-line max-len
14
+ const str_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/ThirdParties.js', UIStrings);
15
+
16
+ /**
17
+ * @typedef URLSummary
18
+ * @property {number} transferSize
19
+ * @property {number} mainThreadTime
20
+ * @property {string | LH.IcuMessage} url
21
+ */
22
+
23
+ class ThirdPartiesInsight extends Audit {
24
+ /**
25
+ * @return {LH.Audit.Meta}
26
+ */
27
+ static get meta() {
28
+ return {
29
+ id: 'third-parties-insight',
30
+ title: str_(UIStrings.title),
31
+ failureTitle: str_(UIStrings.title),
32
+ description: str_(UIStrings.description),
33
+ guidanceLevel: 3,
34
+ requiredArtifacts: ['traces', 'TraceElements'],
35
+ replacesAudits: ['third-party-summary'],
36
+ };
37
+ }
38
+
39
+ /**
40
+ * @param {LH.Artifacts.Entity} entity
41
+ * @param {import('@paulirish/trace_engine/models/trace/insights/ThirdParties.js').ThirdPartiesInsightModel} insight
42
+ * @return {Array<URLSummary>}
43
+ */
44
+ static makeSubItems(entity, insight) {
45
+ const urls = [...insight.urlsByEntity.get(entity) ?? []];
46
+ return urls
47
+ .map(url => ({
48
+ url,
49
+ mainThreadTime: 0,
50
+ transferSize: 0,
51
+ ...insight.summaryByUrl.get(url),
52
+ }))
53
+ // Sort by main thread time first, then transfer size to break ties.
54
+ .sort((a, b) => (b.mainThreadTime - a.mainThreadTime) || (b.transferSize - a.transferSize));
55
+ }
56
+
57
+ /**
58
+ * @param {LH.Artifacts} artifacts
59
+ * @param {LH.Audit.Context} context
60
+ * @return {Promise<LH.Audit.Product>}
61
+ */
62
+ static async audit(artifacts, context) {
63
+ return adaptInsightToAuditProduct(artifacts, context, 'ThirdParties', (insight) => {
64
+ const thirdPartyEntities = [...insight.summaryByEntity.entries()]
65
+ .filter((([entity, _]) => entity !== insight.firstPartyEntity));
66
+
67
+ /** @type {LH.Audit.Details.Table['headings']} */
68
+ const headings = [
69
+ /* eslint-disable max-len */
70
+ {key: 'entity', valueType: 'text', label: str_(UIStrings.columnThirdParty), subItemsHeading: {key: 'url', valueType: 'url'}},
71
+ {key: 'transferSize', granularity: 1, valueType: 'bytes', label: str_(UIStrings.columnTransferSize), subItemsHeading: {key: 'transferSize'}},
72
+ {key: 'mainThreadTime', granularity: 1, valueType: 'ms', label: str_(UIStrings.columnMainThreadTime), subItemsHeading: {key: 'mainThreadTime'}},
73
+ /* eslint-enable max-len */
74
+ ];
75
+ /** @type {LH.Audit.Details.Table['items']} */
76
+ const items = thirdPartyEntities.map(([entity, summary]) => ({
77
+ entity: entity.name,
78
+ transferSize: summary.transferSize,
79
+ mainThreadTime: summary.mainThreadTime,
80
+ subItems: {
81
+ type: /** @type {const} */ ('subitems'),
82
+ items: ThirdPartiesInsight.makeSubItems(entity, insight),
83
+ },
84
+ }));
85
+ return Audit.makeTableDetails(headings, items, {isEntityGrouped: true});
86
+ });
87
+ }
88
+ }
89
+
90
+ export default ThirdPartiesInsight;
@@ -0,0 +1,11 @@
1
+ export default ViewportInsight;
2
+ declare class ViewportInsight extends Audit {
3
+ /**
4
+ * @param {LH.Artifacts} artifacts
5
+ * @param {LH.Audit.Context} context
6
+ * @return {Promise<LH.Audit.Product>}
7
+ */
8
+ static audit(artifacts: LH.Artifacts, context: LH.Audit.Context): Promise<LH.Audit.Product>;
9
+ }
10
+ import { Audit } from '../audit.js';
11
+ //# sourceMappingURL=viewport-insight.d.ts.map
@@ -0,0 +1,54 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/Viewport.js';
8
+
9
+ import {Audit} from '../audit.js';
10
+ import * as i18n from '../../lib/i18n/i18n.js';
11
+ import {adaptInsightToAuditProduct, makeNodeItemForNodeId} from './insight-audit.js';
12
+
13
+ // eslint-disable-next-line max-len
14
+ const str_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/Viewport.js', UIStrings);
15
+
16
+ class ViewportInsight extends Audit {
17
+ /**
18
+ * @return {LH.Audit.Meta}
19
+ */
20
+ static get meta() {
21
+ return {
22
+ id: 'viewport-insight',
23
+ title: str_(UIStrings.title),
24
+ failureTitle: str_(UIStrings.title),
25
+ description: str_(UIStrings.description),
26
+ guidanceLevel: 3,
27
+ requiredArtifacts: ['traces', 'TraceElements'],
28
+ replacesAudits: ['viewport'],
29
+ };
30
+ }
31
+
32
+ /**
33
+ * @param {LH.Artifacts} artifacts
34
+ * @param {LH.Audit.Context} context
35
+ * @return {Promise<LH.Audit.Product>}
36
+ */
37
+ static async audit(artifacts, context) {
38
+ return adaptInsightToAuditProduct(artifacts, context, 'Viewport', (insight) => {
39
+ const nodeId = insight.viewportEvent?.args.data.node_id;
40
+
41
+ /** @type {LH.Audit.Details.Table['headings']} */
42
+ const headings = [
43
+ {key: 'node', valueType: 'node', label: ''},
44
+ ];
45
+ /** @type {LH.Audit.Details.Table['items']} */
46
+ const items = [
47
+ {node: makeNodeItemForNodeId(artifacts.TraceElements, nodeId)},
48
+ ];
49
+ return Audit.makeTableDetails(headings, items);
50
+ });
51
+ }
52
+ }
53
+
54
+ export default ViewportInsight;
@@ -26,7 +26,6 @@ export namespace UIStrings {
26
26
  let rootCauseUnsizedMedia: string;
27
27
  let rootCauseFontChanges: string;
28
28
  let rootCauseInjectedIframe: string;
29
- let rootCauseRenderBlockingRequest: string;
30
29
  let displayValueShiftsFound: string;
31
30
  }
32
31
  import { Audit } from './audit.js';