@paulirish/trace_engine 0.0.55 → 0.0.57

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 (268) hide show
  1. package/.tmp/tsbuildinfo/tsconfig.tsbuildinfo +1 -1
  2. package/README.md +2 -2
  3. package/core/platform/devtools_entrypoint-bundle-tsconfig-tsconfig.json +43 -0
  4. package/core/platform/platform.prebundle.d.ts +18 -0
  5. package/core/platform/platform.prebundle.js +53 -0
  6. package/core/platform/platform.prebundle.js.map +1 -0
  7. package/core/platform/platform.prebundle.ts +71 -0
  8. package/generated/protocol.d.ts +51 -23
  9. package/locales/af.json +8 -8
  10. package/locales/am.json +8 -8
  11. package/locales/ar.json +8 -8
  12. package/locales/as.json +8 -8
  13. package/locales/az.json +8 -8
  14. package/locales/be.json +7 -7
  15. package/locales/bg.json +8 -8
  16. package/locales/bn.json +8 -8
  17. package/locales/bs.json +8 -8
  18. package/locales/ca.json +8 -8
  19. package/locales/cs.json +8 -8
  20. package/locales/cy.json +8 -8
  21. package/locales/da.json +8 -8
  22. package/locales/de.json +8 -8
  23. package/locales/el.json +8 -8
  24. package/locales/en-GB.json +8 -8
  25. package/locales/en-US.json +72 -51
  26. package/locales/en-XL.json +72 -51
  27. package/locales/es-419.json +8 -8
  28. package/locales/es.json +8 -8
  29. package/locales/et.json +8 -8
  30. package/locales/eu.json +8 -8
  31. package/locales/fa.json +11 -11
  32. package/locales/fi.json +8 -8
  33. package/locales/fil.json +8 -8
  34. package/locales/fr-CA.json +8 -8
  35. package/locales/fr.json +8 -8
  36. package/locales/gl.json +8 -8
  37. package/locales/gu.json +8 -8
  38. package/locales/he.json +8 -8
  39. package/locales/hi.json +8 -8
  40. package/locales/hr.json +8 -8
  41. package/locales/hu.json +8 -8
  42. package/locales/hy.json +8 -8
  43. package/locales/id.json +8 -8
  44. package/locales/is.json +8 -8
  45. package/locales/it.json +8 -8
  46. package/locales/ja.json +8 -8
  47. package/locales/ka.json +8 -8
  48. package/locales/kk.json +8 -8
  49. package/locales/km.json +8 -8
  50. package/locales/kn.json +7 -7
  51. package/locales/ko.json +8 -8
  52. package/locales/ky.json +7 -7
  53. package/locales/lo.json +8 -8
  54. package/locales/lt.json +8 -8
  55. package/locales/lv.json +8 -8
  56. package/locales/mk.json +8 -8
  57. package/locales/ml.json +8 -8
  58. package/locales/mn.json +8 -8
  59. package/locales/mr.json +7 -7
  60. package/locales/ms.json +7 -7
  61. package/locales/my.json +8 -8
  62. package/locales/ne.json +8 -8
  63. package/locales/nl.json +8 -8
  64. package/locales/no.json +8 -8
  65. package/locales/or.json +8 -8
  66. package/locales/pa.json +7 -7
  67. package/locales/pl.json +8 -8
  68. package/locales/pt-PT.json +8 -8
  69. package/locales/pt.json +8 -8
  70. package/locales/ro.json +8 -8
  71. package/locales/ru.json +8 -8
  72. package/locales/si.json +8 -8
  73. package/locales/sk.json +8 -8
  74. package/locales/sl.json +8 -8
  75. package/locales/sq.json +8 -8
  76. package/locales/sr-Latn.json +8 -8
  77. package/locales/sr.json +8 -8
  78. package/locales/sv.json +8 -8
  79. package/locales/sw.json +7 -7
  80. package/locales/ta.json +8 -8
  81. package/locales/te.json +8 -8
  82. package/locales/th.json +8 -8
  83. package/locales/tr.json +7 -7
  84. package/locales/uk.json +7 -7
  85. package/locales/ur.json +8 -8
  86. package/locales/uz.json +7 -7
  87. package/locales/vi.json +8 -8
  88. package/locales/zh-HK.json +8 -8
  89. package/locales/zh-TW.json +8 -8
  90. package/locales/zh.json +8 -8
  91. package/locales/zu.json +8 -8
  92. package/models/cpu_profile/cpu_profile.prebundle.d.ts +3 -0
  93. package/models/cpu_profile/cpu_profile.prebundle.js +7 -0
  94. package/models/cpu_profile/cpu_profile.prebundle.js.map +1 -0
  95. package/models/cpu_profile/cpu_profile.prebundle.ts +11 -0
  96. package/models/cpu_profile/devtools_entrypoint-bundle-tsconfig-tsconfig.json +43 -0
  97. package/models/trace/ModelImpl.d.ts +1 -0
  98. package/models/trace/ModelImpl.js +2 -4
  99. package/models/trace/ModelImpl.js.map +1 -1
  100. package/models/trace/Processor.js +20 -14
  101. package/models/trace/Processor.js.map +1 -1
  102. package/models/trace/devtools_entrypoint-bundle-tsconfig-tsconfig.json +61 -0
  103. package/models/trace/extras/TraceTree.d.ts +0 -1
  104. package/models/trace/extras/TraceTree.js +0 -3
  105. package/models/trace/extras/TraceTree.js.map +1 -1
  106. package/models/trace/extras/devtools_entrypoint-bundle-tsconfig-tsconfig.json +43 -0
  107. package/models/trace/extras/extras.prebundle.d.ts +7 -0
  108. package/models/trace/extras/extras.prebundle.js +11 -0
  109. package/models/trace/extras/extras.prebundle.js.map +1 -0
  110. package/models/trace/extras/extras.prebundle.ts +11 -0
  111. package/models/trace/handlers/ExtensionTraceDataHandler.js +28 -14
  112. package/models/trace/handlers/ExtensionTraceDataHandler.js.map +1 -1
  113. package/models/trace/handlers/ImagePaintingHandler.d.ts +7 -1
  114. package/models/trace/handlers/ImagePaintingHandler.js +33 -1
  115. package/models/trace/handlers/ImagePaintingHandler.js.map +1 -1
  116. package/models/trace/handlers/NetworkRequestsHandler.js +70 -3
  117. package/models/trace/handlers/NetworkRequestsHandler.js.map +1 -1
  118. package/models/trace/handlers/SamplesHandler.js +2 -6
  119. package/models/trace/handlers/SamplesHandler.js.map +1 -1
  120. package/models/trace/handlers/SelectorStatsHandler.d.ts +17 -0
  121. package/models/trace/handlers/SelectorStatsHandler.js +42 -0
  122. package/models/trace/handlers/SelectorStatsHandler.js.map +1 -1
  123. package/models/trace/handlers/devtools_entrypoint-bundle-tsconfig-tsconfig.json +43 -0
  124. package/models/trace/handlers/handlers.prebundle.d.ts +4 -0
  125. package/models/trace/handlers/handlers.prebundle.js +8 -0
  126. package/models/trace/handlers/handlers.prebundle.js.map +1 -0
  127. package/models/trace/handlers/handlers.prebundle.ts +8 -0
  128. package/models/trace/helpers/SamplesIntegrator.js +14 -22
  129. package/models/trace/helpers/SamplesIntegrator.js.map +1 -1
  130. package/models/trace/helpers/SyntheticEvents.d.ts +0 -6
  131. package/models/trace/helpers/SyntheticEvents.js +2 -2
  132. package/models/trace/helpers/SyntheticEvents.js.map +1 -1
  133. package/models/trace/helpers/Timing.d.ts +5 -0
  134. package/models/trace/helpers/Timing.js +53 -3
  135. package/models/trace/helpers/Timing.js.map +1 -1
  136. package/models/trace/helpers/devtools_entrypoint-bundle-tsconfig-tsconfig.json +43 -0
  137. package/models/trace/helpers/helpers.prebundle.d.ts +7 -0
  138. package/models/trace/helpers/helpers.prebundle.js +11 -0
  139. package/models/trace/helpers/helpers.prebundle.js.map +1 -0
  140. package/models/trace/helpers/helpers.prebundle.ts +11 -0
  141. package/models/trace/insights/CLSCulprits.d.ts +5 -4
  142. package/models/trace/insights/CLSCulprits.js +29 -7
  143. package/models/trace/insights/CLSCulprits.js.map +1 -1
  144. package/models/trace/insights/Cache.d.ts +2 -0
  145. package/models/trace/insights/Cache.js +10 -0
  146. package/models/trace/insights/Cache.js.map +1 -1
  147. package/models/trace/insights/Common.d.ts +1 -1
  148. package/models/trace/insights/Common.js +3 -3
  149. package/models/trace/insights/Common.js.map +1 -1
  150. package/models/trace/insights/DOMSize.d.ts +27 -1
  151. package/models/trace/insights/DOMSize.js +42 -1
  152. package/models/trace/insights/DOMSize.js.map +1 -1
  153. package/models/trace/insights/DocumentLatency.d.ts +1 -0
  154. package/models/trace/insights/DocumentLatency.js +43 -1
  155. package/models/trace/insights/DocumentLatency.js.map +1 -1
  156. package/models/trace/insights/DuplicatedJavaScript.d.ts +2 -0
  157. package/models/trace/insights/DuplicatedJavaScript.js +9 -0
  158. package/models/trace/insights/DuplicatedJavaScript.js.map +1 -1
  159. package/models/trace/insights/FontDisplay.d.ts +1 -0
  160. package/models/trace/insights/FontDisplay.js +7 -0
  161. package/models/trace/insights/FontDisplay.js.map +1 -1
  162. package/models/trace/insights/ForcedReflow.d.ts +3 -1
  163. package/models/trace/insights/ForcedReflow.js +18 -1
  164. package/models/trace/insights/ForcedReflow.js.map +1 -1
  165. package/models/trace/insights/{InteractionToNextPaint.d.ts → INPBreakdown.d.ts} +14 -8
  166. package/models/trace/insights/{InteractionToNextPaint.js → INPBreakdown.js} +41 -10
  167. package/models/trace/insights/INPBreakdown.js.map +1 -0
  168. package/models/trace/insights/ImageDelivery.d.ts +2 -0
  169. package/models/trace/insights/ImageDelivery.js +28 -7
  170. package/models/trace/insights/ImageDelivery.js.map +1 -1
  171. package/models/trace/insights/{LCPPhases.d.ts → LCPBreakdown.d.ts} +27 -22
  172. package/models/trace/insights/{LCPPhases.js → LCPBreakdown.js} +77 -48
  173. package/models/trace/insights/LCPBreakdown.js.map +1 -0
  174. package/models/trace/insights/LCPDiscovery.d.ts +12 -0
  175. package/models/trace/insights/LCPDiscovery.js +59 -1
  176. package/models/trace/insights/LCPDiscovery.js.map +1 -1
  177. package/models/trace/insights/LegacyJavaScript.d.ts +2 -0
  178. package/models/trace/insights/LegacyJavaScript.js +9 -0
  179. package/models/trace/insights/LegacyJavaScript.js.map +1 -1
  180. package/models/trace/insights/Models.d.ts +2 -2
  181. package/models/trace/insights/Models.js +2 -2
  182. package/models/trace/insights/Models.js.map +1 -1
  183. package/models/trace/insights/ModernHTTP.d.ts +8 -5
  184. package/models/trace/insights/ModernHTTP.js +26 -13
  185. package/models/trace/insights/ModernHTTP.js.map +1 -1
  186. package/models/trace/insights/NetworkDependencyTree.d.ts +5 -4
  187. package/models/trace/insights/NetworkDependencyTree.js +36 -11
  188. package/models/trace/insights/NetworkDependencyTree.js.map +1 -1
  189. package/models/trace/insights/RenderBlocking.d.ts +2 -0
  190. package/models/trace/insights/RenderBlocking.js +10 -0
  191. package/models/trace/insights/RenderBlocking.js.map +1 -1
  192. package/models/trace/insights/SlowCSSSelector.d.ts +11 -2
  193. package/models/trace/insights/SlowCSSSelector.js +33 -14
  194. package/models/trace/insights/SlowCSSSelector.js.map +1 -1
  195. package/models/trace/insights/ThirdParties.d.ts +3 -0
  196. package/models/trace/insights/ThirdParties.js +31 -0
  197. package/models/trace/insights/ThirdParties.js.map +1 -1
  198. package/models/trace/insights/Viewport.d.ts +2 -1
  199. package/models/trace/insights/Viewport.js +16 -0
  200. package/models/trace/insights/Viewport.js.map +1 -1
  201. package/models/trace/insights/devtools_entrypoint-bundle-tsconfig-tsconfig.json +43 -0
  202. package/models/trace/insights/insights-tsconfig.json +2 -2
  203. package/models/trace/insights/insights.prebundle.d.ts +4 -0
  204. package/models/trace/insights/insights.prebundle.js +8 -0
  205. package/models/trace/insights/insights.prebundle.js.map +1 -0
  206. package/models/trace/insights/insights.prebundle.ts +8 -0
  207. package/models/trace/insights/types.d.ts +6 -3
  208. package/models/trace/insights/types.js +3 -2
  209. package/models/trace/insights/types.js.map +1 -1
  210. package/models/trace/lantern/core/core.prebundle.d.ts +2 -0
  211. package/models/trace/lantern/core/core.prebundle.js +6 -0
  212. package/models/trace/lantern/core/core.prebundle.js.map +1 -0
  213. package/models/trace/lantern/core/core.prebundle.ts +6 -0
  214. package/models/trace/lantern/core/devtools_entrypoint-bundle-tsconfig-tsconfig.json +43 -0
  215. package/models/trace/lantern/devtools_entrypoint-bundle-tsconfig-tsconfig.json +43 -0
  216. package/models/trace/lantern/graph/devtools_entrypoint-bundle-tsconfig-tsconfig.json +43 -0
  217. package/models/trace/lantern/graph/graph.prebundle.d.ts +4 -0
  218. package/models/trace/lantern/graph/graph.prebundle.js +8 -0
  219. package/models/trace/lantern/graph/graph.prebundle.js.map +1 -0
  220. package/models/trace/lantern/graph/graph.prebundle.ts +8 -0
  221. package/models/trace/lantern/lantern.prebundle.d.ts +6 -0
  222. package/models/trace/lantern/lantern.prebundle.js +10 -0
  223. package/models/trace/lantern/lantern.prebundle.js.map +1 -0
  224. package/models/trace/lantern/lantern.prebundle.ts +17 -0
  225. package/models/trace/lantern/metrics/devtools_entrypoint-bundle-tsconfig-tsconfig.json +43 -0
  226. package/models/trace/lantern/metrics/metrics.prebundle.d.ts +8 -0
  227. package/models/trace/lantern/metrics/metrics.prebundle.js +12 -0
  228. package/models/trace/lantern/metrics/metrics.prebundle.js.map +1 -0
  229. package/models/trace/lantern/metrics/metrics.prebundle.ts +12 -0
  230. package/models/trace/lantern/simulation/devtools_entrypoint-bundle-tsconfig-tsconfig.json +43 -0
  231. package/models/trace/lantern/simulation/simulation.prebundle.d.ts +6 -0
  232. package/models/trace/lantern/simulation/simulation.prebundle.js +10 -0
  233. package/models/trace/lantern/simulation/simulation.prebundle.js.map +1 -0
  234. package/models/trace/lantern/simulation/simulation.prebundle.ts +10 -0
  235. package/models/trace/lantern/types/devtools_entrypoint-bundle-tsconfig-tsconfig.json +43 -0
  236. package/models/trace/lantern/types/types.prebundle.d.ts +1 -0
  237. package/models/trace/lantern/types/types.prebundle.js +5 -0
  238. package/models/trace/lantern/types/types.prebundle.js.map +1 -0
  239. package/models/trace/lantern/types/types.prebundle.ts +5 -0
  240. package/models/trace/trace.prebundle.d.ts +10 -0
  241. package/models/trace/trace.prebundle.js +14 -0
  242. package/models/trace/trace.prebundle.js.map +1 -0
  243. package/models/trace/trace.prebundle.ts +25 -0
  244. package/models/trace/types/Extensions.d.ts +13 -1
  245. package/models/trace/types/Extensions.js +5 -1
  246. package/models/trace/types/Extensions.js.map +1 -1
  247. package/models/trace/types/File.d.ts +1 -0
  248. package/models/trace/types/File.js.map +1 -1
  249. package/models/trace/types/Overlays.d.ts +110 -0
  250. package/models/trace/types/Overlays.js +5 -0
  251. package/models/trace/types/Overlays.js.map +1 -0
  252. package/models/trace/types/Timing.js.map +1 -1
  253. package/models/trace/types/TraceEvents.d.ts +27 -9
  254. package/models/trace/types/TraceEvents.js +7 -18
  255. package/models/trace/types/TraceEvents.js.map +1 -1
  256. package/models/trace/types/devtools_entrypoint-bundle-tsconfig-tsconfig.json +43 -0
  257. package/models/trace/types/types-tsconfig.json +1 -0
  258. package/models/trace/types/types.d.ts +1 -0
  259. package/models/trace/types/types.js +1 -0
  260. package/models/trace/types/types.js.map +1 -1
  261. package/models/trace/types/types.prebundle.d.ts +5 -0
  262. package/models/trace/types/types.prebundle.js +9 -0
  263. package/models/trace/types/types.prebundle.js.map +1 -0
  264. package/models/trace/types/types.prebundle.ts +9 -0
  265. package/package.json +1 -1
  266. package/test/test-trace-engine.mjs +3 -3
  267. package/models/trace/insights/InteractionToNextPaint.js.map +0 -1
  268. package/models/trace/insights/LCPPhases.js.map +0 -1
@@ -26,10 +26,13 @@ export const UIStrings = {
26
26
  /**
27
27
  * @description Text explaining that there were not requests that were slowed down by using HTTP/1.1. "HTTP/1.1" should not be translated.
28
28
  */
29
- noOldProtocolRequests: 'No requests used HTTP/1.1'
29
+ noOldProtocolRequests: 'No requests used HTTP/1.1, or its current use of HTTP/1.1 does not present a significant optimization opportunity. HTTP/1.1 requests are only flagged if six or more static assets originate from the same origin, and they are not served from a local development environment or a third-party source.'
30
30
  };
31
31
  // const str_ = i18n.i18n.registerUIStrings('models/trace/insights/ModernHTTP.ts', UIStrings);
32
32
  export const i18nString = (i18nId, values) => ({i18nId, values}); // i18n.i18n.getLocalizedString.bind(undefined, str_);
33
+ export function isModernHTTP(model) {
34
+ return model.insightKey === InsightKeys.MODERN_HTTP;
35
+ }
33
36
  /**
34
37
  * Determines whether a network request is a "static resource" that would benefit from H2 multiplexing.
35
38
  * XHRs, tracking pixels, etc generally don't benefit as much because they aren't requested en-masse
@@ -75,8 +78,8 @@ function isMultiplexableStaticAsset(request, entityMappings, firstPartyEntity) {
75
78
  * [2] https://www.twilio.com/blog/2017/10/http2-issues.html
76
79
  * [3] https://www.cachefly.com/http-2-is-not-a-magic-bullet/
77
80
  */
78
- export function determineNonHttp2Resources(requests, entityMappings, firstPartyEntity) {
79
- const nonHttp2Resources = [];
81
+ export function determineHttp1Requests(requests, entityMappings, firstPartyEntity) {
82
+ const http1Requests = [];
80
83
  const groupedByOrigin = new Map();
81
84
  for (const record of requests) {
82
85
  const url = new URL(record.args.data.url);
@@ -112,9 +115,9 @@ export function determineNonHttp2Resources(requests, entityMappings, firstPartyE
112
115
  continue;
113
116
  }
114
117
  seenURLs.add(request.args.data.url);
115
- nonHttp2Resources.push(request);
118
+ http1Requests.push(request);
116
119
  }
117
- return nonHttp2Resources;
120
+ return http1Requests;
118
121
  }
119
122
  /**
120
123
  * Computes the estimated effect of all results being converted to http/2 on the provided graph.
@@ -148,11 +151,11 @@ function computeWasteWithGraph(urlsToChange, graph, simulator) {
148
151
  const savings = simulationBefore.timeInMs - simulationAfter.timeInMs;
149
152
  return Platform.NumberUtilities.floor(savings, 1 / 10);
150
153
  }
151
- function computeMetricSavings(nonHttp2Requests, context) {
154
+ function computeMetricSavings(http1Requests, context) {
152
155
  if (!context.navigation || !context.lantern) {
153
156
  return;
154
157
  }
155
- const urlsToChange = new Set(nonHttp2Requests.map(r => r.args.data.url));
158
+ const urlsToChange = new Set(http1Requests.map(r => r.args.data.url));
156
159
  const fcpGraph = context.lantern.metrics.firstContentfulPaint.optimisticGraph;
157
160
  const lcpGraph = context.lantern.metrics.largestContentfulPaint.optimisticGraph;
158
161
  return {
@@ -162,14 +165,14 @@ function computeMetricSavings(nonHttp2Requests, context) {
162
165
  }
163
166
  function finalize(partialModel) {
164
167
  return {
165
- insightKey: InsightKeys.IMAGE_DELIVERY,
168
+ insightKey: InsightKeys.MODERN_HTTP,
166
169
  strings: UIStrings,
167
170
  title: i18nString(UIStrings.title),
168
171
  description: i18nString(UIStrings.description),
169
172
  category: InsightCategory.LCP,
170
- state: partialModel.requests.length > 0 ? 'fail' : 'pass',
173
+ state: partialModel.http1Requests.length > 0 ? 'fail' : 'pass',
171
174
  ...partialModel,
172
- relatedEvents: partialModel.requests,
175
+ relatedEvents: partialModel.http1Requests,
173
176
  };
174
177
  }
175
178
  export function generateInsight(parsedTrace, context) {
@@ -178,10 +181,20 @@ export function generateInsight(parsedTrace, context) {
178
181
  const entityMappings = parsedTrace.NetworkRequests.entityMappings;
179
182
  const firstPartyUrl = context.navigation?.args.data?.documentLoaderURL ?? parsedTrace.Meta.mainFrameURL;
180
183
  const firstPartyEntity = Handlers.Helpers.getEntityForUrl(firstPartyUrl, entityMappings.createdEntityCache);
181
- const nonHttp2Requests = determineNonHttp2Resources(contextRequests, entityMappings, firstPartyEntity ?? null);
184
+ const http1Requests = determineHttp1Requests(contextRequests, entityMappings, firstPartyEntity ?? null);
182
185
  return finalize({
183
- requests: nonHttp2Requests,
184
- metricSavings: computeMetricSavings(nonHttp2Requests, context),
186
+ http1Requests,
187
+ metricSavings: computeMetricSavings(http1Requests, context),
185
188
  });
186
189
  }
190
+ export function createOverlayForRequest(request) {
191
+ return {
192
+ type: 'ENTRY_OUTLINE',
193
+ entry: request,
194
+ outlineReason: 'ERROR',
195
+ };
196
+ }
197
+ export function createOverlays(model) {
198
+ return model.http1Requests.map(req => createOverlayForRequest(req)) ?? [];
199
+ }
187
200
  //# sourceMappingURL=ModernHTTP.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ModernHTTP.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/ModernHTTP.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2025 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as i18n from '../../../core/i18n/i18n.js';\nimport * as Platform from '../../../core/platform/platform.js';\nimport * as Handlers from '../handlers/handlers.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport type * as Lantern from '../lantern/lantern.js';\nimport type * as Types from '../types/types.js';\n\nimport {\n InsightCategory,\n InsightKeys,\n type InsightModel,\n type InsightSetContext,\n type MetricSavings,\n type PartialInsightModel,\n} from './types.js';\n\nexport const UIStrings = {\n /**\n * @description Title of an insight that recommends using HTTP/2 over HTTP/1.1 because of the performance benefits. \"HTTP\" should not be translated.\n */\n title: 'Modern HTTP',\n /**\n * @description Description of an insight that recommends recommends using HTTP/2 over HTTP/1.1 because of the performance benefits. \"HTTP\" should not be translated.\n */\n description:\n 'HTTP/2 and HTTP/3 offer many benefits over HTTP/1.1, such as multiplexing. [Learn more about using modern HTTP](https://developer.chrome.com/docs/lighthouse/best-practices/uses-http2/).',\n /**\n * @description Column header for a table where each cell represents a network request.\n */\n request: 'Request',\n /**\n * @description Column header for a table where each cell represents the protocol of a network request.\n */\n protocol: 'Protocol',\n /**\n * @description Text explaining that there were not requests that were slowed down by using HTTP/1.1. \"HTTP/1.1\" should not be translated.\n */\n noOldProtocolRequests: 'No requests used HTTP/1.1'\n} as const;\n\nconst str_ = i18n.i18n.registerUIStrings('models/trace/insights/ModernHTTP.ts', UIStrings);\nexport const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);\n\nexport type UseModernHTTPInsightModel = InsightModel<typeof UIStrings, {\n requests: Types.Events.SyntheticNetworkRequest[],\n}>;\n\n/**\n * Determines whether a network request is a \"static resource\" that would benefit from H2 multiplexing.\n * XHRs, tracking pixels, etc generally don't benefit as much because they aren't requested en-masse\n * for the same origin at the exact same time.\n */\nfunction isMultiplexableStaticAsset(\n request: Types.Events.SyntheticNetworkRequest, entityMappings: Handlers.Helpers.EntityMappings,\n firstPartyEntity: Handlers.Helpers.Entity|null): boolean {\n if (!Helpers.Network.STATIC_RESOURCE_TYPES.has(request.args.data.resourceType)) {\n return false;\n }\n\n // Resources from third-parties that are less than 100 bytes are usually tracking pixels, not actual resources.\n // They can masquerade as static types though (gifs, documents, etc)\n if (request.args.data.decodedBodyLength < 100) {\n const entity = entityMappings.entityByEvent.get(request);\n if (entity) {\n // Third-party assets are multiplexable in their first-party context.\n if (firstPartyEntity?.name === entity.name) {\n return true;\n }\n // Skip recognizable third-parties' requests.\n if (!entity.isUnrecognized) {\n return false;\n }\n }\n }\n\n return true;\n}\n\n/**\n * Determine the set of resources that aren't HTTP/2 but should be.\n * We're a little conservative about what we surface for a few reasons:\n *\n * - The simulator approximation of HTTP/2 is a little more generous than reality.\n * - There's a bit of debate surrounding HTTP/2 due to its worse performance in environments with high packet loss. [1][2][3]\n * - It's something that you'd have absolutely zero control over with a third-party (can't defer to fix it for example).\n *\n * Therefore, we only surface requests that were...\n *\n * - Served over HTTP/1.1 or earlier\n * - Served over an origin that serves at least 6 static asset requests\n * (if there aren't more requests than browser's max/host, multiplexing isn't as big a deal)\n * - Not served on localhost (h2 is a pain to deal with locally & and CI)\n *\n * [1] https://news.ycombinator.com/item?id=19086639\n * [2] https://www.twilio.com/blog/2017/10/http2-issues.html\n * [3] https://www.cachefly.com/http-2-is-not-a-magic-bullet/\n */\nexport function determineNonHttp2Resources(\n requests: Types.Events.SyntheticNetworkRequest[], entityMappings: Handlers.Helpers.EntityMappings,\n firstPartyEntity: Handlers.Helpers.Entity|null): Types.Events.SyntheticNetworkRequest[] {\n const nonHttp2Resources: Types.Events.SyntheticNetworkRequest[] = [];\n\n const groupedByOrigin = new Map<string, Types.Events.SyntheticNetworkRequest[]>();\n for (const record of requests) {\n const url = new URL(record.args.data.url);\n if (!isMultiplexableStaticAsset(record, entityMappings, firstPartyEntity)) {\n continue;\n }\n if (Helpers.Network.isSyntheticNetworkRequestLocalhost(record)) {\n continue;\n }\n const originRequests = Platform.MapUtilities.getWithDefault(groupedByOrigin, url.origin, () => []);\n originRequests.push(record);\n }\n\n const seenURLs = new Set<string>();\n\n for (const request of requests) {\n // Skip duplicates.\n if (seenURLs.has(request.args.data.url)) {\n continue;\n }\n\n // Check if record is not served through the service worker, servicer worker uses http/1.1 as a protocol.\n // These can generate false positives (bug: https://github.com/GoogleChrome/lighthouse/issues/7158).\n if (request.args.data.fromServiceWorker) {\n continue;\n }\n\n // Test the protocol to see if it was http/1.1.\n const isOldHttp = /HTTP\\/[01][.\\d]?/i.test(request.args.data.protocol);\n if (!isOldHttp) {\n continue;\n }\n\n const url = new URL(request.args.data.url);\n\n // Check if the origin has enough requests to bother flagging.\n const group = groupedByOrigin.get(url.origin) || [];\n if (group.length < 6) {\n continue;\n }\n\n seenURLs.add(request.args.data.url);\n nonHttp2Resources.push(request);\n }\n\n return nonHttp2Resources;\n}\n\n/**\n * Computes the estimated effect of all results being converted to http/2 on the provided graph.\n */\nfunction computeWasteWithGraph(\n urlsToChange: Set<string>, graph: Lantern.Graph.Node, simulator: Lantern.Simulation.Simulator): Types.Timing.Milli {\n const simulationBefore = simulator.simulate(graph);\n\n // Update all the protocols to reflect implementing our recommendations\n const originalProtocols = new Map();\n graph.traverse(node => {\n if (node.type !== 'network') {\n return;\n }\n if (!urlsToChange.has(node.request.url)) {\n return;\n }\n\n originalProtocols.set(node.request.requestId, node.request.protocol);\n node.request.protocol = 'h2';\n });\n\n const simulationAfter = simulator.simulate(graph);\n\n // Restore the original protocol after we've done our simulation\n graph.traverse(node => {\n if (node.type !== 'network') {\n return;\n }\n const originalProtocol = originalProtocols.get(node.request.requestId);\n if (originalProtocol === undefined) {\n return;\n }\n node.request.protocol = originalProtocol;\n });\n\n const savings = simulationBefore.timeInMs - simulationAfter.timeInMs;\n\n return Platform.NumberUtilities.floor(savings, 1 / 10) as Types.Timing.Milli;\n}\n\nfunction computeMetricSavings(\n nonHttp2Requests: Types.Events.SyntheticNetworkRequest[], context: InsightSetContext): MetricSavings|undefined {\n if (!context.navigation || !context.lantern) {\n return;\n }\n\n const urlsToChange = new Set(nonHttp2Requests.map(r => r.args.data.url));\n\n const fcpGraph = context.lantern.metrics.firstContentfulPaint.optimisticGraph;\n const lcpGraph = context.lantern.metrics.largestContentfulPaint.optimisticGraph;\n\n return {\n FCP: computeWasteWithGraph(urlsToChange, fcpGraph, context.lantern.simulator),\n LCP: computeWasteWithGraph(urlsToChange, lcpGraph, context.lantern.simulator),\n };\n}\n\nfunction finalize(partialModel: PartialInsightModel<UseModernHTTPInsightModel>): UseModernHTTPInsightModel {\n return {\n insightKey: InsightKeys.IMAGE_DELIVERY,\n strings: UIStrings,\n title: i18nString(UIStrings.title),\n description: i18nString(UIStrings.description),\n category: InsightCategory.LCP,\n state: partialModel.requests.length > 0 ? 'fail' : 'pass',\n ...partialModel,\n relatedEvents: partialModel.requests,\n };\n}\n\nexport function generateInsight(\n parsedTrace: Handlers.Types.ParsedTrace, context: InsightSetContext): UseModernHTTPInsightModel {\n const isWithinContext = (event: Types.Events.Event): boolean => Helpers.Timing.eventIsInBounds(event, context.bounds);\n\n const contextRequests = parsedTrace.NetworkRequests.byTime.filter(isWithinContext);\n\n const entityMappings = parsedTrace.NetworkRequests.entityMappings;\n const firstPartyUrl = context.navigation?.args.data?.documentLoaderURL ?? parsedTrace.Meta.mainFrameURL;\n const firstPartyEntity = Handlers.Helpers.getEntityForUrl(firstPartyUrl, entityMappings.createdEntityCache);\n const nonHttp2Requests = determineNonHttp2Resources(contextRequests, entityMappings, firstPartyEntity ?? null);\n\n return finalize({\n requests: nonHttp2Requests,\n metricSavings: computeMetricSavings(nonHttp2Requests, context),\n });\n}\n"]}
1
+ {"version":3,"file":"ModernHTTP.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/ModernHTTP.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2025 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as i18n from '../../../core/i18n/i18n.js';\nimport * as Platform from '../../../core/platform/platform.js';\nimport * as Handlers from '../handlers/handlers.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport type * as Lantern from '../lantern/lantern.js';\nimport type * as Types from '../types/types.js';\n\nimport {\n InsightCategory,\n InsightKeys,\n type InsightModel,\n type InsightSetContext,\n type MetricSavings,\n type PartialInsightModel,\n} from './types.js';\n\nexport const UIStrings = {\n /**\n * @description Title of an insight that recommends using HTTP/2 over HTTP/1.1 because of the performance benefits. \"HTTP\" should not be translated.\n */\n title: 'Modern HTTP',\n /**\n * @description Description of an insight that recommends recommends using HTTP/2 over HTTP/1.1 because of the performance benefits. \"HTTP\" should not be translated.\n */\n description:\n 'HTTP/2 and HTTP/3 offer many benefits over HTTP/1.1, such as multiplexing. [Learn more about using modern HTTP](https://developer.chrome.com/docs/lighthouse/best-practices/uses-http2/).',\n /**\n * @description Column header for a table where each cell represents a network request.\n */\n request: 'Request',\n /**\n * @description Column header for a table where each cell represents the protocol of a network request.\n */\n protocol: 'Protocol',\n /**\n * @description Text explaining that there were not requests that were slowed down by using HTTP/1.1. \"HTTP/1.1\" should not be translated.\n */\n noOldProtocolRequests:\n 'No requests used HTTP/1.1, or its current use of HTTP/1.1 does not present a significant optimization opportunity. HTTP/1.1 requests are only flagged if six or more static assets originate from the same origin, and they are not served from a local development environment or a third-party source.'\n} as const;\n\nconst str_ = i18n.i18n.registerUIStrings('models/trace/insights/ModernHTTP.ts', UIStrings);\nexport const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);\n\nexport type ModernHTTPInsightModel = InsightModel<typeof UIStrings, {\n http1Requests: Types.Events.SyntheticNetworkRequest[],\n}>;\n\nexport function isModernHTTP(model: InsightModel): model is ModernHTTPInsightModel {\n return model.insightKey === InsightKeys.MODERN_HTTP;\n}\n\n/**\n * Determines whether a network request is a \"static resource\" that would benefit from H2 multiplexing.\n * XHRs, tracking pixels, etc generally don't benefit as much because they aren't requested en-masse\n * for the same origin at the exact same time.\n */\nfunction isMultiplexableStaticAsset(\n request: Types.Events.SyntheticNetworkRequest, entityMappings: Handlers.Helpers.EntityMappings,\n firstPartyEntity: Handlers.Helpers.Entity|null): boolean {\n if (!Helpers.Network.STATIC_RESOURCE_TYPES.has(request.args.data.resourceType)) {\n return false;\n }\n\n // Resources from third-parties that are less than 100 bytes are usually tracking pixels, not actual resources.\n // They can masquerade as static types though (gifs, documents, etc)\n if (request.args.data.decodedBodyLength < 100) {\n const entity = entityMappings.entityByEvent.get(request);\n if (entity) {\n // Third-party assets are multiplexable in their first-party context.\n if (firstPartyEntity?.name === entity.name) {\n return true;\n }\n // Skip recognizable third-parties' requests.\n if (!entity.isUnrecognized) {\n return false;\n }\n }\n }\n\n return true;\n}\n\n/**\n * Determine the set of resources that aren't HTTP/2 but should be.\n * We're a little conservative about what we surface for a few reasons:\n *\n * - The simulator approximation of HTTP/2 is a little more generous than reality.\n * - There's a bit of debate surrounding HTTP/2 due to its worse performance in environments with high packet loss. [1][2][3]\n * - It's something that you'd have absolutely zero control over with a third-party (can't defer to fix it for example).\n *\n * Therefore, we only surface requests that were...\n *\n * - Served over HTTP/1.1 or earlier\n * - Served over an origin that serves at least 6 static asset requests\n * (if there aren't more requests than browser's max/host, multiplexing isn't as big a deal)\n * - Not served on localhost (h2 is a pain to deal with locally & and CI)\n *\n * [1] https://news.ycombinator.com/item?id=19086639\n * [2] https://www.twilio.com/blog/2017/10/http2-issues.html\n * [3] https://www.cachefly.com/http-2-is-not-a-magic-bullet/\n */\nexport function determineHttp1Requests(\n requests: Types.Events.SyntheticNetworkRequest[], entityMappings: Handlers.Helpers.EntityMappings,\n firstPartyEntity: Handlers.Helpers.Entity|null): Types.Events.SyntheticNetworkRequest[] {\n const http1Requests: Types.Events.SyntheticNetworkRequest[] = [];\n\n const groupedByOrigin = new Map<string, Types.Events.SyntheticNetworkRequest[]>();\n for (const record of requests) {\n const url = new URL(record.args.data.url);\n if (!isMultiplexableStaticAsset(record, entityMappings, firstPartyEntity)) {\n continue;\n }\n if (Helpers.Network.isSyntheticNetworkRequestLocalhost(record)) {\n continue;\n }\n const originRequests = Platform.MapUtilities.getWithDefault(groupedByOrigin, url.origin, () => []);\n originRequests.push(record);\n }\n\n const seenURLs = new Set<string>();\n\n for (const request of requests) {\n // Skip duplicates.\n if (seenURLs.has(request.args.data.url)) {\n continue;\n }\n\n // Check if record is not served through the service worker, servicer worker uses http/1.1 as a protocol.\n // These can generate false positives (bug: https://github.com/GoogleChrome/lighthouse/issues/7158).\n if (request.args.data.fromServiceWorker) {\n continue;\n }\n\n // Test the protocol to see if it was http/1.1.\n const isOldHttp = /HTTP\\/[01][.\\d]?/i.test(request.args.data.protocol);\n if (!isOldHttp) {\n continue;\n }\n\n const url = new URL(request.args.data.url);\n\n // Check if the origin has enough requests to bother flagging.\n const group = groupedByOrigin.get(url.origin) || [];\n if (group.length < 6) {\n continue;\n }\n\n seenURLs.add(request.args.data.url);\n http1Requests.push(request);\n }\n\n return http1Requests;\n}\n\n/**\n * Computes the estimated effect of all results being converted to http/2 on the provided graph.\n */\nfunction computeWasteWithGraph(\n urlsToChange: Set<string>, graph: Lantern.Graph.Node, simulator: Lantern.Simulation.Simulator): Types.Timing.Milli {\n const simulationBefore = simulator.simulate(graph);\n\n // Update all the protocols to reflect implementing our recommendations\n const originalProtocols = new Map();\n graph.traverse(node => {\n if (node.type !== 'network') {\n return;\n }\n if (!urlsToChange.has(node.request.url)) {\n return;\n }\n\n originalProtocols.set(node.request.requestId, node.request.protocol);\n node.request.protocol = 'h2';\n });\n\n const simulationAfter = simulator.simulate(graph);\n\n // Restore the original protocol after we've done our simulation\n graph.traverse(node => {\n if (node.type !== 'network') {\n return;\n }\n const originalProtocol = originalProtocols.get(node.request.requestId);\n if (originalProtocol === undefined) {\n return;\n }\n node.request.protocol = originalProtocol;\n });\n\n const savings = simulationBefore.timeInMs - simulationAfter.timeInMs;\n\n return Platform.NumberUtilities.floor(savings, 1 / 10) as Types.Timing.Milli;\n}\n\nfunction computeMetricSavings(\n http1Requests: Types.Events.SyntheticNetworkRequest[], context: InsightSetContext): MetricSavings|undefined {\n if (!context.navigation || !context.lantern) {\n return;\n }\n\n const urlsToChange = new Set(http1Requests.map(r => r.args.data.url));\n\n const fcpGraph = context.lantern.metrics.firstContentfulPaint.optimisticGraph;\n const lcpGraph = context.lantern.metrics.largestContentfulPaint.optimisticGraph;\n\n return {\n FCP: computeWasteWithGraph(urlsToChange, fcpGraph, context.lantern.simulator),\n LCP: computeWasteWithGraph(urlsToChange, lcpGraph, context.lantern.simulator),\n };\n}\n\nfunction finalize(partialModel: PartialInsightModel<ModernHTTPInsightModel>): ModernHTTPInsightModel {\n return {\n insightKey: InsightKeys.MODERN_HTTP,\n strings: UIStrings,\n title: i18nString(UIStrings.title),\n description: i18nString(UIStrings.description),\n category: InsightCategory.LCP,\n state: partialModel.http1Requests.length > 0 ? 'fail' : 'pass',\n ...partialModel,\n relatedEvents: partialModel.http1Requests,\n };\n}\n\nexport function generateInsight(\n parsedTrace: Handlers.Types.ParsedTrace, context: InsightSetContext): ModernHTTPInsightModel {\n const isWithinContext = (event: Types.Events.Event): boolean => Helpers.Timing.eventIsInBounds(event, context.bounds);\n\n const contextRequests = parsedTrace.NetworkRequests.byTime.filter(isWithinContext);\n\n const entityMappings = parsedTrace.NetworkRequests.entityMappings;\n const firstPartyUrl = context.navigation?.args.data?.documentLoaderURL ?? parsedTrace.Meta.mainFrameURL;\n const firstPartyEntity = Handlers.Helpers.getEntityForUrl(firstPartyUrl, entityMappings.createdEntityCache);\n const http1Requests = determineHttp1Requests(contextRequests, entityMappings, firstPartyEntity ?? null);\n\n return finalize({\n http1Requests,\n metricSavings: computeMetricSavings(http1Requests, context),\n });\n}\n\nexport function createOverlayForRequest(request: Types.Events.SyntheticNetworkRequest): Types.Overlays.EntryOutline {\n return {\n type: 'ENTRY_OUTLINE',\n entry: request,\n outlineReason: 'ERROR',\n };\n}\n\nexport function createOverlays(model: ModernHTTPInsightModel): Types.Overlays.Overlay[] {\n return model.http1Requests.map(req => createOverlayForRequest(req)) ?? [];\n}\n"]}
@@ -42,15 +42,15 @@ export declare const UIStrings: {
42
42
  */
43
43
  readonly noPreconnectOrigins: "no origins were preconnected";
44
44
  /**
45
- * @description A warning message that is shown when found more than 4 preconnected links
45
+ * @description A warning message that is shown when found more than 4 preconnected links. "preconnect" should not be translated.
46
46
  */
47
47
  readonly tooManyPreconnectLinksWarning: "More than 4 `preconnect` connections were found. These should be used sparingly and only to the most important origins.";
48
48
  /**
49
- * @description A warning message that is shown when the user added preconnect for some unnecessary origins.
49
+ * @description A warning message that is shown when the user added preconnect for some unnecessary origins. "preconnect" should not be translated.
50
50
  */
51
51
  readonly unusedWarning: "Unused preconnect. Only use `preconnect` for origins that the page is likely to request.";
52
52
  /**
53
- * @description A warning message that is shown when the user forget to set the `crossorigin` HTML attribute, or setting it to an incorrect value, on the link is a common mistake when adding preconnect links.
53
+ * @description A warning message that is shown when the user forget to set the `crossorigin` HTML attribute, or setting it to an incorrect value, on the link is a common mistake when adding preconnect links. "preconnect" should not be translated.
54
54
  * */
55
55
  readonly crossoriginWarning: "Unused preconnect. Check that the `crossorigin` attribute is used properly.";
56
56
  /**
@@ -66,7 +66,7 @@ export declare const UIStrings: {
66
66
  */
67
67
  readonly estSavingTableTitle: "Preconnect candidates";
68
68
  /**
69
- * @description Description of the table that recommends preconnecting to the origins to save time.
69
+ * @description Description of the table that recommends preconnecting to the origins to save time. "preconnect" should not be translated.
70
70
  */
71
71
  readonly estSavingTableDescription: "Add [preconnect](https://developer.chrome.com/docs/lighthouse/performance/uses-rel-preconnect/) hints to your most important origins, but try to use no more than 4.";
72
72
  /**
@@ -129,6 +129,7 @@ export declare function handleLinkResponseHeader(linkHeaderValue: string): Array
129
129
  export declare function generatePreconnectedOrigins(parsedTrace: Handlers.Types.ParsedTrace, context: InsightSetContextWithNavigation, contextRequests: Types.Events.SyntheticNetworkRequest[], preconnectCandidates: PreconnectCandidate[]): PreconnectedOrigin[];
130
130
  export declare function generatePreconnectCandidates(parsedTrace: Handlers.Types.ParsedTrace, context: InsightSetContextWithNavigation, contextRequests: Types.Events.SyntheticNetworkRequest[]): PreconnectCandidate[];
131
131
  export declare function generateInsight(parsedTrace: Handlers.Types.ParsedTrace, context: InsightSetContext): NetworkDependencyTreeInsightModel;
132
+ export declare function createOverlays(model: NetworkDependencyTreeInsightModel): Types.Overlays.Overlay[];
132
133
  /**
133
134
  * http://tools.ietf.org/html/rfc3986#section-5.2.4
134
135
  */
@@ -45,15 +45,15 @@ export const UIStrings = {
45
45
  */
46
46
  noPreconnectOrigins: 'no origins were preconnected',
47
47
  /**
48
- * @description A warning message that is shown when found more than 4 preconnected links
48
+ * @description A warning message that is shown when found more than 4 preconnected links. "preconnect" should not be translated.
49
49
  */
50
50
  tooManyPreconnectLinksWarning: 'More than 4 `preconnect` connections were found. These should be used sparingly and only to the most important origins.',
51
51
  /**
52
- * @description A warning message that is shown when the user added preconnect for some unnecessary origins.
52
+ * @description A warning message that is shown when the user added preconnect for some unnecessary origins. "preconnect" should not be translated.
53
53
  */
54
54
  unusedWarning: 'Unused preconnect. Only use `preconnect` for origins that the page is likely to request.',
55
55
  /**
56
- * @description A warning message that is shown when the user forget to set the `crossorigin` HTML attribute, or setting it to an incorrect value, on the link is a common mistake when adding preconnect links.
56
+ * @description A warning message that is shown when the user forget to set the `crossorigin` HTML attribute, or setting it to an incorrect value, on the link is a common mistake when adding preconnect links. "preconnect" should not be translated.
57
57
  * */
58
58
  crossoriginWarning: 'Unused preconnect. Check that the `crossorigin` attribute is used properly.',
59
59
  /**
@@ -69,7 +69,7 @@ export const UIStrings = {
69
69
  */
70
70
  estSavingTableTitle: 'Preconnect candidates',
71
71
  /**
72
- * @description Description of the table that recommends preconnecting to the origins to save time.
72
+ * @description Description of the table that recommends preconnecting to the origins to save time. "preconnect" should not be translated.
73
73
  */
74
74
  estSavingTableDescription: 'Add [preconnect](https://developer.chrome.com/docs/lighthouse/performance/uses-rel-preconnect/) hints to your most important origins, but try to use no more than 4.',
75
75
  /**
@@ -313,12 +313,21 @@ export function handleLinkResponseHeader(linkHeaderValue) {
313
313
  return [];
314
314
  }
315
315
  const preconnectedOrigins = [];
316
- // const headerTextParts = linkHeaderValue.split(',');
317
316
  for (let i = 0; i < linkHeaderValue.length;) {
318
317
  const firstUrlEnd = linkHeaderValue.indexOf('>', i);
318
+ if (firstUrlEnd === -1) {
319
+ break;
320
+ }
319
321
  const commaIndex = linkHeaderValue.indexOf(',', firstUrlEnd);
320
322
  const partEnd = commaIndex !== -1 ? commaIndex : linkHeaderValue.length;
321
323
  const part = linkHeaderValue.substring(i, partEnd);
324
+ // This shouldn't be necessary, but we had a bug that created an infinite loop so
325
+ // let's guard against that.
326
+ // See crbug.com/431239629
327
+ if (partEnd + 1 <= i) {
328
+ console.warn('unexpected infinite loop, bailing');
329
+ break;
330
+ }
322
331
  i = partEnd + 1;
323
332
  const preconnectedOrigin = handleLinkResponseHeaderPart(part.trim());
324
333
  if (preconnectedOrigin) {
@@ -344,7 +353,7 @@ export function generatePreconnectedOrigins(parsedTrace, context, contextRequest
344
353
  source: 'DOM',
345
354
  });
346
355
  }
347
- const documentRequest = parsedTrace.NetworkRequests.byTime.find(req => req.args.data.requestId === context.navigationId);
356
+ const documentRequest = parsedTrace.NetworkRequests.byId.get(context.navigationId);
348
357
  documentRequest?.args.data.responseHeaders?.forEach(header => {
349
358
  if (header.name.toLowerCase() === 'link') {
350
359
  const preconnectedOriginsFromResponseHeader = handleLinkResponseHeader(header.value); // , documentRequest);
@@ -431,8 +440,8 @@ export function generatePreconnectCandidates(parsedTrace, context, contextReques
431
440
  if (!context.lantern) {
432
441
  return [];
433
442
  }
434
- const mainResource = contextRequests.find(request => request.args.data.requestId === context.navigationId);
435
- if (!mainResource) {
443
+ const documentRequest = parsedTrace.NetworkRequests.byId.get(context.navigationId);
444
+ if (!documentRequest) {
436
445
  return [];
437
446
  }
438
447
  const { rtt, additionalRttByOrigin } = context.lantern.simulator.getOptions();
@@ -450,11 +459,11 @@ export function generatePreconnectCandidates(parsedTrace, context, contextReques
450
459
  fcpGraphURLs.add(node.request.url);
451
460
  }
452
461
  });
453
- const origins = candidateRequestsByOrigin(parsedTrace, mainResource, contextRequests, lcpGraphURLs);
462
+ const groupedOrigins = candidateRequestsByOrigin(parsedTrace, documentRequest, contextRequests, lcpGraphURLs);
454
463
  let maxWastedLcp = Types.Timing.Milli(0);
455
464
  let maxWastedFcp = Types.Timing.Milli(0);
456
465
  let preconnectCandidates = [];
457
- origins.forEach(requests => {
466
+ groupedOrigins.forEach(requests => {
458
467
  const firstRequestOfOrigin = requests[0];
459
468
  // Skip the origin if we don't have timing information
460
469
  if (!firstRequestOfOrigin.args.data.timing) {
@@ -471,7 +480,8 @@ export function generatePreconnectCandidates(parsedTrace, context, contextReques
471
480
  if (firstRequestOfOriginParsedURL.scheme === 'https') {
472
481
  connectionTime = Types.Timing.Milli(connectionTime * 2);
473
482
  }
474
- const timeBetweenMainResourceAndDnsStart = Types.Timing.Micro(firstRequestOfOrigin.args.data.syntheticData.sendStartTime - mainResource.args.data.syntheticData.finishTime +
483
+ const timeBetweenMainResourceAndDnsStart = Types.Timing.Micro(firstRequestOfOrigin.args.data.syntheticData.sendStartTime -
484
+ documentRequest.args.data.syntheticData.finishTime +
475
485
  Helpers.Timing.milliToMicro(firstRequestOfOrigin.args.data.timing.dnsStart));
476
486
  const wastedMs = Math.min(connectionTime, Helpers.Timing.microToMilli(timeBetweenMainResourceAndDnsStart));
477
487
  if (wastedMs < IGNORE_THRESHOLD_IN_MILLISECONDS) {
@@ -513,6 +523,21 @@ export function generateInsight(parsedTrace, context) {
513
523
  preconnectCandidates,
514
524
  });
515
525
  }
526
+ export function createOverlays(model) {
527
+ function walk(nodes, overlays) {
528
+ nodes.forEach(node => {
529
+ overlays.push({
530
+ type: 'ENTRY_OUTLINE',
531
+ entry: node.request,
532
+ outlineReason: 'ERROR',
533
+ });
534
+ walk(node.children, overlays);
535
+ });
536
+ }
537
+ const overlays = [];
538
+ walk(model.rootNodes, overlays);
539
+ return overlays;
540
+ }
516
541
  // the rest of this file is copied from core/common/common.js, which can't be bundled right now.
517
542
  /**
518
543
  * http://tools.ietf.org/html/rfc3986#section-5.2.4