lighthouse 9.5.0-dev.20220329 → 9.5.0-dev.20220330

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 (59) hide show
  1. package/dist/report/bundle.esm.js +20 -18
  2. package/dist/report/flow.js +1 -1
  3. package/dist/report/standalone.js +1 -1
  4. package/lighthouse-cli/test/smokehouse/lighthouse-runners/devtools.js +26 -18
  5. package/lighthouse-core/audits/byte-efficiency/byte-efficiency-audit.js +2 -1
  6. package/lighthouse-core/audits/byte-efficiency/efficient-animated-content.js +1 -1
  7. package/lighthouse-core/audits/byte-efficiency/offscreen-images.js +3 -2
  8. package/lighthouse-core/audits/byte-efficiency/render-blocking-resources.js +1 -1
  9. package/lighthouse-core/audits/byte-efficiency/unused-javascript.js +1 -1
  10. package/lighthouse-core/audits/byte-efficiency/uses-responsive-images.js +1 -1
  11. package/lighthouse-core/audits/byte-efficiency/uses-text-compression.js +1 -1
  12. package/lighthouse-core/audits/dobetterweb/uses-http2.js +2 -1
  13. package/lighthouse-core/audits/long-tasks.js +3 -2
  14. package/lighthouse-core/audits/metrics/first-contentful-paint-3g.js +2 -2
  15. package/lighthouse-core/audits/metrics/first-contentful-paint.js +3 -2
  16. package/lighthouse-core/audits/metrics/first-meaningful-paint.js +3 -2
  17. package/lighthouse-core/audits/metrics/interactive.js +3 -2
  18. package/lighthouse-core/audits/metrics/largest-contentful-paint.js +3 -2
  19. package/lighthouse-core/audits/metrics/max-potential-fid.js +3 -2
  20. package/lighthouse-core/audits/metrics/speed-index.js +3 -2
  21. package/lighthouse-core/audits/metrics/total-blocking-time.js +3 -2
  22. package/lighthouse-core/audits/metrics.js +3 -2
  23. package/lighthouse-core/audits/predictive-perf.js +2 -1
  24. package/lighthouse-core/audits/preload-lcp-image.js +1 -1
  25. package/lighthouse-core/audits/redirects.js +1 -1
  26. package/lighthouse-core/audits/timing-budget.js +3 -2
  27. package/lighthouse-core/audits/uses-rel-preconnect.js +1 -1
  28. package/lighthouse-core/audits/uses-rel-preload.js +1 -1
  29. package/lighthouse-core/computed/critical-request-chains.js +2 -9
  30. package/lighthouse-core/computed/main-resource.js +1 -1
  31. package/lighthouse-core/computed/metrics/first-contentful-paint-all-frames.js +1 -1
  32. package/lighthouse-core/computed/metrics/first-contentful-paint.js +1 -1
  33. package/lighthouse-core/computed/metrics/first-meaningful-paint.js +1 -1
  34. package/lighthouse-core/computed/metrics/interactive.js +1 -1
  35. package/lighthouse-core/computed/metrics/lantern-first-contentful-paint.js +1 -1
  36. package/lighthouse-core/computed/metrics/lantern-first-meaningful-paint.js +1 -1
  37. package/lighthouse-core/computed/metrics/lantern-interactive.js +1 -1
  38. package/lighthouse-core/computed/metrics/lantern-largest-contentful-paint.js +1 -1
  39. package/lighthouse-core/computed/metrics/lantern-max-potential-fid.js +1 -1
  40. package/lighthouse-core/computed/metrics/lantern-metric.js +3 -5
  41. package/lighthouse-core/computed/metrics/lantern-speed-index.js +1 -1
  42. package/lighthouse-core/computed/metrics/lantern-total-blocking-time.js +1 -1
  43. package/lighthouse-core/computed/metrics/largest-contentful-paint-all-frames.js +1 -1
  44. package/lighthouse-core/computed/metrics/largest-contentful-paint.js +1 -1
  45. package/lighthouse-core/computed/metrics/max-potential-fid.js +1 -1
  46. package/lighthouse-core/computed/metrics/metric.js +1 -0
  47. package/lighthouse-core/computed/metrics/speed-index.js +1 -1
  48. package/lighthouse-core/computed/metrics/timing-summary.js +13 -6
  49. package/lighthouse-core/computed/metrics/total-blocking-time.js +1 -1
  50. package/lighthouse-core/computed/page-dependency-graph.js +54 -31
  51. package/lighthouse-core/gather/driver/execution-context.js +4 -2
  52. package/lighthouse-core/gather/gatherers/js-usage.js +7 -6
  53. package/lighthouse-core/gather/gatherers/scripts.js +20 -2
  54. package/lighthouse-core/lib/dependency-graph/simulator/network-analyzer.js +8 -29
  55. package/lighthouse-core/lib/navigation-error.js +13 -4
  56. package/lighthouse-core/util-commonjs.js +20 -18
  57. package/package.json +1 -1
  58. package/report/renderer/util.js +20 -18
  59. package/types/artifacts.d.ts +1 -0
@@ -29,7 +29,7 @@ class LargestContentfulPaint extends Audit {
29
29
  description: str_(UIStrings.description),
30
30
  scoreDisplayMode: Audit.SCORING_MODES.NUMERIC,
31
31
  supportedModes: ['navigation'],
32
- requiredArtifacts: ['HostUserAgent', 'traces', 'devtoolsLogs', 'GatherContext'],
32
+ requiredArtifacts: ['HostUserAgent', 'traces', 'devtoolsLogs', 'GatherContext', 'URL'],
33
33
  };
34
34
  }
35
35
 
@@ -74,7 +74,8 @@ class LargestContentfulPaint extends Audit {
74
74
  const trace = artifacts.traces[Audit.DEFAULT_PASS];
75
75
  const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
76
76
  const gatherContext = artifacts.GatherContext;
77
- const metricComputationData = {trace, devtoolsLog, gatherContext, settings: context.settings};
77
+ const metricComputationData = {trace, devtoolsLog, gatherContext,
78
+ settings: context.settings, URL: artifacts.URL};
78
79
 
79
80
  let metricResult;
80
81
  try {
@@ -33,7 +33,7 @@ class MaxPotentialFID extends Audit {
33
33
  description: str_(UIStrings.description),
34
34
  scoreDisplayMode: Audit.SCORING_MODES.NUMERIC,
35
35
  supportedModes: ['navigation'],
36
- requiredArtifacts: ['traces', 'devtoolsLogs', 'GatherContext'],
36
+ requiredArtifacts: ['traces', 'devtoolsLogs', 'GatherContext', 'URL'],
37
37
  };
38
38
  }
39
39
 
@@ -57,7 +57,8 @@ class MaxPotentialFID extends Audit {
57
57
  const trace = artifacts.traces[Audit.DEFAULT_PASS];
58
58
  const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
59
59
  const gatherContext = artifacts.GatherContext;
60
- const metricComputationData = {trace, devtoolsLog, gatherContext, settings: context.settings};
60
+ const metricComputationData = {trace, devtoolsLog, gatherContext,
61
+ settings: context.settings, URL: artifacts.URL};
61
62
  const metricResult = await ComputedFid.request(metricComputationData, context);
62
63
 
63
64
  return {
@@ -28,7 +28,7 @@ class SpeedIndex extends Audit {
28
28
  description: str_(UIStrings.description),
29
29
  scoreDisplayMode: Audit.SCORING_MODES.NUMERIC,
30
30
  supportedModes: ['navigation'],
31
- requiredArtifacts: ['traces', 'devtoolsLogs', 'GatherContext'],
31
+ requiredArtifacts: ['traces', 'devtoolsLogs', 'GatherContext', 'URL'],
32
32
  };
33
33
  }
34
34
 
@@ -67,7 +67,8 @@ class SpeedIndex extends Audit {
67
67
  const trace = artifacts.traces[Audit.DEFAULT_PASS];
68
68
  const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
69
69
  const gatherContext = artifacts.GatherContext;
70
- const metricComputationData = {trace, devtoolsLog, gatherContext, settings: context.settings};
70
+ const metricComputationData = {trace, devtoolsLog, gatherContext,
71
+ settings: context.settings, URL: artifacts.URL};
71
72
  const metricResult = await ComputedSi.request(metricComputationData, context);
72
73
  const options = context.options[context.settings.formFactor];
73
74
 
@@ -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'],
30
+ requiredArtifacts: ['traces', 'devtoolsLogs', 'GatherContext', 'URL'],
31
31
  };
32
32
  }
33
33
 
@@ -88,7 +88,8 @@ 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, settings: context.settings};
91
+ const metricComputationData = {trace, devtoolsLog, gatherContext,
92
+ settings: context.settings, URL: artifacts.URL};
92
93
  if (
93
94
  gatherContext.gatherMode === 'timespan' &&
94
95
  context.settings.throttlingMethod === 'simulate'
@@ -29,7 +29,7 @@ class Metrics extends Audit {
29
29
  title: 'Metrics',
30
30
  description: 'Collects all available metrics.',
31
31
  supportedModes: ['navigation'],
32
- requiredArtifacts: ['traces', 'devtoolsLogs', 'GatherContext'],
32
+ requiredArtifacts: ['traces', 'devtoolsLogs', 'GatherContext', 'URL'],
33
33
  };
34
34
  }
35
35
 
@@ -42,8 +42,9 @@ class Metrics extends Audit {
42
42
  const gatherContext = artifacts.GatherContext;
43
43
  const trace = artifacts.traces[Audit.DEFAULT_PASS];
44
44
  const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
45
+ const URL = artifacts.URL;
45
46
  const summary = await ComputedTimingSummary
46
- .request({trace, devtoolsLog, gatherContext, settings: context.settings}, context);
47
+ .request({trace, devtoolsLog, gatherContext, settings: context.settings, URL}, context);
47
48
  const metrics = summary.metrics;
48
49
  const debugInfo = summary.debugInfo;
49
50
 
@@ -47,10 +47,11 @@ class PredictivePerf extends Audit {
47
47
  const gatherContext = artifacts.GatherContext;
48
48
  const trace = artifacts.traces[Audit.DEFAULT_PASS];
49
49
  const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
50
+ const URL = artifacts.URL;
50
51
  /** @type {LH.Config.Settings} */
51
52
  // @ts-expect-error - TODO(bckenny): allow optional `throttling` settings
52
53
  const settings = {}; // Use default settings.
53
- const computationData = {trace, devtoolsLog, gatherContext, settings};
54
+ const computationData = {trace, devtoolsLog, gatherContext, settings, URL};
54
55
  const fcp = await LanternFcp.request(computationData, context);
55
56
  const fmp = await LanternFmp.request(computationData, context);
56
57
  const tti = await LanternInteractive.request(computationData, context);
@@ -203,7 +203,7 @@ class PreloadLCPImageAudit extends Audit {
203
203
  const trace = artifacts.traces[PreloadLCPImageAudit.DEFAULT_PASS];
204
204
  const devtoolsLog = artifacts.devtoolsLogs[PreloadLCPImageAudit.DEFAULT_PASS];
205
205
  const URL = artifacts.URL;
206
- const metricData = {trace, devtoolsLog, gatherContext, settings: context.settings};
206
+ const metricData = {trace, devtoolsLog, gatherContext, settings: context.settings, URL};
207
207
  const lcpElement = artifacts.TraceElements
208
208
  .find(element => element.traceEventType === 'largest-contentful-paint');
209
209
 
@@ -93,7 +93,7 @@ class Redirects extends Audit {
93
93
  const networkRecords = await NetworkRecords.request(devtoolsLog, context);
94
94
  const mainResource = await MainResource.request({URL: artifacts.URL, devtoolsLog}, context);
95
95
 
96
- const metricComputationData = {trace, devtoolsLog, gatherContext, settings};
96
+ const metricComputationData = {trace, devtoolsLog, gatherContext, settings, URL: artifacts.URL};
97
97
  const metricResult = await LanternInteractive.request(metricComputationData, context);
98
98
 
99
99
  /** @type {Map<string, LH.Gatherer.Simulation.NodeTiming>} */
@@ -140,8 +140,9 @@ class TimingBudget extends Audit {
140
140
  const gatherContext = artifacts.GatherContext;
141
141
  const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
142
142
  const trace = artifacts.traces[Audit.DEFAULT_PASS];
143
- const mainResource = await MainResource.request({URL: artifacts.URL, devtoolsLog}, context);
144
- const data = {trace, devtoolsLog, gatherContext, settings: context.settings};
143
+ const URL = artifacts.URL;
144
+ const mainResource = await MainResource.request({URL, devtoolsLog}, context);
145
+ const data = {trace, devtoolsLog, gatherContext, settings: context.settings, URL};
145
146
  const summary = (await TimingSummary.request(data, context)).metrics;
146
147
  const budget = Budget.getMatchingBudget(context.settings.budgets, mainResource.url);
147
148
 
@@ -123,7 +123,7 @@ class UsesRelPreconnectAudit extends Audit {
123
123
  MainResource.request({devtoolsLog, URL: artifacts.URL}, context),
124
124
  LoadSimulator.request({devtoolsLog, settings}, context),
125
125
  ProcessedNavigation.request(processedTrace, context),
126
- PageDependencyGraph.request({trace, devtoolsLog}, context),
126
+ PageDependencyGraph.request({trace, devtoolsLog, URL: artifacts.URL}, context),
127
127
  ]);
128
128
 
129
129
  const {rtt, additionalRttByOrigin} = loadSimulator.getOptions();
@@ -217,7 +217,7 @@ class UsesRelPreloadAudit extends Audit {
217
217
 
218
218
  const [mainResource, graph, simulator] = await Promise.all([
219
219
  MainResource.request({devtoolsLog, URL}, context),
220
- PageDependencyGraph.request({trace, devtoolsLog}, context),
220
+ PageDependencyGraph.request({trace, devtoolsLog, URL}, context),
221
221
  LoadSimulator.request(simulatorOptions, context),
222
222
  ]);
223
223
 
@@ -129,15 +129,8 @@ class CriticalRequestChains {
129
129
  * @return {Promise<LH.Artifacts.CriticalRequestNode>}
130
130
  */
131
131
  static async compute_(data, context) {
132
- const mainResource = await MainResource.request({
133
- URL: data.URL,
134
- devtoolsLog: data.devtoolsLog,
135
- }, context);
136
-
137
- const graph = await PageDependencyGraph.request({
138
- trace: data.trace,
139
- devtoolsLog: data.devtoolsLog,
140
- }, context);
132
+ const mainResource = await MainResource.request(data, context);
133
+ const graph = await PageDependencyGraph.request(data, context);
141
134
 
142
135
  return CriticalRequestChains.extractChainsFromGraph(mainResource, graph);
143
136
  }
@@ -22,7 +22,7 @@ class MainResource {
22
22
  static async compute_(data, context) {
23
23
  const finalUrl = data.URL.finalUrl;
24
24
  const requests = await NetworkRecords.request(data.devtoolsLog, context);
25
- const mainResource = NetworkAnalyzer.findMainDocument(requests, finalUrl);
25
+ const mainResource = NetworkAnalyzer.findResourceForUrl(requests, finalUrl);
26
26
  if (!mainResource) {
27
27
  throw new Error('Unable to identify the main resource');
28
28
  }
@@ -33,5 +33,5 @@ class FirstContentfulPaintAllFrames extends NavigationMetric {
33
33
 
34
34
  module.exports = makeComputedArtifact(
35
35
  FirstContentfulPaintAllFrames,
36
- ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace']
36
+ ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
37
37
  );
@@ -36,5 +36,5 @@ class FirstContentfulPaint extends NavigationMetric {
36
36
 
37
37
  module.exports = makeComputedArtifact(
38
38
  FirstContentfulPaint,
39
- ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace']
39
+ ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
40
40
  );
@@ -40,5 +40,5 @@ class FirstMeaningfulPaint extends NavigationMetric {
40
40
 
41
41
  module.exports = makeComputedArtifact(
42
42
  FirstMeaningfulPaint,
43
- ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace']
43
+ ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
44
44
  );
@@ -183,7 +183,7 @@ class Interactive extends NavigationMetric {
183
183
 
184
184
  module.exports = makeComputedArtifact(
185
185
  Interactive,
186
- ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace']
186
+ ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
187
187
  );
188
188
 
189
189
  /**
@@ -200,5 +200,5 @@ class LanternFirstContentfulPaint extends LanternMetric {
200
200
 
201
201
  module.exports = makeComputedArtifact(
202
202
  LanternFirstContentfulPaint,
203
- ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace']
203
+ ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
204
204
  );
@@ -79,5 +79,5 @@ class LanternFirstMeaningfulPaint extends LanternMetric {
79
79
 
80
80
  module.exports = makeComputedArtifact(
81
81
  LanternFirstMeaningfulPaint,
82
- ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace']
82
+ ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
83
83
  );
@@ -109,5 +109,5 @@ class LanternInteractive extends LanternMetric {
109
109
 
110
110
  module.exports = makeComputedArtifact(
111
111
  LanternInteractive,
112
- ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace']
112
+ ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
113
113
  );
@@ -107,5 +107,5 @@ class LanternLargestContentfulPaint extends LanternMetric {
107
107
 
108
108
  module.exports = makeComputedArtifact(
109
109
  LanternLargestContentfulPaint,
110
- ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace']
110
+ ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
111
111
  );
@@ -89,5 +89,5 @@ class LanternMaxPotentialFID extends LanternMetricArtifact {
89
89
 
90
90
  module.exports = makeComputedArtifact(
91
91
  LanternMaxPotentialFID,
92
- ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace']
92
+ ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
93
93
  );
@@ -101,17 +101,15 @@ class LanternMetricArtifact {
101
101
  static async computeMetricWithGraphs(data, context, extras) {
102
102
  // TODO: remove this fallback when lighthouse-pub-ads plugin can update.
103
103
  const gatherContext = data.gatherContext || {gatherMode: 'navigation'};
104
- const {trace, devtoolsLog, settings} = data;
105
104
  if (gatherContext.gatherMode !== 'navigation') {
106
105
  throw new Error(`Lantern metrics can only be computed on navigations`);
107
106
  }
108
107
 
109
108
  const metricName = this.name.replace('Lantern', '');
110
- const graph = await PageDependencyGraph.request({trace, devtoolsLog}, context);
111
- const processedTrace = await ProcessedTrace.request(trace, context);
109
+ const graph = await PageDependencyGraph.request(data, context);
110
+ const processedTrace = await ProcessedTrace.request(data.trace, context);
112
111
  const processedNavigation = await ProcessedNavigation.request(processedTrace, context);
113
- const simulator = data.simulator ||
114
- (await LoadSimulator.request({devtoolsLog, settings}, context));
112
+ const simulator = data.simulator || (await LoadSimulator.request(data, context));
115
113
 
116
114
  const optimisticGraph = this.getOptimisticGraph(graph, processedNavigation);
117
115
  const pessimisticGraph = this.getPessimisticGraph(graph, processedNavigation);
@@ -146,5 +146,5 @@ class LanternSpeedIndex extends LanternMetric {
146
146
 
147
147
  module.exports = makeComputedArtifact(
148
148
  LanternSpeedIndex,
149
- ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace']
149
+ ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
150
150
  );
@@ -122,5 +122,5 @@ class LanternTotalBlockingTime extends LanternMetric {
122
122
 
123
123
  module.exports = makeComputedArtifact(
124
124
  LanternTotalBlockingTime,
125
- ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace']
125
+ ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
126
126
  );
@@ -41,5 +41,5 @@ class LargestContentfulPaintAllFrames extends NavigationMetric {
41
41
 
42
42
  module.exports = makeComputedArtifact(
43
43
  LargestContentfulPaintAllFrames,
44
- ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace']
44
+ ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
45
45
  );
@@ -48,5 +48,5 @@ class LargestContentfulPaint extends NavigationMetric {
48
48
 
49
49
  module.exports = makeComputedArtifact(
50
50
  LargestContentfulPaint,
51
- ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace']
51
+ ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
52
52
  );
@@ -41,5 +41,5 @@ class MaxPotentialFID extends NavigationMetric {
41
41
 
42
42
  module.exports = makeComputedArtifact(
43
43
  MaxPotentialFID,
44
- ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace']
44
+ ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
45
45
  );
@@ -34,6 +34,7 @@ class Metric {
34
34
  devtoolsLog: data.devtoolsLog,
35
35
  gatherContext: data.gatherContext,
36
36
  settings: data.settings,
37
+ URL: data.URL,
37
38
  };
38
39
  }
39
40
 
@@ -36,5 +36,5 @@ class SpeedIndex extends NavigationMetric {
36
36
 
37
37
  module.exports = makeComputedArtifact(
38
38
  SpeedIndex,
39
- ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace']
39
+ ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
40
40
  );
@@ -26,11 +26,12 @@ class TimingSummary {
26
26
  * @param {LH.DevtoolsLog} devtoolsLog
27
27
  * @param {LH.Artifacts['GatherContext']} gatherContext
28
28
  * @param {ImmutableObject<LH.Config.Settings>} settings
29
+ * @param {LH.Artifacts['URL']} URL
29
30
  * @param {LH.Artifacts.ComputedContext} context
30
31
  * @return {Promise<{metrics: LH.Artifacts.TimingSummary, debugInfo: Record<string,boolean>}>}
31
32
  */
32
- static async summarize(trace, devtoolsLog, gatherContext, settings, context) {
33
- const metricComputationData = {trace, devtoolsLog, gatherContext, settings};
33
+ static async summarize(trace, devtoolsLog, gatherContext, settings, URL, context) {
34
+ const metricComputationData = {trace, devtoolsLog, gatherContext, settings, URL};
34
35
  /**
35
36
  * @template TArtifacts
36
37
  * @template TReturn
@@ -134,17 +135,23 @@ class TimingSummary {
134
135
  return {metrics, debugInfo};
135
136
  }
136
137
  /**
137
- * @param {{trace: LH.Trace, devtoolsLog: LH.DevtoolsLog, gatherContext: LH.Artifacts['GatherContext']; settings: ImmutableObject<LH.Config.Settings>}} data
138
+ * @param {{trace: LH.Trace, devtoolsLog: LH.DevtoolsLog, gatherContext: LH.Artifacts['GatherContext']; settings: ImmutableObject<LH.Config.Settings>, URL: LH.Artifacts['URL']}} data
138
139
  * @param {LH.Artifacts.ComputedContext} context
139
140
  * @return {Promise<{metrics: LH.Artifacts.TimingSummary, debugInfo: Record<string,boolean>}>}
140
141
  */
141
142
  static async compute_(data, context) {
142
- return TimingSummary.summarize(data.trace, data.devtoolsLog, data.gatherContext, data.settings,
143
- context);
143
+ return TimingSummary.summarize(
144
+ data.trace,
145
+ data.devtoolsLog,
146
+ data.gatherContext,
147
+ data.settings,
148
+ data.URL,
149
+ context
150
+ );
144
151
  }
145
152
  }
146
153
 
147
154
  module.exports = makeComputedArtifact(
148
155
  TimingSummary,
149
- ['devtoolsLog', 'gatherContext', 'settings', 'trace']
156
+ ['devtoolsLog', 'gatherContext', 'settings', 'trace', 'URL']
150
157
  );
@@ -70,5 +70,5 @@ class TotalBlockingTime extends ComputedMetric {
70
70
 
71
71
  module.exports = makeComputedArtifact(
72
72
  TotalBlockingTime,
73
- ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace']
73
+ ['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
74
74
  );
@@ -8,13 +8,14 @@
8
8
  const makeComputedArtifact = require('./computed-artifact.js');
9
9
  const NetworkNode = require('../lib/dependency-graph/network-node.js');
10
10
  const CPUNode = require('../lib/dependency-graph/cpu-node.js');
11
- const NetworkAnalyzer = require('../lib/dependency-graph/simulator/network-analyzer.js');
12
11
  const TracingProcessor = require('../lib/tracehouse/trace-processor.js');
13
12
  const NetworkRequest = require('../lib/network-request.js');
14
13
  const ProcessedTrace = require('./processed-trace.js');
15
14
  const NetworkRecords = require('./network-records.js');
15
+ const NetworkAnalyzer = require('../lib/dependency-graph/simulator/network-analyzer.js');
16
16
 
17
17
  /** @typedef {import('../lib/dependency-graph/base-node.js').Node} Node */
18
+ /** @typedef {Omit<LH.Artifacts['URL'], 'initialUrl'|'finalUrl'>} URLArtifact */
18
19
 
19
20
  // Shorter tasks have negligible impact on simulation results.
20
21
  const SIGNIFICANT_DUR_THRESHOLD_MS = 10;
@@ -388,37 +389,24 @@ class PageDependencyGraph {
388
389
  /**
389
390
  * @param {LH.Artifacts.ProcessedTrace} processedTrace
390
391
  * @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
392
+ * @param {URLArtifact} URL
391
393
  * @return {Node}
392
394
  */
393
- static createGraph(processedTrace, networkRecords) {
395
+ static createGraph(processedTrace, networkRecords, URL) {
394
396
  const networkNodeOutput = PageDependencyGraph.getNetworkNodeOutput(networkRecords);
395
397
  const cpuNodes = PageDependencyGraph.getCPUNodes(processedTrace);
398
+ const {requestedUrl, mainDocumentUrl} = URL;
399
+ if (!mainDocumentUrl) throw new Error('mainDocumentUrl is required to get the main resource');
396
400
 
397
- // TODO: Remove this usage of `findMainDocument` and create a new function to get the first document request.
398
- // https://github.com/GoogleChrome/lighthouse/issues/8984
399
- //
400
- // The main document request is the earliest network request *of type document*.
401
- // This will be different from the root request when there are server redirects.
402
- const mainDocumentRequest = NetworkAnalyzer.findMainDocument(networkRecords);
403
- const mainDocumentNode = networkNodeOutput.idToNodeMap.get(mainDocumentRequest.requestId);
404
- if (!mainDocumentNode) {
405
- // mainDocumentNode should always be found.
406
- throw new Error('mainDocumentNode not found.');
407
- }
401
+ const rootRequest = NetworkAnalyzer.findResourceForUrl(networkRecords, requestedUrl);
402
+ if (!rootRequest) throw new Error('rootRequest not found');
403
+ const rootNode = networkNodeOutput.idToNodeMap.get(rootRequest.requestId);
404
+ if (!rootNode) throw new Error('rootNode not found');
408
405
 
409
- // The root request is the earliest request in the main document redirect chain.
410
- // Will be undefined if there were no redirects.
411
- const rootRequest = mainDocumentNode.record.redirects?.[0];
412
-
413
- let rootNode;
414
- if (rootRequest) {
415
- // rootNode should always be found.
416
- rootNode = rootRequest && networkNodeOutput.idToNodeMap.get(rootRequest.requestId);
417
- if (!rootNode) throw new Error('rootNode not found');
418
- } else {
419
- // Use main document as root if there were no redirects.
420
- rootNode = mainDocumentNode;
421
- }
406
+ const mainDocumentRequest = NetworkAnalyzer.findResourceForUrl(networkRecords, mainDocumentUrl);
407
+ if (!mainDocumentRequest) throw new Error('mainDocumentRequest not found');
408
+ const mainDocumentNode = networkNodeOutput.idToNodeMap.get(mainDocumentRequest.requestId);
409
+ if (!mainDocumentNode) throw new Error('mainDocumentNode not found');
422
410
 
423
411
  PageDependencyGraph.linkNetworkNodes(rootNode, networkNodeOutput);
424
412
  PageDependencyGraph.linkCPUNodes(rootNode, networkNodeOutput, cpuNodes);
@@ -464,23 +452,58 @@ class PageDependencyGraph {
464
452
  }
465
453
 
466
454
  /**
467
- * @param {{trace: LH.Trace, devtoolsLog: LH.DevtoolsLog}} data
455
+ * Recalculate `artifacts.URL` for clients that don't provide it.
456
+ *
457
+ * @param {LH.DevtoolsLog} devtoolsLog
458
+ * @param {LH.Artifacts.NetworkRequest[]} networkRecords
459
+ * @param {LH.Artifacts.ProcessedTrace} processedTrace
460
+ * @return {URLArtifact}
461
+ */
462
+ static getDocumentUrls(devtoolsLog, networkRecords, processedTrace) {
463
+ const mainFrameId = processedTrace.mainFrameIds.frameId;
464
+
465
+ /** @type {string|undefined} */
466
+ let requestedUrl;
467
+ /** @type {string|undefined} */
468
+ let mainDocumentUrl;
469
+ for (const event of devtoolsLog) {
470
+ if (event.method === 'Page.frameNavigated' && event.params.frame.id === mainFrameId) {
471
+ const {url} = event.params.frame;
472
+ // Only set requestedUrl on the first main frame navigation.
473
+ if (!requestedUrl) requestedUrl = url;
474
+ mainDocumentUrl = url;
475
+ }
476
+ }
477
+ if (!requestedUrl || !mainDocumentUrl) throw new Error('No main frame navigations found');
478
+
479
+ const initialRequest = NetworkAnalyzer.findResourceForUrl(networkRecords, requestedUrl);
480
+ if (initialRequest?.redirects?.length) requestedUrl = initialRequest.redirects[0].url;
481
+
482
+ return {requestedUrl, mainDocumentUrl};
483
+ }
484
+
485
+ /**
486
+ * @param {{trace: LH.Trace, devtoolsLog: LH.DevtoolsLog, URL: LH.Artifacts['URL']}} data
468
487
  * @param {LH.Artifacts.ComputedContext} context
469
488
  * @return {Promise<Node>}
470
489
  */
471
490
  static async compute_(data, context) {
472
- const trace = data.trace;
473
- const devtoolsLog = data.devtoolsLog;
491
+ const {trace, devtoolsLog} = data;
474
492
  const [processedTrace, networkRecords] = await Promise.all([
475
493
  ProcessedTrace.request(trace, context),
476
494
  NetworkRecords.request(devtoolsLog, context),
477
495
  ]);
478
496
 
479
- return PageDependencyGraph.createGraph(processedTrace, networkRecords);
497
+ // COMPAT: Backport for pre-10.0 clients that don't pass the URL artifact here (e.g. pubads).
498
+ // Calculates the URL artifact from the processed trace and DT log.
499
+ const URL = data.URL ||
500
+ PageDependencyGraph.getDocumentUrls(devtoolsLog, networkRecords, processedTrace);
501
+
502
+ return PageDependencyGraph.createGraph(processedTrace, networkRecords, URL);
480
503
  }
481
504
  }
482
505
 
483
- module.exports = makeComputedArtifact(PageDependencyGraph, ['devtoolsLog', 'trace']);
506
+ module.exports = makeComputedArtifact(PageDependencyGraph, ['devtoolsLog', 'trace', 'URL']);
484
507
 
485
508
  /**
486
509
  * @typedef {Object} NetworkNodeOutput
@@ -97,7 +97,8 @@ class ExecutionContext {
97
97
  .catch(${pageFunctions.wrapRuntimeEvalErrorInBrowserString})
98
98
  .then(resolve);
99
99
  });
100
- }())`,
100
+ }())
101
+ //# sourceURL=_lighthouse-eval.js`,
101
102
  includeCommandLineAPI: true,
102
103
  awaitPromise: true,
103
104
  returnByValue: true,
@@ -195,7 +196,8 @@ class ExecutionContext {
195
196
  ${ExecutionContext._cachedNativesPreamble};
196
197
  ${depsSerialized};
197
198
  (${mainFn})(${argsSerialized});
198
- })()`;
199
+ })()
200
+ //# sourceURL=_lighthouse-eval.js`;
199
201
 
200
202
  await this._session.sendCommand('Page.addScriptToEvaluateOnNewDocument', {source: expression});
201
203
  }
@@ -50,12 +50,13 @@ class JsUsage extends FRGatherer {
50
50
  const usageByScriptId = {};
51
51
 
52
52
  for (const scriptUsage of this._scriptUsages) {
53
- // If `url` is blank, that means the script was anonymous (eval, new Function, onload, ...).
54
- // Or, it's because it was code Lighthouse over the protocol via `Runtime.evaluate`.
55
- // We currently don't consider coverage of anonymous scripts, and we definitely don't want
56
- // coverage of code Lighthouse ran to inspect the page, so we ignore this ScriptCoverage if
57
- // url is blank.
58
- if (scriptUsage.url === '') {
53
+ // If `url` is blank, that means the script was dynamically
54
+ // created (eval, new Function, onload, ...)
55
+ if (scriptUsage.url === '' || scriptUsage.url === '_lighthouse-eval.js') {
56
+ // We currently don't consider coverage of dynamic scripts, and we definitely don't want
57
+ // coverage of code Lighthouse ran to inspect the page, so we ignore this ScriptCoverage.
58
+ // Audits would work the same without this, it is only an optimization (not tracking coverage
59
+ // for scripts we don't care about).
59
60
  continue;
60
61
  }
61
62
 
@@ -28,6 +28,23 @@ async function runInSeriesOrParallel(values, promiseMapper, runInSeries) {
28
28
  }
29
29
  }
30
30
 
31
+ /**
32
+ * Returns true if the script was created via our own calls
33
+ * to Runtime.evaluate.
34
+ * @param {LH.Crdp.Debugger.ScriptParsedEvent} script
35
+ */
36
+ function isLighthouseRuntimeEvaluateScript(script) {
37
+ // Scripts created by Runtime.evaluate that run on the main session/frame
38
+ // result in an empty string for the embedderName.
39
+ // Or, it means the script was dynamically created (eval, new Function, onload, ...)
40
+ if (!script.embedderName) return true;
41
+
42
+ // Otherwise, when running our own code inside other frames, the embedderName
43
+ // is set to the frame's url. In that case, we rely on the special sourceURL that
44
+ // we set.
45
+ return script.hasSourceURL && script.url === '_lighthouse-eval.js';
46
+ }
47
+
31
48
  /**
32
49
  * @fileoverview Gets JavaScript file contents.
33
50
  */
@@ -68,8 +85,9 @@ class Scripts extends FRGatherer {
68
85
  // it also blocks scripts from the same origin but that happen to run in a different process,
69
86
  // like a worker.
70
87
  if (event.method === 'Debugger.scriptParsed' && !sessionId) {
71
- // Events without an embedderName (read: a url) are for JS that we ran over the protocol.
72
- if (event.params.embedderName) this._scriptParsedEvents.push(event.params);
88
+ if (!isLighthouseRuntimeEvaluateScript(event.params)) {
89
+ this._scriptParsedEvents.push(event.params);
90
+ }
73
91
  }
74
92
  }
75
93