lighthouse 12.0.0-dev.20240602 → 12.0.0-dev.20240604

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 (41) hide show
  1. package/core/audits/byte-efficiency/byte-efficiency-audit.js +1 -1
  2. package/core/audits/byte-efficiency/offscreen-images.js +1 -1
  3. package/core/audits/byte-efficiency/render-blocking-resources.js +6 -6
  4. package/core/audits/dobetterweb/uses-http2.js +3 -3
  5. package/core/audits/prioritize-lcp-image.js +2 -2
  6. package/core/audits/redirects.js +1 -1
  7. package/core/audits/third-party-facades.js +1 -1
  8. package/core/audits/third-party-summary.js +1 -1
  9. package/core/audits/uses-rel-preconnect.js +2 -2
  10. package/core/audits/uses-rel-preload.js +9 -9
  11. package/core/computed/critical-request-chains.js +3 -3
  12. package/core/computed/metrics/lantern-metric.d.ts +18 -0
  13. package/core/computed/metrics/lantern-metric.js +34 -2
  14. package/core/computed/navigation-insights.d.ts +2 -0
  15. package/core/computed/page-dependency-graph.d.ts +3 -1
  16. package/core/computed/page-dependency-graph.js +11 -4
  17. package/core/computed/trace-engine-result.d.ts +1 -0
  18. package/core/computed/trace-engine-result.js +1 -0
  19. package/core/lib/lantern/metric.js +3 -3
  20. package/core/lib/lantern/metrics/first-contentful-paint.js +1 -1
  21. package/core/lib/lantern/metrics/interactive.js +4 -4
  22. package/core/lib/lantern/metrics/largest-contentful-paint.js +2 -2
  23. package/core/lib/lantern/network-node.d.ts +2 -2
  24. package/core/lib/lantern/network-node.js +3 -4
  25. package/core/lib/lantern/page-dependency-graph.d.ts +62 -6
  26. package/core/lib/lantern/page-dependency-graph.js +473 -30
  27. package/core/lib/lantern/simulator/connection-pool.d.ts +10 -10
  28. package/core/lib/lantern/simulator/connection-pool.js +22 -22
  29. package/core/lib/lantern/simulator/dns-cache.d.ts +1 -1
  30. package/core/lib/lantern/simulator/dns-cache.js +1 -1
  31. package/core/lib/lantern/simulator/network-analyzer.d.ts +12 -12
  32. package/core/lib/lantern/simulator/network-analyzer.js +53 -53
  33. package/core/lib/lantern/simulator/simulator.d.ts +5 -5
  34. package/core/lib/lantern/simulator/simulator.js +18 -18
  35. package/core/lib/lantern/types/lantern.d.ts +12 -8
  36. package/core/lib/lantern-trace-saver.js +1 -1
  37. package/core/lib/network-request.d.ts +21 -0
  38. package/core/lib/network-request.js +5 -2
  39. package/package.json +6 -4
  40. package/tsconfig.json +1 -0
  41. package/types/artifacts.d.ts +16 -0
@@ -120,7 +120,7 @@ class ByteEfficiencyAudit extends Audit {
120
120
  const originalTransferSizes = new Map();
121
121
  graph.traverse(node => {
122
122
  if (node.type !== 'network') return;
123
- const wastedBytes = wastedBytesByUrl.get(node.record.url);
123
+ const wastedBytes = wastedBytesByUrl.get(node.request.url);
124
124
  if (!wastedBytes) return;
125
125
 
126
126
  const original = node.request.transferSize;
@@ -128,7 +128,7 @@ class OffscreenImages extends ByteEfficiencyAudit {
128
128
  if (node.type === 'cpu' && timing.duration >= 50) {
129
129
  lastLongTaskStartTime = Math.max(lastLongTaskStartTime, timing.startTime);
130
130
  } else if (node.type === 'network') {
131
- startTimesByURL.set(node.record.url, timing.startTime);
131
+ startTimesByURL.set(node.request.url, timing.startTime);
132
132
  }
133
133
  }
134
134
 
@@ -53,7 +53,7 @@ function getNodesAndTimingByRequestId(nodeTimings) {
53
53
  for (const [node, nodeTiming] of nodeTimings) {
54
54
  if (node.type !== 'network') continue;
55
55
 
56
- requestIdToNode.set(node.record.requestId, {node, nodeTiming});
56
+ requestIdToNode.set(node.request.requestId, {node, nodeTiming});
57
57
  }
58
58
 
59
59
  return requestIdToNode;
@@ -94,7 +94,7 @@ function computeStackSpecificTiming(node, nodeTiming, Stacks) {
94
94
  // https://github.com/ampproject/amphtml/blob/8e03ac2f315774070651584a7e046ff24212c9b1/src/font-stylesheet-timeout.js#L54-L59
95
95
  // Any potential savings must only include time spent on AMP stylesheet nodes before 2.1 seconds.
96
96
  if (node.type === BaseNode.TYPES.NETWORK &&
97
- node.record.resourceType === NetworkRequest.TYPES.Stylesheet &&
97
+ node.request.resourceType === NetworkRequest.TYPES.Stylesheet &&
98
98
  nodeTiming.endTime > 2100) {
99
99
  stackSpecificTiming.endTime = Math.max(nodeTiming.startTime, 2100);
100
100
  stackSpecificTiming.duration = stackSpecificTiming.endTime - stackSpecificTiming.startTime;
@@ -228,11 +228,11 @@ class RenderBlockingResources extends Audit {
228
228
  if (node.type !== BaseNode.TYPES.NETWORK) return !canDeferRequest;
229
229
 
230
230
  const isStylesheet =
231
- node.record.resourceType === NetworkRequest.TYPES.Stylesheet;
231
+ node.request.resourceType === NetworkRequest.TYPES.Stylesheet;
232
232
  if (canDeferRequest && isStylesheet) {
233
233
  // We'll inline the used bytes of the stylesheet and assume the rest can be deferred
234
- const wastedBytes = wastedCssBytesByUrl.get(node.record.url) || 0;
235
- totalChildNetworkBytes += (node.record.transferSize || 0) - wastedBytes;
234
+ const wastedBytes = wastedCssBytesByUrl.get(node.request.url) || 0;
235
+ totalChildNetworkBytes += (node.request.transferSize || 0) - wastedBytes;
236
236
  }
237
237
  return !canDeferRequest;
238
238
  });
@@ -247,7 +247,7 @@ class RenderBlockingResources extends Audit {
247
247
  ));
248
248
 
249
249
  // Add the inlined bytes to the HTML response
250
- const originalTransferSize = minimalFCPGraph.record.transferSize;
250
+ const originalTransferSize = minimalFCPGraph.request.transferSize;
251
251
  const safeTransferSize = originalTransferSize || 0;
252
252
  minimalFCPGraph.request.transferSize = safeTransferSize + totalChildNetworkBytes;
253
253
  const estimateAfterInline = simulator.simulate(minimalFCPGraph).timeInMs;
@@ -87,9 +87,9 @@ class UsesHTTP2Audit extends Audit {
87
87
  const originalProtocols = new Map();
88
88
  graph.traverse(node => {
89
89
  if (node.type !== 'network') return;
90
- if (!urlsToChange.has(node.record.url)) return;
90
+ if (!urlsToChange.has(node.request.url)) return;
91
91
 
92
- originalProtocols.set(node.record.requestId, node.record.protocol);
92
+ originalProtocols.set(node.request.requestId, node.request.protocol);
93
93
  node.request.protocol = 'h2';
94
94
  });
95
95
 
@@ -98,7 +98,7 @@ class UsesHTTP2Audit extends Audit {
98
98
  // Restore the original protocol after we've done our simulation
99
99
  graph.traverse(node => {
100
100
  if (node.type !== 'network') return;
101
- const originalProtocol = originalProtocols.get(node.record.requestId);
101
+ const originalProtocol = originalProtocols.get(node.request.requestId);
102
102
  if (originalProtocol === undefined) return;
103
103
  node.request.protocol = originalProtocol;
104
104
  });
@@ -69,7 +69,7 @@ class PrioritizeLcpImage extends Audit {
69
69
  static findLCPNode(graph, lcpRecord) {
70
70
  for (const {node} of graph.traverseGenerator()) {
71
71
  if (node.type !== 'network') continue;
72
- if (node.record.requestId === lcpRecord.requestId) {
72
+ if (node.request.requestId === lcpRecord.requestId) {
73
73
  return node;
74
74
  }
75
75
  }
@@ -222,7 +222,7 @@ class PrioritizeLcpImage extends Audit {
222
222
  wastedMs,
223
223
  results: [{
224
224
  node: Audit.makeNodeItem(lcpElement.node),
225
- url: lcpNode.record.url,
225
+ url: lcpNode.request.url,
226
226
  wastedMs,
227
227
  }],
228
228
  };
@@ -98,7 +98,7 @@ class Redirects extends Audit {
98
98
  const nodeTimingsById = new Map();
99
99
  for (const [node, timing] of metricResult.pessimisticEstimate.nodeTimings.entries()) {
100
100
  if (node.type === 'network') {
101
- nodeTimingsById.set(node.record.requestId, timing);
101
+ nodeTimingsById.set(node.request.requestId, timing);
102
102
  }
103
103
  }
104
104
 
@@ -225,7 +225,7 @@ class ThirdPartyFacades extends Audit {
225
225
  itemCount: results.length,
226
226
  }),
227
227
  details: Audit.makeTableDetails(headings, results),
228
- metricSavings: {TBT: tbtImpact},
228
+ metricSavings: {TBT: Math.round(tbtImpact)},
229
229
  };
230
230
  }
231
231
  }
@@ -223,7 +223,7 @@ class ThirdPartySummary extends Audit {
223
223
  }),
224
224
  details,
225
225
  metricSavings: {
226
- TBT: overallSummary.tbtImpact,
226
+ TBT: Math.round(overallSummary.tbtImpact),
227
227
  },
228
228
  };
229
229
  }
@@ -146,14 +146,14 @@ class UsesRelPreconnectAudit extends Audit {
146
146
  /** @type {Set<string>} */
147
147
  const lcpGraphURLs = new Set();
148
148
  lcpGraph.traverse(node => {
149
- if (node.type === 'network') lcpGraphURLs.add(node.record.url);
149
+ if (node.type === 'network') lcpGraphURLs.add(node.request.url);
150
150
  });
151
151
 
152
152
  const fcpGraph =
153
153
  await LanternFirstContentfulPaint.getPessimisticGraph(pageGraph, processedNavigation);
154
154
  const fcpGraphURLs = new Set();
155
155
  fcpGraph.traverse(node => {
156
- if (node.type === 'network') fcpGraphURLs.add(node.record.url);
156
+ if (node.type === 'network') fcpGraphURLs.add(node.request.url);
157
157
  });
158
158
 
159
159
  /** @type {Map<string, LH.Artifacts.NetworkRequest[]>} */
@@ -61,8 +61,8 @@ class UsesRelPreloadAudit extends Audit {
61
61
  if (node.type !== 'network') return;
62
62
  // Don't include the node itself or any CPU nodes in the initiatorPath
63
63
  const path = traversalPath.slice(1).filter(initiator => initiator.type === 'network');
64
- if (!UsesRelPreloadAudit.shouldPreloadRequest(node.record, mainResource, path)) return;
65
- urls.add(node.record.url);
64
+ if (!UsesRelPreloadAudit.shouldPreloadRequest(node.rawRequest, mainResource, path)) return;
65
+ urls.add(node.rawRequest.url);
66
66
  });
67
67
 
68
68
  return urls;
@@ -77,7 +77,7 @@ class UsesRelPreloadAudit extends Audit {
77
77
  static getURLsFailedToPreload(graph) {
78
78
  /** @type {Array<LH.Artifacts.NetworkRequest>} */
79
79
  const requests = [];
80
- graph.traverse(node => node.type === 'network' && requests.push(node.record));
80
+ graph.traverse(node => node.type === 'network' && requests.push(node.rawRequest));
81
81
 
82
82
  const preloadRequests = requests.filter(req => req.isLinkPreload);
83
83
  const preloadURLsByFrame = new Map();
@@ -157,7 +157,7 @@ class UsesRelPreloadAudit extends Audit {
157
157
 
158
158
  if (node.isMainDocument()) {
159
159
  mainDocumentNode = node;
160
- } else if (node.record && urls.has(node.record.url)) {
160
+ } else if (node.rawRequest && urls.has(node.rawRequest.url)) {
161
161
  nodesToPreload.push(node);
162
162
  }
163
163
  });
@@ -176,20 +176,20 @@ class UsesRelPreloadAudit extends Audit {
176
176
 
177
177
  // Once we've modified the dependencies, simulate the new graph.
178
178
  const simulationAfterChanges = simulator.simulate(modifiedGraph);
179
- const originalNodesByRecord = Array.from(simulationBeforeChanges.nodeTimings.keys())
180
- // @ts-expect-error we don't care if all nodes without a record collect on `undefined`
181
- .reduce((map, node) => map.set(node.record, node), new Map());
179
+ const originalNodesByRequest = Array.from(simulationBeforeChanges.nodeTimings.keys())
180
+ // @ts-expect-error we don't care if all nodes without a request collect on `undefined`
181
+ .reduce((map, node) => map.set(node.request, node), new Map());
182
182
 
183
183
  const results = [];
184
184
  for (const node of nodesToPreload) {
185
- const originalNode = originalNodesByRecord.get(node.record);
185
+ const originalNode = originalNodesByRequest.get(node.request);
186
186
  const timingAfter = simulationAfterChanges.nodeTimings.get(node);
187
187
  const timingBefore = simulationBeforeChanges.nodeTimings.get(originalNode);
188
188
  if (!timingBefore || !timingAfter) throw new Error('Missing preload node');
189
189
 
190
190
  const wastedMs = Math.round(timingBefore.endTime - timingAfter.endTime);
191
191
  if (wastedMs < THRESHOLD_IN_MS) continue;
192
- results.push({url: node.record.url, wastedMs});
192
+ results.push({url: node.rawRequest.url, wastedMs});
193
193
  }
194
194
 
195
195
  if (!results.length) {
@@ -105,19 +105,19 @@ class CriticalRequestChains {
105
105
  graph.traverse((node, traversalPath) => {
106
106
  seenNodes.add(node);
107
107
  if (node.type !== 'network') return;
108
- if (!CriticalRequestChains.isCritical(node.record, mainResource)) return;
108
+ if (!CriticalRequestChains.isCritical(node.rawRequest, mainResource)) return;
109
109
 
110
110
  const networkPath = traversalPath
111
111
  .filter(/** @return {n is LH.Gatherer.Simulation.GraphNetworkNode} */
112
112
  n => n.type === 'network')
113
113
  .reverse()
114
- .map(node => node.record);
114
+ .map(node => node.rawRequest);
115
115
 
116
116
  // Ignore if some ancestor is not a critical request.
117
117
  if (networkPath.some(r => !CriticalRequestChains.isCritical(r, mainResource))) return;
118
118
 
119
119
  // Ignore non-network things (like data urls).
120
- if (NetworkRequest.isNonNetworkRequest(node.record)) return;
120
+ if (NetworkRequest.isNonNetworkRequest(node.rawRequest)) return;
121
121
 
122
122
  addChain(networkPath);
123
123
  }, getNextNodes);
@@ -1,3 +1,21 @@
1
+ /**
2
+ * @param {LH.Artifacts.MetricComputationDataInput} data
3
+ * @param {LH.Artifacts.ComputedContext} context
4
+ */
5
+ export function getComputationDataParamsFromTrace(data: LH.Artifacts.MetricComputationDataInput, context: LH.Artifacts.ComputedContext): Promise<{
6
+ simulator: import("../../lib/lantern/simulator/simulator.js").Simulator<any>;
7
+ graph: import("../page-dependency-graph.js").Node;
8
+ processedNavigation: import("../../index.js").Artifacts.ProcessedNavigation;
9
+ }>;
10
+ /**
11
+ * @param {LH.Artifacts.MetricComputationDataInput} data
12
+ * @param {LH.Artifacts.ComputedContext} context
13
+ */
14
+ export function getComputationDataParamsFromDevtoolsLog(data: LH.Artifacts.MetricComputationDataInput, context: LH.Artifacts.ComputedContext): Promise<{
15
+ simulator: import("../../lib/lantern/simulator/simulator.js").Simulator<any>;
16
+ graph: import("../page-dependency-graph.js").Node;
17
+ processedNavigation: import("../../index.js").Artifacts.ProcessedNavigation;
18
+ }>;
1
19
  /**
2
20
  * @param {LH.Artifacts.MetricComputationDataInput} data
3
21
  * @param {LH.Artifacts.ComputedContext} context
@@ -7,14 +7,14 @@
7
7
  import {LanternError} from '../../lib/lantern/lantern-error.js';
8
8
  import {LighthouseError} from '../../lib/lh-error.js';
9
9
  import {LoadSimulator} from '../load-simulator.js';
10
- import {PageDependencyGraph} from '../page-dependency-graph.js';
11
10
  import {ProcessedNavigation} from '../processed-navigation.js';
11
+ import {PageDependencyGraph} from '../page-dependency-graph.js';
12
12
 
13
13
  /**
14
14
  * @param {LH.Artifacts.MetricComputationDataInput} data
15
15
  * @param {LH.Artifacts.ComputedContext} context
16
16
  */
17
- async function getComputationDataParams(data, context) {
17
+ async function getComputationDataParamsFromDevtoolsLog(data, context) {
18
18
  if (data.gatherContext.gatherMode !== 'navigation') {
19
19
  throw new Error(`Lantern metrics can only be computed on navigations`);
20
20
  }
@@ -26,6 +26,22 @@ async function getComputationDataParams(data, context) {
26
26
  return {simulator, graph, processedNavigation};
27
27
  }
28
28
 
29
+ /**
30
+ * @param {LH.Artifacts.MetricComputationDataInput} data
31
+ * @param {LH.Artifacts.ComputedContext} context
32
+ */
33
+ async function getComputationDataParamsFromTrace(data, context) {
34
+ if (data.gatherContext.gatherMode !== 'navigation') {
35
+ throw new Error(`Lantern metrics can only be computed on navigations`);
36
+ }
37
+
38
+ const graph = await PageDependencyGraph.request({...data, fromTrace: true}, context);
39
+ const processedNavigation = await ProcessedNavigation.request(data.trace, context);
40
+ const simulator = data.simulator || (await LoadSimulator.request(data, context));
41
+
42
+ return {simulator, graph, processedNavigation};
43
+ }
44
+
29
45
  /**
30
46
  * @param {unknown} err
31
47
  * @return {never}
@@ -43,7 +59,23 @@ function lanternErrorAdapter(err) {
43
59
  throw err;
44
60
  }
45
61
 
62
+ /**
63
+ * @param {LH.Artifacts.MetricComputationDataInput} data
64
+ * @param {LH.Artifacts.ComputedContext} context
65
+ */
66
+ function getComputationDataParams(data, context) {
67
+ // TODO(15841): remove devtools impl when ready to make breaking change.
68
+ if (process.env.INTERNAL_LANTERN_USE_TRACE !== undefined) {
69
+ return getComputationDataParamsFromTrace(data, context);
70
+ } else {
71
+ // This is the default behavior.
72
+ return getComputationDataParamsFromDevtoolsLog(data, context);
73
+ }
74
+ }
75
+
46
76
  export {
77
+ getComputationDataParamsFromTrace,
78
+ getComputationDataParamsFromDevtoolsLog,
47
79
  getComputationDataParams,
48
80
  lanternErrorAdapter,
49
81
  };
@@ -11,6 +11,7 @@ declare const NavigationInsightsComputed: typeof NavigationInsights & {
11
11
  Samples: typeof import("@paulirish/trace_engine/models/trace/handlers/SamplesHandler.js");
12
12
  Screenshots: typeof import("@paulirish/trace_engine/models/trace/handlers/ScreenshotsHandler.js");
13
13
  PageLoadMetrics: typeof import("@paulirish/trace_engine/models/trace/handlers/PageLoadMetricsHandler.js");
14
+ Workers: typeof import("@paulirish/trace_engine/models/trace/handlers/WorkersHandler.js");
14
15
  }>>;
15
16
  };
16
17
  /**
@@ -31,6 +32,7 @@ declare class NavigationInsights {
31
32
  Samples: typeof import("@paulirish/trace_engine/models/trace/handlers/SamplesHandler.js");
32
33
  Screenshots: typeof import("@paulirish/trace_engine/models/trace/handlers/ScreenshotsHandler.js");
33
34
  PageLoadMetrics: typeof import("@paulirish/trace_engine/models/trace/handlers/PageLoadMetricsHandler.js");
35
+ Workers: typeof import("@paulirish/trace_engine/models/trace/handlers/WorkersHandler.js");
34
36
  }>>;
35
37
  }
36
38
  //# sourceMappingURL=navigation-insights.d.ts.map
@@ -5,6 +5,7 @@ declare const PageDependencyGraphComputed: typeof PageDependencyGraph & {
5
5
  trace: LH.Trace;
6
6
  devtoolsLog: import("../index.js").DevtoolsLog;
7
7
  URL: LH.Artifacts['URL'];
8
+ fromTrace?: boolean | undefined;
8
9
  }, context: import("../../types/utility-types.js").default.ImmutableObject<{
9
10
  computedCache: Map<string, import("../lib/arbitrary-equality-map.js").ArbitraryEqualityMap>;
10
11
  }>) => Promise<Node>;
@@ -13,7 +14,7 @@ import { NetworkRequest } from '../lib/network-request.js';
13
14
  /** @typedef {import('../lib/lantern/base-node.js').Node<LH.Artifacts.NetworkRequest>} Node */
14
15
  declare class PageDependencyGraph {
15
16
  /**
16
- * @param {{trace: LH.Trace, devtoolsLog: LH.DevtoolsLog, URL: LH.Artifacts['URL']}} data
17
+ * @param {{trace: LH.Trace, devtoolsLog: LH.DevtoolsLog, URL: LH.Artifacts['URL'], fromTrace?: boolean}} data
17
18
  * @param {LH.Artifacts.ComputedContext} context
18
19
  * @return {Promise<Node>}
19
20
  */
@@ -21,6 +22,7 @@ declare class PageDependencyGraph {
21
22
  trace: LH.Trace;
22
23
  devtoolsLog: import("../index.js").DevtoolsLog;
23
24
  URL: LH.Artifacts['URL'];
25
+ fromTrace?: boolean | undefined;
24
26
  }, context: LH.Artifacts.ComputedContext): Promise<Node>;
25
27
  }
26
28
  //# sourceMappingURL=page-dependency-graph.d.ts.map
@@ -9,28 +9,35 @@ import {PageDependencyGraph as LanternPageDependencyGraph} from '../lib/lantern/
9
9
  import {NetworkRequest} from '../lib/network-request.js';
10
10
  import {ProcessedTrace} from './processed-trace.js';
11
11
  import {NetworkRecords} from './network-records.js';
12
+ import {TraceEngineResult} from './trace-engine-result.js';
12
13
 
13
14
  /** @typedef {import('../lib/lantern/base-node.js').Node<LH.Artifacts.NetworkRequest>} Node */
14
15
 
15
16
  class PageDependencyGraph {
16
17
  /**
17
- * @param {{trace: LH.Trace, devtoolsLog: LH.DevtoolsLog, URL: LH.Artifacts['URL']}} data
18
+ * @param {{trace: LH.Trace, devtoolsLog: LH.DevtoolsLog, URL: LH.Artifacts['URL'], fromTrace?: boolean}} data
18
19
  * @param {LH.Artifacts.ComputedContext} context
19
20
  * @return {Promise<Node>}
20
21
  */
21
22
  static async compute_(data, context) {
22
23
  const {trace, devtoolsLog, URL} = data;
23
- const [processedTrace, networkRecords] = await Promise.all([
24
+ const [{mainThreadEvents}, networkRecords] = await Promise.all([
24
25
  ProcessedTrace.request(trace, context),
25
26
  NetworkRecords.request(devtoolsLog, context),
26
27
  ]);
27
28
 
28
- const mainThreadEvents = processedTrace.mainThreadEvents;
29
+ if (data.fromTrace) {
30
+ const traceEngineResult = await TraceEngineResult.request({trace}, context);
31
+ const {graph} = await LanternPageDependencyGraph.createGraphFromTrace(
32
+ mainThreadEvents, trace, traceEngineResult, URL);
33
+ return graph;
34
+ }
35
+
29
36
  const lanternRequests = networkRecords.map(NetworkRequest.asLanternNetworkRequest);
30
37
  return LanternPageDependencyGraph.createGraph(mainThreadEvents, lanternRequests, URL);
31
38
  }
32
39
  }
33
40
 
34
41
  const PageDependencyGraphComputed =
35
- makeComputedArtifact(PageDependencyGraph, ['devtoolsLog', 'trace', 'URL']);
42
+ makeComputedArtifact(PageDependencyGraph, ['devtoolsLog', 'trace', 'URL', 'fromTrace']);
36
43
  export {PageDependencyGraphComputed as PageDependencyGraph};
@@ -16,6 +16,7 @@ declare namespace ENABLED_HANDLERS {
16
16
  const Samples: typeof import("@paulirish/trace_engine/models/trace/handlers/SamplesHandler.js");
17
17
  const Screenshots: typeof import("@paulirish/trace_engine/models/trace/handlers/ScreenshotsHandler.js");
18
18
  const PageLoadMetrics: typeof import("@paulirish/trace_engine/models/trace/handlers/PageLoadMetricsHandler.js");
19
+ const Workers: typeof import("@paulirish/trace_engine/models/trace/handlers/WorkersHandler.js");
19
20
  }
20
21
  /**
21
22
  * @fileoverview Processes trace with the shared trace engine.
@@ -21,6 +21,7 @@ const ENABLED_HANDLERS = {
21
21
  Samples: TraceEngine.TraceHandlers.Samples,
22
22
  Screenshots: TraceEngine.TraceHandlers.Screenshots,
23
23
  PageLoadMetrics: TraceEngine.TraceHandlers.PageLoadMetrics,
24
+ Workers: TraceEngine.TraceHandlers.Workers,
24
25
  };
25
26
 
26
27
  /**
@@ -6,7 +6,7 @@
6
6
 
7
7
  import * as Lantern from './types/lantern.js';
8
8
  import {BaseNode} from '../../lib/lantern/base-node.js';
9
- import {NetworkRequest} from '../../lib/network-request.js';
9
+ import {RESOURCE_TYPES} from '../../lib/network-request.js';
10
10
 
11
11
  /** @typedef {import('./base-node.js').Node} Node */
12
12
  /** @typedef {import('./network-node.js').NetworkNode} NetworkNode */
@@ -33,9 +33,9 @@ class Metric {
33
33
 
34
34
  dependencyGraph.traverse(node => {
35
35
  if (node.type !== BaseNode.TYPES.NETWORK) return;
36
- if (node.record.resourceType !== NetworkRequest.TYPES.Script) return;
36
+ if (node.request.resourceType !== RESOURCE_TYPES.Script) return;
37
37
  if (treatNodeAsRenderBlocking?.(node)) {
38
- scriptUrls.add(node.record.url);
38
+ scriptUrls.add(node.request.url);
39
39
  }
40
40
  });
41
41
 
@@ -153,7 +153,7 @@ class FirstContentfulPaint extends Metric {
153
153
  const endedAfterPaint = node.endTime > cutoffTimestamp || node.startTime > cutoffTimestamp;
154
154
  if (endedAfterPaint && !node.isMainDocument()) return false;
155
155
 
156
- const url = node.record.url;
156
+ const url = node.request.url;
157
157
  // If the URL definitely wasn't render-blocking then we filter it out.
158
158
  if (definitelyNotRenderBlockingScriptUrls.has(url)) {
159
159
  return false;
@@ -41,13 +41,13 @@ class Interactive extends Metric {
41
41
  }
42
42
 
43
43
  // Include all scripts and high priority requests, exclude all images
44
- const isImage = node.record.resourceType === NetworkRequestTypes.Image;
45
- const isScript = node.record.resourceType === NetworkRequestTypes.Script;
44
+ const isImage = node.request.resourceType === NetworkRequestTypes.Image;
45
+ const isScript = node.request.resourceType === NetworkRequestTypes.Script;
46
46
  return (
47
47
  !isImage &&
48
48
  (isScript ||
49
- node.record.priority === 'High' ||
50
- node.record.priority === 'VeryHigh')
49
+ node.request.priority === 'High' ||
50
+ node.request.priority === 'VeryHigh')
51
51
  );
52
52
  });
53
53
  }
@@ -32,8 +32,8 @@ class LargestContentfulPaint extends Metric {
32
32
  */
33
33
  static isNotLowPriorityImageNode(node) {
34
34
  if (node.type !== 'network') return true;
35
- const isImage = node.record.resourceType === 'Image';
36
- const isLowPriority = node.record.priority === 'Low' || node.record.priority === 'VeryLow';
35
+ const isImage = node.request.resourceType === 'Image';
36
+ const isLowPriority = node.request.priority === 'Low' || node.request.priority === 'VeryLow';
37
37
  return !isImage || !isLowPriority;
38
38
  }
39
39
 
@@ -13,7 +13,7 @@ export class NetworkNode<T = any> extends BaseNode<T> {
13
13
  /**
14
14
  * @return {Readonly<T>}
15
15
  */
16
- get record(): Readonly<T>;
16
+ get rawRequest(): Readonly<T>;
17
17
  /**
18
18
  * @return {Lantern.NetworkRequest<T>}
19
19
  */
@@ -31,7 +31,7 @@ export class NetworkNode<T = any> extends BaseNode<T> {
31
31
  */
32
32
  get isNonNetworkProtocol(): boolean;
33
33
  /**
34
- * Returns whether this network record can be downloaded without a TCP connection.
34
+ * Returns whether this network request can be downloaded without a TCP connection.
35
35
  * During simulation we treat data coming in over a network connection separately from on-device data.
36
36
  * @return {boolean}
37
37
  */
@@ -18,7 +18,6 @@ const NON_NETWORK_SCHEMES = [
18
18
  ];
19
19
 
20
20
  /**
21
- * Use `NetworkRequest.isNonNetworkRequest(req)` if working with a request.
22
21
  * Note: the `protocol` field from CDP can be 'h2', 'http', (not 'https'!) or it'll be url's scheme.
23
22
  * https://source.chromium.org/chromium/chromium/src/+/main:content/browser/devtools/protocol/network_handler.cc;l=598-611;drc=56d4a9a9deb30be73adcee8737c73bcb2a5ab64f
24
23
  * However, a `new URL(href).protocol` has a colon suffix.
@@ -69,8 +68,8 @@ class NetworkNode extends BaseNode {
69
68
  /**
70
69
  * @return {Readonly<T>}
71
70
  */
72
- get record() {
73
- return /** @type {Required<T>} */ (this._request.record);
71
+ get rawRequest() {
72
+ return /** @type {Required<T>} */ (this._request.rawRequest);
74
73
  }
75
74
 
76
75
  /**
@@ -105,7 +104,7 @@ class NetworkNode extends BaseNode {
105
104
  }
106
105
 
107
106
  /**
108
- * Returns whether this network record can be downloaded without a TCP connection.
107
+ * Returns whether this network request can be downloaded without a TCP connection.
109
108
  * During simulation we treat data coming in over a network connection separately from on-device data.
110
109
  * @return {boolean}
111
110
  */
@@ -8,15 +8,15 @@ export type NetworkNodeOutput = {
8
8
  };
9
9
  export class PageDependencyGraph {
10
10
  /**
11
- * @param {Lantern.NetworkRequest} record
11
+ * @param {Lantern.NetworkRequest} request
12
12
  * @return {Array<string>}
13
13
  */
14
- static getNetworkInitiators(record: Lantern.NetworkRequest): Array<string>;
14
+ static getNetworkInitiators(request: Lantern.NetworkRequest): Array<string>;
15
15
  /**
16
- * @param {Array<Lantern.NetworkRequest>} networkRecords
16
+ * @param {Array<Lantern.NetworkRequest>} networkRequests
17
17
  * @return {NetworkNodeOutput}
18
18
  */
19
- static getNetworkNodeOutput(networkRecords: Array<Lantern.NetworkRequest>): NetworkNodeOutput;
19
+ static getNetworkNodeOutput(networkRequests: Array<Lantern.NetworkRequest>): NetworkNodeOutput;
20
20
  /**
21
21
  * @param {LH.TraceEvent[]} mainThreadEvents
22
22
  * @return {Array<CPUNode>}
@@ -39,13 +39,69 @@ export class PageDependencyGraph {
39
39
  * @param {Node} node
40
40
  */
41
41
  static _pruneNode(node: Node): void;
42
+ /**
43
+ * TODO(15841): remove when CDT backend is gone. until then, this is a useful debugging tool
44
+ * to find delta between using CDP or the trace to create the network requests.
45
+ *
46
+ * When a test fails using the trace backend, I enabled this debug method and copied the network
47
+ * requests when CDP was used, then when trace is used, and diff'd them. This method helped
48
+ * remove non-logical differences from the comparison (order of properties, slight rounding
49
+ * discrepancies, removing object cycles, etc).
50
+ *
51
+ * When using for a unit test, make sure to do `.only` so you are getting what you expect.
52
+ * @param {Lantern.NetworkRequest[]} lanternRequests
53
+ * @return {never}
54
+ */
55
+ static _debugNormalizeRequests(lanternRequests: Lantern.NetworkRequest[]): never;
42
56
  /**
43
57
  * @param {LH.TraceEvent[]} mainThreadEvents
44
- * @param {Array<Lantern.NetworkRequest>} networkRecords
58
+ * @param {Lantern.NetworkRequest[]} networkRequests
45
59
  * @param {URLArtifact} URL
46
60
  * @return {Node}
47
61
  */
48
- static createGraph(mainThreadEvents: LH.TraceEvent[], networkRecords: Array<Lantern.NetworkRequest>, URL: URLArtifact): Node;
62
+ static createGraph(mainThreadEvents: LH.TraceEvent[], networkRequests: Lantern.NetworkRequest[], URL: URLArtifact): Node;
63
+ /**
64
+ * @param {Lantern.NetworkRequest} request The request to find the initiator of
65
+ * @param {Map<string, Lantern.NetworkRequest[]>} requestsByURL
66
+ * @return {Lantern.NetworkRequest|null}
67
+ */
68
+ static chooseInitiatorRequest(request: Lantern.NetworkRequest, requestsByURL: Map<string, Lantern.NetworkRequest[]>): Lantern.NetworkRequest | null;
69
+ /**
70
+ * Returns a map of `pid` -> `tid[]`.
71
+ * @param {LH.Trace} trace
72
+ * @return {Map<number, number[]>}
73
+ */
74
+ static _findWorkerThreads(trace: LH.Trace): Map<number, number[]>;
75
+ /**
76
+ * @param {URL|string} url
77
+ */
78
+ static _createParsedUrl(url: URL | string): {
79
+ scheme: string;
80
+ host: string;
81
+ securityOrigin: string;
82
+ };
83
+ /**
84
+ * @param {LH.Artifacts.TraceEngineResult} traceEngineResult
85
+ * @param {Map<number, number[]>} workerThreads
86
+ * @param {import('@paulirish/trace_engine/models/trace/types/TraceEvents.js').SyntheticNetworkRequest} request
87
+ * @return {Lantern.NetworkRequest=}
88
+ */
89
+ static _createLanternRequest(traceEngineResult: LH.Artifacts.TraceEngineResult, workerThreads: Map<number, number[]>, request: import('@paulirish/trace_engine/models/trace/types/TraceEvents.js').SyntheticNetworkRequest): Lantern.NetworkRequest | undefined;
90
+ /**
91
+ *
92
+ * @param {Lantern.NetworkRequest[]} lanternRequests
93
+ */
94
+ static _linkInitiators(lanternRequests: Lantern.NetworkRequest[]): void;
95
+ /**
96
+ * @param {LH.TraceEvent[]} mainThreadEvents
97
+ * @param {LH.Trace} trace
98
+ * @param {LH.Artifacts.TraceEngineResult} traceEngineResult
99
+ * @param {LH.Artifacts.URL} URL
100
+ */
101
+ static createGraphFromTrace(mainThreadEvents: LH.TraceEvent[], trace: LH.Trace, traceEngineResult: LH.Artifacts.TraceEngineResult, URL: LH.Artifacts.URL): Promise<{
102
+ graph: Node;
103
+ records: Lantern.NetworkRequest<any>[];
104
+ }>;
49
105
  /**
50
106
  *
51
107
  * @param {Node} rootNode