lighthouse 12.4.0-dev.20250318 → 12.4.0-dev.20250320

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 (147) hide show
  1. package/core/audits/audit.js +3 -1
  2. package/core/audits/bootup-time.js +1 -1
  3. package/core/audits/byte-efficiency/efficient-animated-content.js +1 -1
  4. package/core/audits/byte-efficiency/modern-image-formats.js +1 -1
  5. package/core/audits/byte-efficiency/offscreen-images.js +4 -3
  6. package/core/audits/byte-efficiency/render-blocking-resources.js +5 -3
  7. package/core/audits/byte-efficiency/unminified-css.js +2 -1
  8. package/core/audits/byte-efficiency/unminified-javascript.js +2 -1
  9. package/core/audits/byte-efficiency/unused-css-rules.js +1 -1
  10. package/core/audits/byte-efficiency/unused-javascript.js +2 -2
  11. package/core/audits/byte-efficiency/uses-long-cache-ttl.js +1 -1
  12. package/core/audits/byte-efficiency/uses-optimized-images.js +1 -1
  13. package/core/audits/byte-efficiency/uses-responsive-images.js +1 -1
  14. package/core/audits/byte-efficiency/uses-text-compression.js +2 -1
  15. package/core/audits/critical-request-chains.js +4 -3
  16. package/core/audits/dobetterweb/dom-size.js +1 -1
  17. package/core/audits/dobetterweb/uses-http2.js +1 -1
  18. package/core/audits/insights/cls-culprits-insight.js +1 -1
  19. package/core/audits/insights/document-latency-insight.js +1 -1
  20. package/core/audits/insights/dom-size-insight.js +1 -1
  21. package/core/audits/insights/duplicated-javascript-insight.d.ts +11 -0
  22. package/core/audits/insights/{duplicate-javascript-insight.js → duplicated-javascript-insight.js} +7 -7
  23. package/core/audits/insights/font-display-insight.js +1 -1
  24. package/core/audits/insights/forced-reflow-insight.d.ts +10 -0
  25. package/core/audits/insights/forced-reflow-insight.js +64 -12
  26. package/core/audits/insights/image-delivery-insight.js +1 -1
  27. package/core/audits/insights/insight-audit.js +2 -1
  28. package/core/audits/insights/interaction-to-next-paint-insight.js +1 -1
  29. package/core/audits/insights/lcp-discovery-insight.js +1 -1
  30. package/core/audits/insights/lcp-phases-insight.js +1 -1
  31. package/core/audits/insights/network-dependency-tree-insight.js +1 -1
  32. package/core/audits/insights/render-blocking-insight.js +1 -1
  33. package/core/audits/insights/slow-css-selector-insight.js +1 -1
  34. package/core/audits/insights/third-parties-insight.js +1 -1
  35. package/core/audits/insights/{duplicate-javascript-insight.d.ts → use-cache-insight.d.ts} +3 -3
  36. package/core/audits/insights/use-cache-insight.js +54 -0
  37. package/core/audits/insights/viewport-insight.js +1 -1
  38. package/core/audits/largest-contentful-paint-element.js +7 -3
  39. package/core/audits/layout-shifts.js +4 -2
  40. package/core/audits/lcp-lazy-loaded.js +1 -1
  41. package/core/audits/long-tasks.js +5 -4
  42. package/core/audits/mainthread-work-breakdown.js +1 -1
  43. package/core/audits/metrics/first-contentful-paint.js +4 -2
  44. package/core/audits/metrics/interactive.js +6 -3
  45. package/core/audits/metrics/largest-contentful-paint.js +7 -3
  46. package/core/audits/metrics/max-potential-fid.js +6 -3
  47. package/core/audits/metrics/speed-index.js +6 -3
  48. package/core/audits/metrics/total-blocking-time.js +6 -3
  49. package/core/audits/metrics.js +4 -3
  50. package/core/audits/predictive-perf.js +4 -3
  51. package/core/audits/prioritize-lcp-image.js +5 -3
  52. package/core/audits/redirects.js +4 -2
  53. package/core/audits/script-treemap-data.js +2 -2
  54. package/core/audits/third-party-facades.js +1 -1
  55. package/core/audits/third-party-summary.js +1 -1
  56. package/core/audits/uses-rel-preconnect.js +7 -5
  57. package/core/audits/uses-rel-preload.js +4 -3
  58. package/core/computed/computed-artifact.d.ts +5 -1
  59. package/core/computed/computed-artifact.js +23 -2
  60. package/core/computed/critical-request-chains.d.ts +3 -1
  61. package/core/computed/critical-request-chains.js +4 -4
  62. package/core/computed/metrics/first-contentful-paint-all-frames.js +1 -1
  63. package/core/computed/metrics/first-contentful-paint.js +1 -1
  64. package/core/computed/metrics/interactive.js +1 -1
  65. package/core/computed/metrics/lantern-first-contentful-paint.js +1 -1
  66. package/core/computed/metrics/lantern-interactive.js +1 -1
  67. package/core/computed/metrics/lantern-largest-contentful-paint.js +1 -1
  68. package/core/computed/metrics/lantern-max-potential-fid.js +1 -1
  69. package/core/computed/metrics/lantern-metric.js +1 -1
  70. package/core/computed/metrics/lantern-speed-index.js +1 -1
  71. package/core/computed/metrics/lantern-total-blocking-time.js +1 -1
  72. package/core/computed/metrics/largest-contentful-paint-all-frames.js +1 -1
  73. package/core/computed/metrics/largest-contentful-paint.js +1 -1
  74. package/core/computed/metrics/lcp-breakdown.js +1 -1
  75. package/core/computed/metrics/max-potential-fid.js +1 -1
  76. package/core/computed/metrics/metric.js +2 -0
  77. package/core/computed/metrics/speed-index.js +1 -1
  78. package/core/computed/metrics/time-to-first-byte.js +1 -1
  79. package/core/computed/metrics/timing-summary.d.ts +5 -2
  80. package/core/computed/metrics/timing-summary.js +8 -4
  81. package/core/computed/metrics/total-blocking-time.js +1 -1
  82. package/core/computed/navigation-insights.d.ts +3 -1
  83. package/core/computed/navigation-insights.js +6 -4
  84. package/core/computed/page-dependency-graph.d.ts +5 -3
  85. package/core/computed/page-dependency-graph.js +5 -4
  86. package/core/computed/tbt-impact-tasks.js +1 -1
  87. package/core/computed/trace-engine-result.d.ts +5 -2
  88. package/core/computed/trace-engine-result.js +18 -4
  89. package/core/computed/unused-javascript-summary.d.ts +2 -2
  90. package/core/computed/unused-javascript-summary.js +1 -1
  91. package/core/config/default-config.js +4 -2
  92. package/core/config/experimental-config.js +2 -1
  93. package/core/gather/gatherers/source-maps.d.ts +1 -0
  94. package/core/gather/gatherers/source-maps.js +3 -0
  95. package/core/gather/gatherers/trace-elements.d.ts +4 -4
  96. package/core/gather/gatherers/trace-elements.js +7 -4
  97. package/core/gather/gatherers/trace.js +5 -0
  98. package/package.json +2 -2
  99. package/shared/localization/locales/ar-XB.json +235 -1
  100. package/shared/localization/locales/ar.json +235 -7
  101. package/shared/localization/locales/bg.json +235 -7
  102. package/shared/localization/locales/ca.json +235 -7
  103. package/shared/localization/locales/cs.json +234 -6
  104. package/shared/localization/locales/da.json +236 -8
  105. package/shared/localization/locales/de.json +234 -6
  106. package/shared/localization/locales/el.json +235 -7
  107. package/shared/localization/locales/en-GB.json +235 -19
  108. package/shared/localization/locales/en-US.json +30 -3
  109. package/shared/localization/locales/en-XA.json +0 -6
  110. package/shared/localization/locales/en-XL.json +30 -3
  111. package/shared/localization/locales/es-419.json +235 -7
  112. package/shared/localization/locales/es.json +234 -6
  113. package/shared/localization/locales/fi.json +235 -7
  114. package/shared/localization/locales/fil.json +237 -3
  115. package/shared/localization/locales/fr.json +236 -8
  116. package/shared/localization/locales/he.json +234 -0
  117. package/shared/localization/locales/hi.json +236 -2
  118. package/shared/localization/locales/hr.json +235 -7
  119. package/shared/localization/locales/hu.json +235 -7
  120. package/shared/localization/locales/id.json +234 -0
  121. package/shared/localization/locales/it.json +238 -10
  122. package/shared/localization/locales/ja.json +234 -6
  123. package/shared/localization/locales/ko.json +235 -16
  124. package/shared/localization/locales/lt.json +235 -7
  125. package/shared/localization/locales/lv.json +236 -8
  126. package/shared/localization/locales/nl.json +235 -4
  127. package/shared/localization/locales/no.json +235 -7
  128. package/shared/localization/locales/pl.json +236 -8
  129. package/shared/localization/locales/pt-PT.json +235 -1
  130. package/shared/localization/locales/pt.json +235 -1
  131. package/shared/localization/locales/ro.json +234 -0
  132. package/shared/localization/locales/ru.json +235 -1
  133. package/shared/localization/locales/sk.json +235 -1
  134. package/shared/localization/locales/sl.json +236 -2
  135. package/shared/localization/locales/sr-Latn.json +235 -1
  136. package/shared/localization/locales/sr.json +235 -1
  137. package/shared/localization/locales/sv.json +235 -1
  138. package/shared/localization/locales/ta.json +235 -1
  139. package/shared/localization/locales/te.json +237 -3
  140. package/shared/localization/locales/th.json +235 -1
  141. package/shared/localization/locales/tr.json +236 -2
  142. package/shared/localization/locales/uk.json +235 -1
  143. package/shared/localization/locales/vi.json +236 -2
  144. package/shared/localization/locales/zh-HK.json +235 -1
  145. package/shared/localization/locales/zh-TW.json +236 -2
  146. package/shared/localization/locales/zh.json +234 -0
  147. package/types/artifacts.d.ts +2 -1
@@ -50,7 +50,8 @@ class LargestContentfulPaintElement extends Audit {
50
50
  guidanceLevel: 1,
51
51
  supportedModes: ['navigation'],
52
52
  requiredArtifacts:
53
- ['traces', 'TraceElements', 'devtoolsLogs', 'GatherContext', 'settings', 'URL'],
53
+ ['traces', 'TraceElements', 'devtoolsLogs', 'GatherContext', 'settings', 'URL',
54
+ 'SourceMaps'],
54
55
  };
55
56
  }
56
57
 
@@ -122,8 +123,11 @@ class LargestContentfulPaintElement extends Audit {
122
123
  const trace = artifacts.traces[Audit.DEFAULT_PASS];
123
124
  const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
124
125
  const gatherContext = artifacts.GatherContext;
125
- const metricComputationData = {trace, devtoolsLog, gatherContext,
126
- settings: context.settings, URL: artifacts.URL};
126
+ const metricComputationData = {
127
+ trace, devtoolsLog, gatherContext,
128
+ settings: context.settings, URL: artifacts.URL,
129
+ SourceMaps: artifacts.SourceMaps, simulator: null,
130
+ };
127
131
 
128
132
  const elementTable = this.makeElementTable(artifacts);
129
133
  if (!elementTable) {
@@ -47,7 +47,7 @@ class LayoutShifts extends Audit {
47
47
  description: str_(UIStrings.description),
48
48
  scoreDisplayMode: Audit.SCORING_MODES.METRIC_SAVINGS,
49
49
  guidanceLevel: 2,
50
- requiredArtifacts: ['traces', 'TraceElements'],
50
+ requiredArtifacts: ['traces', 'TraceElements', 'SourceMaps'],
51
51
  };
52
52
  }
53
53
 
@@ -59,7 +59,9 @@ class LayoutShifts extends Audit {
59
59
  static async audit(artifacts, context) {
60
60
  const settings = context.settings;
61
61
  const trace = artifacts.traces[Audit.DEFAULT_PASS];
62
- const traceEngineResult = await TraceEngineResult.request({trace, settings}, context);
62
+ const SourceMaps = artifacts.SourceMaps;
63
+ const traceEngineResult =
64
+ await TraceEngineResult.request({trace, settings, SourceMaps}, context);
63
65
  const clusters = traceEngineResult.data.LayoutShifts.clusters ?? [];
64
66
  const {cumulativeLayoutShift: clsSavings, impactByNodeId} =
65
67
  await CumulativeLayoutShiftComputed.request(trace, context);
@@ -36,7 +36,7 @@ class LargestContentfulPaintLazyLoaded extends Audit {
36
36
  scoreDisplayMode: Audit.SCORING_MODES.METRIC_SAVINGS,
37
37
  guidanceLevel: 3,
38
38
  requiredArtifacts: ['TraceElements', 'ViewportDimensions', 'ImageElements',
39
- 'traces', 'devtoolsLogs', 'GatherContext', 'URL'],
39
+ 'traces', 'devtoolsLogs', 'GatherContext', 'URL', 'SourceMaps'],
40
40
  };
41
41
  }
42
42
 
@@ -68,7 +68,7 @@ class LongTasks extends Audit {
68
68
  scoreDisplayMode: Audit.SCORING_MODES.INFORMATIVE,
69
69
  title: str_(UIStrings.title),
70
70
  description: str_(UIStrings.description),
71
- requiredArtifacts: ['traces', 'devtoolsLogs', 'URL', 'GatherContext'],
71
+ requiredArtifacts: ['traces', 'devtoolsLogs', 'URL', 'GatherContext', 'SourceMaps'],
72
72
  guidanceLevel: 1,
73
73
  };
74
74
  }
@@ -176,7 +176,7 @@ class LongTasks extends Audit {
176
176
  */
177
177
  static async audit(artifacts, context) {
178
178
  const settings = context.settings || {};
179
- const URL = artifacts.URL;
179
+ const {URL, SourceMaps} = artifacts;
180
180
  const trace = artifacts.traces[Audit.DEFAULT_PASS];
181
181
  const tasks = await MainThreadTasks.request(trace, context);
182
182
  const devtoolsLog = artifacts.devtoolsLogs[LongTasks.DEFAULT_PASS];
@@ -193,9 +193,10 @@ class LongTasks extends Audit {
193
193
 
194
194
  const simulatorOptions = {devtoolsLog, settings: context.settings};
195
195
  const pageGraph =
196
- await PageDependencyGraph.request({settings, trace, devtoolsLog, URL}, context);
196
+ // eslint-disable-next-line max-len
197
+ await PageDependencyGraph.request({settings, trace, devtoolsLog, URL, SourceMaps, fromTrace: false}, context);
197
198
  const simulator = await LoadSimulator.request(simulatorOptions, context);
198
- const simulation = await simulator.simulate(pageGraph, {label: 'long-tasks-diagnostic'});
199
+ const simulation = simulator.simulate(pageGraph, {label: 'long-tasks-diagnostic'});
199
200
  for (const [node, timing] of simulation.nodeTimings.entries()) {
200
201
  if (node.type !== 'cpu') continue;
201
202
  taskTimingsByEvent.set(node.event, timing);
@@ -46,7 +46,7 @@ class MainThreadWorkBreakdown extends Audit {
46
46
  description: str_(UIStrings.description),
47
47
  scoreDisplayMode: Audit.SCORING_MODES.METRIC_SAVINGS,
48
48
  guidanceLevel: 1,
49
- requiredArtifacts: ['traces', 'devtoolsLogs', 'URL', 'GatherContext'],
49
+ requiredArtifacts: ['traces', 'devtoolsLogs', 'URL', 'GatherContext', 'SourceMaps'],
50
50
  };
51
51
  }
52
52
 
@@ -27,7 +27,7 @@ class FirstContentfulPaint extends Audit {
27
27
  description: str_(UIStrings.description),
28
28
  scoreDisplayMode: Audit.SCORING_MODES.NUMERIC,
29
29
  supportedModes: ['navigation'],
30
- requiredArtifacts: ['traces', 'devtoolsLogs', 'GatherContext', 'URL'],
30
+ requiredArtifacts: ['traces', 'devtoolsLogs', 'GatherContext', 'URL', 'SourceMaps'],
31
31
  };
32
32
  }
33
33
 
@@ -65,7 +65,9 @@ class FirstContentfulPaint extends Audit {
65
65
  const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
66
66
  const gatherContext = artifacts.GatherContext;
67
67
  const metricComputationData = {trace, devtoolsLog, gatherContext,
68
- settings: context.settings, URL: artifacts.URL};
68
+ settings: context.settings, URL: artifacts.URL,
69
+ SourceMaps: artifacts.SourceMaps, simulator: null,
70
+ };
69
71
  const metricResult = await ComputedFcp.request(metricComputationData, context);
70
72
  const options = context.options[context.settings.formFactor];
71
73
 
@@ -33,7 +33,7 @@ class InteractiveMetric extends Audit {
33
33
  description: str_(UIStrings.description),
34
34
  scoreDisplayMode: Audit.SCORING_MODES.NUMERIC,
35
35
  supportedModes: ['navigation'],
36
- requiredArtifacts: ['traces', 'devtoolsLogs', 'GatherContext', 'URL'],
36
+ requiredArtifacts: ['traces', 'devtoolsLogs', 'GatherContext', 'URL', 'SourceMaps'],
37
37
  };
38
38
  }
39
39
 
@@ -70,8 +70,11 @@ class InteractiveMetric extends Audit {
70
70
  const trace = artifacts.traces[Audit.DEFAULT_PASS];
71
71
  const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
72
72
  const gatherContext = artifacts.GatherContext;
73
- const metricComputationData = {trace, devtoolsLog, gatherContext,
74
- settings: context.settings, URL: artifacts.URL};
73
+ const metricComputationData = {
74
+ trace, devtoolsLog, gatherContext,
75
+ settings: context.settings, URL: artifacts.URL,
76
+ SourceMaps: artifacts.SourceMaps, simulator: null,
77
+ };
75
78
  const metricResult = await Interactive.request(metricComputationData, context);
76
79
  const timeInMs = metricResult.timing;
77
80
  const options = context.options[context.settings.formFactor];
@@ -27,7 +27,8 @@ class LargestContentfulPaint extends Audit {
27
27
  description: str_(UIStrings.description),
28
28
  scoreDisplayMode: Audit.SCORING_MODES.NUMERIC,
29
29
  supportedModes: ['navigation'],
30
- requiredArtifacts: ['HostUserAgent', 'traces', 'devtoolsLogs', 'GatherContext', 'URL'],
30
+ requiredArtifacts: ['HostUserAgent', 'traces', 'devtoolsLogs', 'GatherContext', 'URL',
31
+ 'SourceMaps'],
31
32
  };
32
33
  }
33
34
 
@@ -72,8 +73,11 @@ class LargestContentfulPaint extends Audit {
72
73
  const trace = artifacts.traces[Audit.DEFAULT_PASS];
73
74
  const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
74
75
  const gatherContext = artifacts.GatherContext;
75
- const metricComputationData = {trace, devtoolsLog, gatherContext,
76
- settings: context.settings, URL: artifacts.URL};
76
+ const metricComputationData = {
77
+ trace, devtoolsLog, gatherContext,
78
+ settings: context.settings, URL: artifacts.URL,
79
+ SourceMaps: artifacts.SourceMaps, simulator: null,
80
+ };
77
81
 
78
82
  const metricResult = await ComputedLcp.request(metricComputationData, context);
79
83
  const options = context.options[context.settings.formFactor];
@@ -43,7 +43,7 @@ class MaxPotentialFID extends Audit {
43
43
  description: str_(UIStrings.description),
44
44
  scoreDisplayMode: Audit.SCORING_MODES.NUMERIC,
45
45
  supportedModes: ['navigation'],
46
- requiredArtifacts: ['traces', 'devtoolsLogs', 'GatherContext', 'URL'],
46
+ requiredArtifacts: ['traces', 'devtoolsLogs', 'GatherContext', 'URL', 'SourceMaps'],
47
47
  };
48
48
  }
49
49
 
@@ -120,8 +120,11 @@ class MaxPotentialFID extends Audit {
120
120
  const trace = artifacts.traces[Audit.DEFAULT_PASS];
121
121
  const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
122
122
  const gatherContext = artifacts.GatherContext;
123
- const metricComputationData = {trace, devtoolsLog, gatherContext,
124
- settings: context.settings, URL: artifacts.URL};
123
+ const metricComputationData = {
124
+ trace, devtoolsLog, gatherContext,
125
+ settings: context.settings, URL: artifacts.URL,
126
+ SourceMaps: artifacts.SourceMaps, simulator: null,
127
+ };
125
128
  const metricResult = await ComputedFid.request(metricComputationData, context);
126
129
 
127
130
  const processedTrace = await ProcessedTrace.request(trace, context);
@@ -27,7 +27,7 @@ class SpeedIndex extends Audit {
27
27
  description: str_(UIStrings.description),
28
28
  scoreDisplayMode: Audit.SCORING_MODES.NUMERIC,
29
29
  supportedModes: ['navigation'],
30
- requiredArtifacts: ['traces', 'devtoolsLogs', 'GatherContext', 'URL'],
30
+ requiredArtifacts: ['traces', 'devtoolsLogs', 'GatherContext', 'URL', 'SourceMaps'],
31
31
  };
32
32
  }
33
33
 
@@ -66,8 +66,11 @@ class SpeedIndex extends Audit {
66
66
  const trace = artifacts.traces[Audit.DEFAULT_PASS];
67
67
  const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
68
68
  const gatherContext = artifacts.GatherContext;
69
- const metricComputationData = {trace, devtoolsLog, gatherContext,
70
- settings: context.settings, URL: artifacts.URL};
69
+ const metricComputationData = {
70
+ trace, devtoolsLog, gatherContext,
71
+ settings: context.settings, URL: artifacts.URL,
72
+ SourceMaps: artifacts.SourceMaps, simulator: null,
73
+ };
71
74
  const metricResult = await ComputedSi.request(metricComputationData, context);
72
75
  const options = context.options[context.settings.formFactor];
73
76
 
@@ -27,7 +27,7 @@ class TotalBlockingTime extends Audit {
27
27
  title: str_(i18n.UIStrings.totalBlockingTimeMetric),
28
28
  description: str_(UIStrings.description),
29
29
  scoreDisplayMode: Audit.SCORING_MODES.NUMERIC,
30
- requiredArtifacts: ['traces', 'devtoolsLogs', 'GatherContext', 'URL'],
30
+ requiredArtifacts: ['traces', 'devtoolsLogs', 'GatherContext', 'URL', 'SourceMaps'],
31
31
  };
32
32
  }
33
33
 
@@ -88,8 +88,11 @@ class TotalBlockingTime extends Audit {
88
88
  const trace = artifacts.traces[Audit.DEFAULT_PASS];
89
89
  const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
90
90
  const gatherContext = artifacts.GatherContext;
91
- const metricComputationData = {trace, devtoolsLog, gatherContext,
92
- settings: context.settings, URL: artifacts.URL};
91
+ const metricComputationData = {
92
+ trace, devtoolsLog, gatherContext,
93
+ settings: context.settings, URL: artifacts.URL,
94
+ SourceMaps: artifacts.SourceMaps, simulator: null,
95
+ };
93
96
  if (
94
97
  gatherContext.gatherMode === 'timespan' &&
95
98
  context.settings.throttlingMethod === 'simulate'
@@ -26,7 +26,7 @@ class Metrics extends Audit {
26
26
  title: 'Metrics',
27
27
  description: 'Collects all available metrics.',
28
28
  supportedModes: ['navigation'],
29
- requiredArtifacts: ['traces', 'devtoolsLogs', 'GatherContext', 'URL'],
29
+ requiredArtifacts: ['traces', 'devtoolsLogs', 'GatherContext', 'URL', 'SourceMaps'],
30
30
  };
31
31
  }
32
32
 
@@ -36,12 +36,13 @@ class Metrics extends Audit {
36
36
  * @return {Promise<LH.Audit.Product>}
37
37
  */
38
38
  static async audit(artifacts, context) {
39
+ const settings = context.settings;
39
40
  const gatherContext = artifacts.GatherContext;
40
41
  const trace = artifacts.traces[Audit.DEFAULT_PASS];
41
42
  const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
42
- const URL = artifacts.URL;
43
+ const {URL, SourceMaps} = artifacts;
43
44
  const summary = await TimingSummary
44
- .request({trace, devtoolsLog, gatherContext, settings: context.settings, URL}, context);
45
+ .request({trace, devtoolsLog, gatherContext, settings, URL, SourceMaps}, context);
45
46
  const metrics = summary.metrics;
46
47
  const debugInfo = summary.debugInfo;
47
48
 
@@ -33,7 +33,7 @@ class PredictivePerf extends Audit {
33
33
  'a cellular connection on a mobile device.',
34
34
  scoreDisplayMode: Audit.SCORING_MODES.NUMERIC,
35
35
  supportedModes: ['navigation'],
36
- requiredArtifacts: ['traces', 'devtoolsLogs', 'GatherContext', 'URL'],
36
+ requiredArtifacts: ['traces', 'devtoolsLogs', 'GatherContext', 'URL', 'SourceMaps'],
37
37
  };
38
38
  }
39
39
 
@@ -46,10 +46,11 @@ class PredictivePerf extends Audit {
46
46
  const gatherContext = artifacts.GatherContext;
47
47
  const trace = artifacts.traces[Audit.DEFAULT_PASS];
48
48
  const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
49
- const URL = artifacts.URL;
49
+ const {URL, SourceMaps} = artifacts;
50
50
  /** @type {LH.Config.Settings} */
51
51
  const settings = JSON.parse(JSON.stringify(defaultSettings)); // Use default settings.
52
- const computationData = {trace, devtoolsLog, gatherContext, settings, URL};
52
+ const computationData =
53
+ {trace, devtoolsLog, gatherContext, settings, URL, SourceMaps, simulator: null};
53
54
  const fcp = await LanternFirstContentfulPaint.request(computationData, context);
54
55
  const tti = await LanternInteractive.request(computationData, context);
55
56
  const si = await LanternSpeedIndex.request(computationData, context);
@@ -38,7 +38,8 @@ class PrioritizeLcpImage extends Audit {
38
38
  description: str_(UIStrings.description),
39
39
  supportedModes: ['navigation'],
40
40
  guidanceLevel: 4,
41
- requiredArtifacts: ['traces', 'devtoolsLogs', 'GatherContext', 'URL', 'TraceElements'],
41
+ requiredArtifacts: ['traces', 'devtoolsLogs', 'GatherContext', 'URL', 'TraceElements',
42
+ 'SourceMaps'],
42
43
  scoreDisplayMode: Audit.SCORING_MODES.METRIC_SAVINGS,
43
44
  };
44
45
  }
@@ -237,9 +238,10 @@ class PrioritizeLcpImage extends Audit {
237
238
  const gatherContext = artifacts.GatherContext;
238
239
  const trace = artifacts.traces[PrioritizeLcpImage.DEFAULT_PASS];
239
240
  const devtoolsLog = artifacts.devtoolsLogs[PrioritizeLcpImage.DEFAULT_PASS];
240
- const URL = artifacts.URL;
241
+ const {URL, SourceMaps} = artifacts;
241
242
  const settings = context.settings;
242
- const metricData = {trace, devtoolsLog, gatherContext, settings, URL};
243
+ const metricData =
244
+ {trace, devtoolsLog, gatherContext, settings, URL, SourceMaps, simulator: null};
243
245
  const lcpElement = artifacts.TraceElements
244
246
  .find(element => element.traceEventType === 'largest-contentful-paint');
245
247
 
@@ -31,7 +31,7 @@ class Redirects extends Audit {
31
31
  scoreDisplayMode: Audit.SCORING_MODES.METRIC_SAVINGS,
32
32
  supportedModes: ['navigation'],
33
33
  guidanceLevel: 2,
34
- requiredArtifacts: ['URL', 'GatherContext', 'devtoolsLogs', 'traces'],
34
+ requiredArtifacts: ['URL', 'GatherContext', 'devtoolsLogs', 'traces', 'SourceMaps'],
35
35
  };
36
36
  }
37
37
 
@@ -87,12 +87,14 @@ class Redirects extends Audit {
87
87
  const trace = artifacts.traces[Audit.DEFAULT_PASS];
88
88
  const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
89
89
  const gatherContext = artifacts.GatherContext;
90
+ const {URL, SourceMaps} = artifacts;
90
91
 
91
92
  const processedTrace = await ProcessedTrace.request(trace, context);
92
93
  const networkRecords = await NetworkRecords.request(devtoolsLog, context);
93
94
  const documentRequests = Redirects.getDocumentRequestChain(networkRecords, processedTrace);
94
95
 
95
- const metricComputationData = {trace, devtoolsLog, gatherContext, settings, URL: artifacts.URL};
96
+ const metricComputationData =
97
+ {trace, devtoolsLog, gatherContext, settings, URL, SourceMaps, simulator: null};
96
98
  const metricResult = await LanternInteractive.request(metricComputationData, context);
97
99
 
98
100
  /** @type {Map<string, LH.Gatherer.Simulation.NodeTiming>} */
@@ -31,7 +31,7 @@ class ScriptTreemapDataAudit extends Audit {
31
31
  title: 'Script Treemap Data',
32
32
  description: 'Used for treemap app',
33
33
  requiredArtifacts:
34
- ['traces', 'devtoolsLogs', 'SourceMaps', 'Scripts', 'JsUsage', 'URL'],
34
+ ['traces', 'devtoolsLogs', 'SourceMaps', 'Scripts', 'JsUsage', 'URL', 'SourceMaps'],
35
35
  };
36
36
  }
37
37
 
@@ -178,7 +178,7 @@ class ScriptTreemapDataAudit extends Audit {
178
178
  if (script.scriptLanguage !== 'JavaScript') continue;
179
179
 
180
180
  const name = script.url;
181
- const bundle = bundles.find(bundle => script.scriptId === bundle.script.scriptId);
181
+ const bundle = bundles.find(bundle => script.scriptId === bundle.script.scriptId) ?? null;
182
182
  const scriptCoverage = /** @type {LH.Artifacts['JsUsage'][string] | undefined} */
183
183
  (artifacts.JsUsage[script.scriptId]);
184
184
  const unusedJavascriptSummary = scriptCoverage ?
@@ -87,7 +87,7 @@ class ThirdPartyFacades extends Audit {
87
87
  description: str_(UIStrings.description),
88
88
  supportedModes: ['navigation'],
89
89
  guidanceLevel: 3,
90
- requiredArtifacts: ['traces', 'devtoolsLogs', 'URL', 'GatherContext'],
90
+ requiredArtifacts: ['traces', 'devtoolsLogs', 'URL', 'GatherContext', 'SourceMaps'],
91
91
  scoreDisplayMode: Audit.SCORING_MODES.METRIC_SAVINGS,
92
92
  };
93
93
  }
@@ -67,7 +67,7 @@ class ThirdPartySummary extends Audit {
67
67
  description: str_(UIStrings.description),
68
68
  guidanceLevel: 1,
69
69
  scoreDisplayMode: Audit.SCORING_MODES.METRIC_SAVINGS,
70
- requiredArtifacts: ['traces', 'devtoolsLogs', 'URL', 'GatherContext'],
70
+ requiredArtifacts: ['traces', 'devtoolsLogs', 'URL', 'GatherContext', 'SourceMaps'],
71
71
  };
72
72
  }
73
73
 
@@ -62,7 +62,7 @@ class UsesRelPreconnectAudit extends Audit {
62
62
  description: str_(UIStrings.description),
63
63
  supportedModes: ['navigation'],
64
64
  guidanceLevel: 3,
65
- requiredArtifacts: ['traces', 'devtoolsLogs', 'URL', 'LinkElements'],
65
+ requiredArtifacts: ['traces', 'devtoolsLogs', 'URL', 'LinkElements', 'SourceMaps'],
66
66
  scoreDisplayMode: Audit.SCORING_MODES.METRIC_SAVINGS,
67
67
  };
68
68
  }
@@ -124,6 +124,7 @@ class UsesRelPreconnectAudit extends Audit {
124
124
  static async audit(artifacts, context) {
125
125
  const trace = artifacts.traces[UsesRelPreconnectAudit.DEFAULT_PASS];
126
126
  const devtoolsLog = artifacts.devtoolsLogs[UsesRelPreconnectAudit.DEFAULT_PASS];
127
+ const {URL, SourceMaps} = artifacts;
127
128
  const settings = context.settings;
128
129
 
129
130
  let maxWastedLcp = 0;
@@ -134,15 +135,16 @@ class UsesRelPreconnectAudit extends Audit {
134
135
  const [networkRecords, mainResource, loadSimulator, processedNavigation, pageGraph] =
135
136
  await Promise.all([
136
137
  NetworkRecords.request(devtoolsLog, context),
137
- MainResource.request({devtoolsLog, URL: artifacts.URL}, context),
138
+ MainResource.request({devtoolsLog, URL}, context),
138
139
  LoadSimulator.request({devtoolsLog, settings}, context),
139
140
  ProcessedNavigation.request(trace, context),
140
- PageDependencyGraph.request({settings, trace, devtoolsLog, URL: artifacts.URL}, context),
141
+ PageDependencyGraph.request(
142
+ {settings, trace, devtoolsLog, URL, SourceMaps, fromTrace: false}, context),
141
143
  ]);
142
144
 
143
145
  const {rtt, additionalRttByOrigin} = loadSimulator.getOptions();
144
146
  const lcpGraph =
145
- await LanternLargestContentfulPaint.getPessimisticGraph(pageGraph, processedNavigation);
147
+ LanternLargestContentfulPaint.getPessimisticGraph(pageGraph, processedNavigation);
146
148
  /** @type {Set<string>} */
147
149
  const lcpGraphURLs = new Set();
148
150
  lcpGraph.traverse(node => {
@@ -150,7 +152,7 @@ class UsesRelPreconnectAudit extends Audit {
150
152
  });
151
153
 
152
154
  const fcpGraph =
153
- await LanternFirstContentfulPaint.getPessimisticGraph(pageGraph, processedNavigation);
155
+ LanternFirstContentfulPaint.getPessimisticGraph(pageGraph, processedNavigation);
154
156
  const fcpGraphURLs = new Set();
155
157
  fcpGraph.traverse(node => {
156
158
  if (node.type === 'network') fcpGraphURLs.add(node.request.url);
@@ -44,7 +44,7 @@ class UsesRelPreloadAudit extends Audit {
44
44
  description: str_(UIStrings.description),
45
45
  supportedModes: ['navigation'],
46
46
  guidanceLevel: 3,
47
- requiredArtifacts: ['devtoolsLogs', 'traces', 'URL'],
47
+ requiredArtifacts: ['devtoolsLogs', 'traces', 'URL', 'SourceMaps'],
48
48
  scoreDisplayMode: Audit.SCORING_MODES.METRIC_SAVINGS,
49
49
  };
50
50
  }
@@ -215,12 +215,13 @@ class UsesRelPreloadAudit extends Audit {
215
215
  const settings = context.settings;
216
216
  const trace = artifacts.traces[UsesRelPreloadAudit.DEFAULT_PASS];
217
217
  const devtoolsLog = artifacts.devtoolsLogs[UsesRelPreloadAudit.DEFAULT_PASS];
218
- const URL = artifacts.URL;
218
+ const {URL, SourceMaps} = artifacts;
219
219
  const simulatorOptions = {devtoolsLog, settings: context.settings};
220
220
 
221
221
  const [mainResource, graph, simulator] = await Promise.all([
222
222
  MainResource.request({devtoolsLog, URL}, context),
223
- PageDependencyGraph.request({settings, trace, devtoolsLog, URL}, context),
223
+ PageDependencyGraph.request(
224
+ {settings, trace, devtoolsLog, URL, SourceMaps, fromTrace: false}, context),
224
225
  LoadSimulator.request(simulatorOptions, context),
225
226
  ]);
226
227
 
@@ -4,7 +4,11 @@
4
4
  * @template {{name: string, compute_(dependencies: unknown, context: LH.Artifacts.ComputedContext): Promise<unknown>}} C
5
5
  * @template {Array<keyof LH.Util.FirstParamType<C['compute_']>>} K
6
6
  * @param {C} computableArtifact
7
- * @param {(K & ([keyof LH.Util.FirstParamType<C['compute_']>] extends [K[number]] ? unknown : never)) | null} keys List of properties of `dependencies` used by `compute_`; other properties are filtered out. Use `null` to allow all properties. Ensures that only required properties are used for caching result.
7
+ * @param {(K & ([keyof LH.Util.FirstParamType<C['compute_']>] extends [K[number]] ? unknown : never)) | null} keys
8
+ * List of properties of `dependencies` used by `compute_`; other properties are filtered out.
9
+ * Use `null` to allow all properties. Ensures that only required properties are used for caching result.
10
+ * For optional properties of `dependencies`, undefined cannot be used and if found is treated as an error.
11
+ * This is to guard against developer mistakes. For optional properties, make it nullable instead.
8
12
  */
9
13
  export function makeComputedArtifact<C extends {
10
14
  name: string;
@@ -7,6 +7,7 @@
7
7
  import log from 'lighthouse-logger';
8
8
 
9
9
  import {ArbitraryEqualityMap} from '../lib/arbitrary-equality-map.js';
10
+ import {isUnderTest} from '../lib/lh-env.js';
10
11
 
11
12
  /**
12
13
  * Decorate computableArtifact with a caching `request()` method which will
@@ -14,7 +15,11 @@ import {ArbitraryEqualityMap} from '../lib/arbitrary-equality-map.js';
14
15
  * @template {{name: string, compute_(dependencies: unknown, context: LH.Artifacts.ComputedContext): Promise<unknown>}} C
15
16
  * @template {Array<keyof LH.Util.FirstParamType<C['compute_']>>} K
16
17
  * @param {C} computableArtifact
17
- * @param {(K & ([keyof LH.Util.FirstParamType<C['compute_']>] extends [K[number]] ? unknown : never)) | null} keys List of properties of `dependencies` used by `compute_`; other properties are filtered out. Use `null` to allow all properties. Ensures that only required properties are used for caching result.
18
+ * @param {(K & ([keyof LH.Util.FirstParamType<C['compute_']>] extends [K[number]] ? unknown : never)) | null} keys
19
+ * List of properties of `dependencies` used by `compute_`; other properties are filtered out.
20
+ * Use `null` to allow all properties. Ensures that only required properties are used for caching result.
21
+ * For optional properties of `dependencies`, undefined cannot be used and if found is treated as an error.
22
+ * This is to guard against developer mistakes. For optional properties, make it nullable instead.
18
23
  */
19
24
  function makeComputedArtifact(computableArtifact, keys) {
20
25
  // tsc (3.1) has more difficulty with template inter-references in jsdoc, so
@@ -27,13 +32,29 @@ function makeComputedArtifact(computableArtifact, keys) {
27
32
  * @return {ReturnType<C['compute_']>}
28
33
  */
29
34
  const request = (dependencies, context) => {
35
+ const computedName = computableArtifact.name;
36
+
37
+ // Guard against missing properties. Optional properties must be passed as null - if missing or
38
+ // undefined, throw an error.
39
+ for (const key of keys || []) {
40
+ if (dependencies && typeof dependencies === 'object' && dependencies[key] === undefined) {
41
+ // eslint-disable-next-line max-len
42
+ const err = new Error(`missing required key "${String(key)}" for computed artifact ${computableArtifact.name}`);
43
+ if (isUnderTest) {
44
+ throw err;
45
+ } else {
46
+ // For now, simply log in production.
47
+ log.error(`lh:computed:${computedName}`, err);
48
+ }
49
+ }
50
+ }
51
+
30
52
  const pickedDependencies = keys ?
31
53
  Object.fromEntries(keys.map(key => [key, dependencies[key]])) :
32
54
  dependencies;
33
55
 
34
56
  // NOTE: break immutability solely for this caching-controller function.
35
57
  const computedCache = /** @type {Map<string, ArbitraryEqualityMap>} */ (context.computedCache);
36
- const computedName = computableArtifact.name;
37
58
 
38
59
  const cache = computedCache.get(computedName) || new ArbitraryEqualityMap();
39
60
  computedCache.set(computedName, cache);
@@ -2,6 +2,7 @@ export { CriticalRequestChainsComputed as CriticalRequestChains };
2
2
  declare const CriticalRequestChainsComputed: typeof CriticalRequestChains & {
3
3
  request: (dependencies: {
4
4
  URL: LH.Artifacts["URL"];
5
+ SourceMaps: LH.Artifacts["SourceMaps"];
5
6
  devtoolsLog: LH.DevtoolsLog;
6
7
  trace: LH.Trace;
7
8
  settings: LH.Audit.Context["settings"];
@@ -25,12 +26,13 @@ declare class CriticalRequestChains {
25
26
  */
26
27
  static extractChainsFromGraph(mainResource: LH.Artifacts.NetworkRequest, graph: LH.Gatherer.Simulation.GraphNode): LH.Artifacts.CriticalRequestNode;
27
28
  /**
28
- * @param {{URL: LH.Artifacts['URL'], devtoolsLog: LH.DevtoolsLog, trace: LH.Trace, settings: LH.Audit.Context['settings']}} data
29
+ * @param {{URL: LH.Artifacts['URL'], SourceMaps: LH.Artifacts['SourceMaps'], devtoolsLog: LH.DevtoolsLog, trace: LH.Trace, settings: LH.Audit.Context['settings']}} data
29
30
  * @param {LH.Artifacts.ComputedContext} context
30
31
  * @return {Promise<LH.Artifacts.CriticalRequestNode>}
31
32
  */
32
33
  static compute_(data: {
33
34
  URL: LH.Artifacts["URL"];
35
+ SourceMaps: LH.Artifacts["SourceMaps"];
34
36
  devtoolsLog: LH.DevtoolsLog;
35
37
  trace: LH.Trace;
36
38
  settings: LH.Audit.Context["settings"];
@@ -126,18 +126,18 @@ class CriticalRequestChains {
126
126
  }
127
127
 
128
128
  /**
129
- * @param {{URL: LH.Artifacts['URL'], devtoolsLog: LH.DevtoolsLog, trace: LH.Trace, settings: LH.Audit.Context['settings']}} data
129
+ * @param {{URL: LH.Artifacts['URL'], SourceMaps: LH.Artifacts['SourceMaps'], devtoolsLog: LH.DevtoolsLog, trace: LH.Trace, settings: LH.Audit.Context['settings']}} data
130
130
  * @param {LH.Artifacts.ComputedContext} context
131
131
  * @return {Promise<LH.Artifacts.CriticalRequestNode>}
132
132
  */
133
133
  static async compute_(data, context) {
134
134
  const mainResource = await MainResource.request(data, context);
135
- const graph = await PageDependencyGraph.request(data, context);
135
+ const graph = await PageDependencyGraph.request({...data, fromTrace: false}, context);
136
136
 
137
137
  return CriticalRequestChains.extractChainsFromGraph(mainResource, graph);
138
138
  }
139
139
  }
140
140
 
141
- const CriticalRequestChainsComputed =
142
- makeComputedArtifact(CriticalRequestChains, ['URL', 'devtoolsLog', 'trace', 'settings']);
141
+ const CriticalRequestChainsComputed = makeComputedArtifact(CriticalRequestChains,
142
+ ['URL', 'SourceMaps', 'devtoolsLog', 'trace', 'settings']);
143
143
  export {CriticalRequestChainsComputed as CriticalRequestChains};
@@ -32,6 +32,6 @@ class FirstContentfulPaintAllFrames extends NavigationMetric {
32
32
 
33
33
  const FirstContentfulPaintAllFramesComputed = makeComputedArtifact(
34
34
  FirstContentfulPaintAllFrames,
35
- ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
35
+ ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL', 'SourceMaps']
36
36
  );
37
37
  export {FirstContentfulPaintAllFramesComputed as FirstContentfulPaintAllFrames};
@@ -35,6 +35,6 @@ class FirstContentfulPaint extends NavigationMetric {
35
35
 
36
36
  const FirstContentfulPaintComputed = makeComputedArtifact(
37
37
  FirstContentfulPaint,
38
- ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
38
+ ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL', 'SourceMaps']
39
39
  );
40
40
  export {FirstContentfulPaintComputed as FirstContentfulPaint};
@@ -181,7 +181,7 @@ class Interactive extends NavigationMetric {
181
181
 
182
182
  const InteractiveComputed = makeComputedArtifact(
183
183
  Interactive,
184
- ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
184
+ ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL', 'SourceMaps']
185
185
  );
186
186
  export {InteractiveComputed as Interactive};
187
187
 
@@ -32,6 +32,6 @@ class LanternFirstContentfulPaint extends Lantern.Metrics.FirstContentfulPaint {
32
32
 
33
33
  const LanternFirstContentfulPaintComputed = makeComputedArtifact(
34
34
  LanternFirstContentfulPaint,
35
- ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
35
+ ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL', 'SourceMaps']
36
36
  );
37
37
  export {LanternFirstContentfulPaintComputed as LanternFirstContentfulPaint};
@@ -34,6 +34,6 @@ class LanternInteractive extends Lantern.Metrics.Interactive {
34
34
 
35
35
  const LanternInteractiveComputed = makeComputedArtifact(
36
36
  LanternInteractive,
37
- ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
37
+ ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL', 'SourceMaps']
38
38
  );
39
39
  export {LanternInteractiveComputed as LanternInteractive};
@@ -34,6 +34,6 @@ class LanternLargestContentfulPaint extends Lantern.Metrics.LargestContentfulPai
34
34
 
35
35
  const LanternLargestContentfulPaintComputed = makeComputedArtifact(
36
36
  LanternLargestContentfulPaint,
37
- ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
37
+ ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL', 'SourceMaps']
38
38
  );
39
39
  export {LanternLargestContentfulPaintComputed as LanternLargestContentfulPaint};
@@ -34,6 +34,6 @@ class LanternMaxPotentialFID extends Lantern.Metrics.MaxPotentialFID {
34
34
 
35
35
  const LanternMaxPotentialFIDComputed = makeComputedArtifact(
36
36
  LanternMaxPotentialFID,
37
- ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
37
+ ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL', 'SourceMaps']
38
38
  );
39
39
  export {LanternMaxPotentialFIDComputed as LanternMaxPotentialFID};