@paulirish/trace_engine 0.0.44 → 0.0.46

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 (272) hide show
  1. package/.tmp/tsbuildinfo/tsconfig.tsbuildinfo +1 -1
  2. package/core/platform/ArrayUtilities.d.ts +1 -1
  3. package/core/platform/ArrayUtilities.js.map +1 -1
  4. package/core/platform/DOMUtilities.js +1 -1
  5. package/core/platform/DOMUtilities.js.map +1 -1
  6. package/core/platform/MimeType.js.map +1 -1
  7. package/core/platform/NumberUtilities.js.map +1 -1
  8. package/core/platform/ServerTiming.d.ts +2 -2
  9. package/core/platform/ServerTiming.js.map +1 -1
  10. package/core/platform/StringUtilities.js +1 -1
  11. package/core/platform/StringUtilities.js.map +1 -1
  12. package/core/platform/Timing.d.ts +0 -1
  13. package/core/platform/Timing.js +0 -3
  14. package/core/platform/Timing.js.map +1 -1
  15. package/core/platform/TypedArrayUtilities.js +3 -2
  16. package/core/platform/TypedArrayUtilities.js.map +1 -1
  17. package/generated/protocol.d.ts +71 -4
  18. package/locales/af.json +544 -1
  19. package/locales/am.json +544 -1
  20. package/locales/ar.json +544 -1
  21. package/locales/as.json +544 -1
  22. package/locales/az.json +544 -1
  23. package/locales/be.json +544 -1
  24. package/locales/bg.json +544 -1
  25. package/locales/bn.json +544 -1
  26. package/locales/bs.json +544 -1
  27. package/locales/ca.json +544 -1
  28. package/locales/cs.json +544 -1
  29. package/locales/cy.json +544 -1
  30. package/locales/da.json +544 -1
  31. package/locales/de.json +544 -1
  32. package/locales/el.json +544 -1
  33. package/locales/en-GB.json +544 -1
  34. package/locales/en-US.json +561 -15
  35. package/locales/en-XL.json +561 -15
  36. package/locales/es-419.json +544 -1
  37. package/locales/es.json +544 -1
  38. package/locales/et.json +544 -1
  39. package/locales/eu.json +544 -1
  40. package/locales/fa.json +544 -1
  41. package/locales/fi.json +544 -1
  42. package/locales/fil.json +544 -1
  43. package/locales/fr-CA.json +544 -1
  44. package/locales/fr.json +544 -1
  45. package/locales/gl.json +544 -1
  46. package/locales/gu.json +544 -1
  47. package/locales/he.json +545 -2
  48. package/locales/hi.json +544 -1
  49. package/locales/hr.json +544 -1
  50. package/locales/hu.json +544 -1
  51. package/locales/hy.json +544 -1
  52. package/locales/id.json +544 -1
  53. package/locales/is.json +544 -1
  54. package/locales/it.json +544 -1
  55. package/locales/ja.json +544 -1
  56. package/locales/ka.json +544 -1
  57. package/locales/kk.json +544 -1
  58. package/locales/km.json +544 -1
  59. package/locales/kn.json +544 -1
  60. package/locales/ko.json +544 -1
  61. package/locales/ky.json +544 -1
  62. package/locales/lo.json +544 -1
  63. package/locales/lt.json +544 -1
  64. package/locales/lv.json +544 -1
  65. package/locales/mk.json +544 -1
  66. package/locales/ml.json +544 -1
  67. package/locales/mn.json +544 -1
  68. package/locales/mr.json +544 -1
  69. package/locales/ms.json +544 -1
  70. package/locales/my.json +544 -1
  71. package/locales/ne.json +544 -1
  72. package/locales/nl.json +544 -1
  73. package/locales/no.json +544 -1
  74. package/locales/or.json +544 -1
  75. package/locales/pa.json +544 -1
  76. package/locales/pl.json +544 -1
  77. package/locales/pt-PT.json +544 -1
  78. package/locales/pt.json +544 -1
  79. package/locales/ro.json +544 -1
  80. package/locales/ru.json +544 -1
  81. package/locales/si.json +544 -1
  82. package/locales/sk.json +544 -1
  83. package/locales/sl.json +544 -1
  84. package/locales/sq.json +544 -1
  85. package/locales/sr-Latn.json +544 -1
  86. package/locales/sr.json +544 -1
  87. package/locales/sv.json +544 -1
  88. package/locales/sw.json +544 -1
  89. package/locales/ta.json +544 -1
  90. package/locales/te.json +544 -1
  91. package/locales/th.json +544 -1
  92. package/locales/tr.json +544 -1
  93. package/locales/uk.json +544 -1
  94. package/locales/ur.json +544 -1
  95. package/locales/uz.json +544 -1
  96. package/locales/vi.json +544 -1
  97. package/locales/zh-HK.json +544 -1
  98. package/locales/zh-TW.json +544 -1
  99. package/locales/zh.json +544 -1
  100. package/locales/zu.json +544 -1
  101. package/models/cpu_profile/CPUProfileDataModel.js +10 -10
  102. package/models/cpu_profile/CPUProfileDataModel.js.map +1 -1
  103. package/models/trace/LanternComputationData.js.map +1 -1
  104. package/models/trace/ModelImpl.d.ts +1 -0
  105. package/models/trace/ModelImpl.js +1 -0
  106. package/models/trace/ModelImpl.js.map +1 -1
  107. package/models/trace/Processor.js +16 -11
  108. package/models/trace/Processor.js.map +1 -1
  109. package/models/trace/extras/FetchNodes.d.ts +1 -1
  110. package/models/trace/extras/FetchNodes.js +3 -3
  111. package/models/trace/extras/FetchNodes.js.map +1 -1
  112. package/models/trace/extras/ScriptDuplication.d.ts +34 -0
  113. package/models/trace/extras/ScriptDuplication.js +178 -0
  114. package/models/trace/extras/ScriptDuplication.js.map +1 -0
  115. package/models/trace/extras/StackTraceForEvent.js +25 -44
  116. package/models/trace/extras/StackTraceForEvent.js.map +1 -1
  117. package/models/trace/extras/ThirdParties.js +1 -0
  118. package/models/trace/extras/ThirdParties.js.map +1 -1
  119. package/models/trace/extras/TraceTree.d.ts +5 -2
  120. package/models/trace/extras/TraceTree.js +47 -17
  121. package/models/trace/extras/TraceTree.js.map +1 -1
  122. package/models/trace/extras/extras-tsconfig.json +1 -1
  123. package/models/trace/extras/extras.d.ts +1 -0
  124. package/models/trace/extras/extras.js +1 -0
  125. package/models/trace/extras/extras.js.map +1 -1
  126. package/models/trace/handlers/AnimationFramesHandler.js.map +1 -1
  127. package/models/trace/handlers/AsyncJSCallsHandler.js.map +1 -1
  128. package/models/trace/handlers/AuctionWorkletsHandler.js.map +1 -1
  129. package/models/trace/handlers/ExtensionTraceDataHandler.d.ts +1 -1
  130. package/models/trace/handlers/ExtensionTraceDataHandler.js +2 -1
  131. package/models/trace/handlers/ExtensionTraceDataHandler.js.map +1 -1
  132. package/models/trace/handlers/FramesHandler.js.map +1 -1
  133. package/models/trace/handlers/ImagePaintingHandler.js +1 -1
  134. package/models/trace/handlers/ImagePaintingHandler.js.map +1 -1
  135. package/models/trace/handlers/InitiatorsHandler.js.map +1 -1
  136. package/models/trace/handlers/InvalidationsHandler.js.map +1 -1
  137. package/models/trace/handlers/LayoutShiftsHandler.js.map +1 -1
  138. package/models/trace/handlers/MetaHandler.d.ts +2 -2
  139. package/models/trace/handlers/MetaHandler.js +4 -6
  140. package/models/trace/handlers/MetaHandler.js.map +1 -1
  141. package/models/trace/handlers/ModelHandlers.d.ts +1 -0
  142. package/models/trace/handlers/ModelHandlers.js +1 -0
  143. package/models/trace/handlers/ModelHandlers.js.map +1 -1
  144. package/models/trace/handlers/NetworkRequestsHandler.d.ts +9 -0
  145. package/models/trace/handlers/NetworkRequestsHandler.js +6 -6
  146. package/models/trace/handlers/NetworkRequestsHandler.js.map +1 -1
  147. package/models/trace/handlers/PageLoadMetricsHandler.js +1 -1
  148. package/models/trace/handlers/PageLoadMetricsHandler.js.map +1 -1
  149. package/models/trace/handlers/RendererHandler.js +3 -4
  150. package/models/trace/handlers/RendererHandler.js.map +1 -1
  151. package/models/trace/handlers/ScriptsHandler.d.ts +22 -0
  152. package/models/trace/handlers/ScriptsHandler.js +116 -0
  153. package/models/trace/handlers/ScriptsHandler.js.map +1 -0
  154. package/models/trace/handlers/UserTimingsHandler.d.ts +5 -0
  155. package/models/trace/handlers/UserTimingsHandler.js +16 -0
  156. package/models/trace/handlers/UserTimingsHandler.js.map +1 -1
  157. package/models/trace/handlers/WorkersHandler.js.map +1 -1
  158. package/models/trace/handlers/handlers-tsconfig.json +1 -0
  159. package/models/trace/handlers/helpers.d.ts +5 -1
  160. package/models/trace/handlers/helpers.js +28 -4
  161. package/models/trace/handlers/helpers.js.map +1 -1
  162. package/models/trace/helpers/Network.d.ts +1 -0
  163. package/models/trace/helpers/Network.js +8 -3
  164. package/models/trace/helpers/Network.js.map +1 -1
  165. package/models/trace/helpers/SamplesIntegrator.d.ts +8 -1
  166. package/models/trace/helpers/SamplesIntegrator.js +42 -2
  167. package/models/trace/helpers/SamplesIntegrator.js.map +1 -1
  168. package/models/trace/helpers/Timing.js.map +1 -1
  169. package/models/trace/helpers/Trace.d.ts +7 -10
  170. package/models/trace/helpers/Trace.js +25 -10
  171. package/models/trace/helpers/Trace.js.map +1 -1
  172. package/models/trace/insights/CLSCulprits.d.ts +12 -12
  173. package/models/trace/insights/CLSCulprits.js +15 -4
  174. package/models/trace/insights/CLSCulprits.js.map +1 -1
  175. package/models/trace/insights/Common.d.ts +7 -1
  176. package/models/trace/insights/Common.js +9 -3
  177. package/models/trace/insights/Common.js.map +1 -1
  178. package/models/trace/insights/DOMSize.d.ts +8 -8
  179. package/models/trace/insights/DOMSize.js +2 -1
  180. package/models/trace/insights/DOMSize.js.map +1 -1
  181. package/models/trace/insights/DocumentLatency.d.ts +11 -11
  182. package/models/trace/insights/DocumentLatency.js +2 -1
  183. package/models/trace/insights/DocumentLatency.js.map +1 -1
  184. package/models/trace/insights/DuplicateJavaScript.d.ts +18 -0
  185. package/models/trace/insights/DuplicateJavaScript.js +49 -0
  186. package/models/trace/insights/DuplicateJavaScript.js.map +1 -0
  187. package/models/trace/insights/FontDisplay.d.ts +4 -4
  188. package/models/trace/insights/FontDisplay.js +2 -1
  189. package/models/trace/insights/FontDisplay.js.map +1 -1
  190. package/models/trace/insights/ForcedReflow.d.ts +5 -5
  191. package/models/trace/insights/ForcedReflow.js +4 -1
  192. package/models/trace/insights/ForcedReflow.js.map +1 -1
  193. package/models/trace/insights/ImageDelivery.d.ts +19 -15
  194. package/models/trace/insights/ImageDelivery.js +26 -20
  195. package/models/trace/insights/ImageDelivery.js.map +1 -1
  196. package/models/trace/insights/InteractionToNextPaint.d.ts +8 -8
  197. package/models/trace/insights/InteractionToNextPaint.js +3 -2
  198. package/models/trace/insights/InteractionToNextPaint.js.map +1 -1
  199. package/models/trace/insights/LCPDiscovery.d.ts +9 -9
  200. package/models/trace/insights/LCPDiscovery.js +6 -3
  201. package/models/trace/insights/LCPDiscovery.js.map +1 -1
  202. package/models/trace/insights/LCPPhases.d.ts +15 -10
  203. package/models/trace/insights/LCPPhases.js +11 -4
  204. package/models/trace/insights/LCPPhases.js.map +1 -1
  205. package/models/trace/insights/Models.d.ts +2 -1
  206. package/models/trace/insights/Models.js +2 -1
  207. package/models/trace/insights/Models.js.map +1 -1
  208. package/models/trace/insights/NetworkDependencyTree.d.ts +33 -0
  209. package/models/trace/insights/NetworkDependencyTree.js +141 -0
  210. package/models/trace/insights/NetworkDependencyTree.js.map +1 -0
  211. package/models/trace/insights/RenderBlocking.d.ts +5 -5
  212. package/models/trace/insights/RenderBlocking.js +2 -1
  213. package/models/trace/insights/RenderBlocking.js.map +1 -1
  214. package/models/trace/insights/SlowCSSSelector.d.ts +8 -8
  215. package/models/trace/insights/SlowCSSSelector.js +4 -2
  216. package/models/trace/insights/SlowCSSSelector.js.map +1 -1
  217. package/models/trace/insights/ThirdParties.d.ts +6 -6
  218. package/models/trace/insights/ThirdParties.js +8 -5
  219. package/models/trace/insights/ThirdParties.js.map +1 -1
  220. package/models/trace/insights/Viewport.d.ts +2 -2
  221. package/models/trace/insights/Viewport.js +2 -1
  222. package/models/trace/insights/Viewport.js.map +1 -1
  223. package/models/trace/insights/insights-tsconfig.json +2 -1
  224. package/models/trace/insights/types.d.ts +25 -3
  225. package/models/trace/insights/types.js.map +1 -1
  226. package/models/trace/lantern/core/NetworkAnalyzer.d.ts +2 -2
  227. package/models/trace/lantern/core/NetworkAnalyzer.js +2 -2
  228. package/models/trace/lantern/core/NetworkAnalyzer.js.map +1 -1
  229. package/models/trace/lantern/graph/BaseNode.d.ts +1 -1
  230. package/models/trace/lantern/graph/BaseNode.js.map +1 -1
  231. package/models/trace/lantern/graph/CPUNode.js +1 -1
  232. package/models/trace/lantern/graph/CPUNode.js.map +1 -1
  233. package/models/trace/lantern/graph/NetworkNode.js +1 -1
  234. package/models/trace/lantern/graph/NetworkNode.js.map +1 -1
  235. package/models/trace/lantern/graph/PageDependencyGraph.d.ts +2 -2
  236. package/models/trace/lantern/graph/PageDependencyGraph.js.map +1 -1
  237. package/models/trace/lantern/metrics/Metric.js.map +1 -1
  238. package/models/trace/lantern/metrics/TotalBlockingTime.d.ts +2 -2
  239. package/models/trace/lantern/metrics/TotalBlockingTime.js.map +1 -1
  240. package/models/trace/lantern/types/Lantern.d.ts +2 -2
  241. package/models/trace/lantern/types/Lantern.js.map +1 -1
  242. package/models/trace/trace-tsconfig.json +3 -3
  243. package/models/trace/trace.d.ts +1 -2
  244. package/models/trace/trace.js +1 -2
  245. package/models/trace/trace.js.map +1 -1
  246. package/models/trace/types/Configuration.d.ts +10 -0
  247. package/models/trace/types/Configuration.js.map +1 -1
  248. package/models/trace/types/Extensions.d.ts +1 -1
  249. package/models/trace/types/Extensions.js.map +1 -1
  250. package/models/trace/types/TraceEvents.d.ts +87 -4
  251. package/models/trace/types/TraceEvents.js +20 -0
  252. package/models/trace/types/TraceEvents.js.map +1 -1
  253. package/package.json +1 -1
  254. package/test/test-trace-engine.mjs +3 -2
  255. package/models/trace/extras/TimelineJSProfile.d.ts +0 -13
  256. package/models/trace/extras/TimelineJSProfile.js +0 -60
  257. package/models/trace/extras/TimelineJSProfile.js.map +0 -1
  258. package/models/trace/insights/LongCriticalNetworkTree.d.ts +0 -22
  259. package/models/trace/insights/LongCriticalNetworkTree.js +0 -40
  260. package/models/trace/insights/LongCriticalNetworkTree.js.map +0 -1
  261. package/models/trace/root-causes/LayoutShift.d.ts +0 -125
  262. package/models/trace/root-causes/LayoutShift.js +0 -519
  263. package/models/trace/root-causes/LayoutShift.js.map +0 -1
  264. package/models/trace/root-causes/RootCauses.d.ts +0 -15
  265. package/models/trace/root-causes/RootCauses.js +0 -12
  266. package/models/trace/root-causes/RootCauses.js.map +0 -1
  267. package/models/trace/root-causes/bundle-tsconfig.json +0 -1
  268. package/models/trace/root-causes/devtools_entrypoint-bundle-typescript-tsconfig.json +0 -43
  269. package/models/trace/root-causes/root-causes-tsconfig.json +0 -56
  270. package/models/trace/root-causes/root-causes.d.ts +0 -1
  271. package/models/trace/root-causes/root-causes.js +0 -5
  272. package/models/trace/root-causes/root-causes.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"SlowCSSSelector.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/SlowCSSSelector.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,yEAAyE;AACzE,6BAA6B;AAE7B,OAAO,KAAK,IAAI,MAAM,4BAA4B,CAAC;AACnD,OAAO,KAAK,OAAO,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAAsB,kBAAkB,EAAC,MAAM,yBAAyB,CAAC;AAChF,OAAO,KAAK,KAAK,MAAM,mBAAmB,CAAC;AAE3C,OAAO,EACL,eAAe,EAKhB,MAAM,YAAY,CAAC;AAEpB,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB;;OAEG;IACH,KAAK,EAAE,oBAAoB;IAE3B;;OAEG;IACH,WAAW,EACP,yUAAyU;IAC7U;;OAEG;IACH,aAAa,EAAE,gBAAgB;IAC/B;;OAEG;IACH,UAAU,EAAE,aAAa;IACzB;;OAEG;IACH,OAAO,EAAE,cAAc;IACvB;;OAEG;IACH,YAAY,EAAE,eAAe;IAC7B;;OAEG;IACH,KAAK,EAAE,OAAO;IACd;;OAEG;IACH,kBAAkB,EACd,0GAA0G;CAC/G,CAAC;AAEF,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,0CAA0C,EAAE,SAAS,CAAC,CAAC;AAChG,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;AAE7E,MAAM,UAAU,IAAI;IAClB,OAAO,CAAC,eAAe,CAAC,CAAC;AAC3B,CAAC;AAUD,SAAS,sBAAsB,CAC3B,IAEE,EACF,OAA0B;IAC5B,MAAM,WAAW,GAAG,IAAI,GAAG,EAA0B,CAAC;IAEtD,KAAK,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC;QAClC,IAAI,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC;YACpD,SAAS;QACX,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3D,SAAS;QACX,CAAC;QACD,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;YACnC,MAAM,GAAG,GAAG,MAAM,CAAC,kBAAkB,CAAC,QAAQ,CAAC,GAAG,GAAG,GAAG,MAAM,CAAC,kBAAkB,CAAC,YAAY,CAAC,CAAC;YAChG,MAAM,UAAU,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACxC,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;gBAC7B,UAAU,CAAC,kBAAkB,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;gBAC7E,UAAU,CAAC,kBAAkB,CAAC,eAAe,CAAC,IAAI,MAAM,CAAC,kBAAkB,CAAC,eAAe,CAAC,CAAC;gBAC7F,UAAU,CAAC,kBAAkB,CAAC,aAAa,CAAC,IAAI,MAAM,CAAC,kBAAkB,CAAC,aAAa,CAAC,CAAC;gBACzF,UAAU,CAAC,kBAAkB,CAAC,UAAU,CAAC,IAAI,MAAM,CAAC,kBAAkB,CAAC,UAAU,CAAC,CAAC;YACrF,CAAC;iBAAM,CAAC;gBACN,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,EAAC,GAAG,MAAM,EAAC,CAAC,CAAC;YACpC,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC;AACnC,CAAC;AAED,SAAS,QAAQ,CAAC,YAA8D;IAC9E,OAAO;QACL,OAAO,EAAE,SAAS;QAClB,KAAK,EAAE,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC;QAClC,WAAW,EAAE,UAAU,CAAC,SAAS,CAAC,WAAW,CAAC;QAC9C,QAAQ,EAAE,eAAe,CAAC,GAAG;QAC7B,UAAU,EAAE,YAAY,CAAC,YAAY,CAAC,MAAM,KAAK,CAAC,IAAI,YAAY,CAAC,gBAAgB,CAAC,MAAM,KAAK,CAAC;QAChG,GAAG,YAAY;KAChB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAC3B,WAAsC,EAAE,OAA0B;IACpE,MAAM,iBAAiB,GAAG,WAAW,CAAC,aAAa,CAAC;IAEpD,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC5C,CAAC;IAED,MAAM,eAAe,GAAG,sBAAsB,CAAC,iBAAiB,CAAC,wBAAwB,EAAE,OAAO,CAAC,CAAC;IAEpG,IAAI,cAAc,GAAG,CAAC,CAAC;IACvB,IAAI,kBAAkB,GAAG,CAAC,CAAC;IAC3B,IAAI,eAAe,GAAG,CAAC,CAAC;IAExB,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;QAC3B,cAAc,IAAI,MAAM,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;QACrD,kBAAkB,IAAI,MAAM,CAAC,kBAAkB,CAAC,aAAa,CAAC,CAAC;QAC/D,eAAe,IAAI,MAAM,CAAC,kBAAkB,CAAC,UAAU,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,uBAAuB;IACvB,MAAM,eAAe,GAAG,CAAC,GAAG,eAAe,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACzD,OAAO,CAAC,CAAC,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;IAEH,yBAAyB;IACzB,MAAM,mBAAmB,GAAG,CAAC,GAAG,eAAe,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QAC7D,OAAO,CAAC,CAAC,kBAAkB,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,kBAAkB,CAAC,aAAa,CAAC,CAAC;IACnF,CAAC,CAAC,CAAC;IAEH,OAAO,QAAQ,CAAC;QACd,0EAA0E;QAC1E,aAAa,EAAE,EAAE;QACjB,cAAc,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,GAAG,MAAM,CAAC;QAC3D,kBAAkB;QAClB,eAAe;QACf,YAAY,EAAE,eAAe,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;QACzC,gBAAgB,EAAE,mBAAmB,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;KAClD,CAAC,CAAC;AACL,CAAC","sourcesContent":["// Copyright 2024 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 Helpers from '../helpers/helpers.js';\nimport {type SelectorTiming, SelectorTimingsKey} from '../types/TraceEvents.js';\nimport * as Types from '../types/types.js';\n\nimport {\n InsightCategory,\n type InsightModel,\n type InsightSetContext,\n type PartialInsightModel,\n type RequiredData\n} from './types.js';\n\nexport const UIStrings = {\n /**\n *@description Title of an insight that provides details about slow CSS selectors.\n */\n title: 'CSS Selector costs',\n\n /**\n * @description Text to describe how to improve the performance of CSS selectors.\n */\n description:\n 'If Recalculate Style costs remain high, selector optimization can reduce them. [Optimize the selectors](https://developer.chrome.com/docs/devtools/performance/selector-stats) with both high elapsed time and high slow-path %. Simpler selectors, fewer selectors, a smaller DOM, and a shallower DOM will all reduce matching costs.',\n /**\n *@description Column name for count of elements that the engine attempted to match against a style rule\n */\n matchAttempts: 'Match attempts',\n /**\n *@description Column name for count of elements that matched a style rule\n */\n matchCount: 'Match count',\n /**\n *@description Column name for elapsed time spent computing a style rule\n */\n elapsed: 'Elapsed time',\n /**\n *@description Column name for the selectors that took the longest amount of time/effort.\n */\n topSelectors: 'Top selectors',\n /**\n *@description Column name for a total sum.\n */\n total: 'Total',\n /**\n * @description Text status indicating that no CSS selector data was found.\n */\n enableSelectorData:\n 'No CSS selector data was found. CSS selector stats need to be enabled in the performance panel settings.',\n};\n\nconst str_ = i18n.i18n.registerUIStrings('models/trace/insights/SlowCSSSelector.ts', UIStrings);\nexport const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);\n\nexport function deps(): ['SelectorStats'] {\n return ['SelectorStats'];\n}\n\nexport type SlowCSSSelectorInsightModel = InsightModel<typeof UIStrings, {\n totalElapsedMs: Types.Timing.Milli,\n totalMatchAttempts: number,\n totalMatchCount: number,\n topElapsedMs: Types.Events.SelectorTiming[],\n topMatchAttempts: Types.Events.SelectorTiming[],\n}>;\n\nfunction aggregateSelectorStats(\n data: Map<Types.Events.UpdateLayoutTree, {\n timings: Types.Events.SelectorTiming[],\n }>,\n context: InsightSetContext): SelectorTiming[] {\n const selectorMap = new Map<String, SelectorTiming>();\n\n for (const [event, value] of data) {\n if (event.args.beginData?.frame !== context.frameId) {\n continue;\n }\n if (!Helpers.Timing.eventIsInBounds(event, context.bounds)) {\n continue;\n }\n for (const timing of value.timings) {\n const key = timing[SelectorTimingsKey.Selector] + '_' + timing[SelectorTimingsKey.StyleSheetId];\n const findTiming = selectorMap.get(key);\n if (findTiming !== undefined) {\n findTiming[SelectorTimingsKey.Elapsed] += timing[SelectorTimingsKey.Elapsed];\n findTiming[SelectorTimingsKey.FastRejectCount] += timing[SelectorTimingsKey.FastRejectCount];\n findTiming[SelectorTimingsKey.MatchAttempts] += timing[SelectorTimingsKey.MatchAttempts];\n findTiming[SelectorTimingsKey.MatchCount] += timing[SelectorTimingsKey.MatchCount];\n } else {\n selectorMap.set(key, {...timing});\n }\n }\n }\n\n return [...selectorMap.values()];\n}\n\nfunction finalize(partialModel: PartialInsightModel<SlowCSSSelectorInsightModel>): SlowCSSSelectorInsightModel {\n return {\n strings: UIStrings,\n title: i18nString(UIStrings.title),\n description: i18nString(UIStrings.description),\n category: InsightCategory.ALL,\n shouldShow: partialModel.topElapsedMs.length !== 0 && partialModel.topMatchAttempts.length !== 0,\n ...partialModel,\n };\n}\n\nexport function generateInsight(\n parsedTrace: RequiredData<typeof deps>, context: InsightSetContext): SlowCSSSelectorInsightModel {\n const selectorStatsData = parsedTrace.SelectorStats;\n\n if (!selectorStatsData) {\n throw new Error('no selector stats data');\n }\n\n const selectorTimings = aggregateSelectorStats(selectorStatsData.dataForUpdateLayoutEvent, context);\n\n let totalElapsedUs = 0;\n let totalMatchAttempts = 0;\n let totalMatchCount = 0;\n\n selectorTimings.map(timing => {\n totalElapsedUs += timing[SelectorTimingsKey.Elapsed];\n totalMatchAttempts += timing[SelectorTimingsKey.MatchAttempts];\n totalMatchCount += timing[SelectorTimingsKey.MatchCount];\n });\n\n // sort by elapsed time\n const sortByElapsedMs = [...selectorTimings].sort((a, b) => {\n return b[SelectorTimingsKey.Elapsed] - a[SelectorTimingsKey.Elapsed];\n });\n\n // sort by match attempts\n const sortByMatchAttempts = [...selectorTimings].sort((a, b) => {\n return b[SelectorTimingsKey.MatchAttempts] - a[SelectorTimingsKey.MatchAttempts];\n });\n\n return finalize({\n // TODO: should we identify UpdateLayout events as linked to this insight?\n relatedEvents: [],\n totalElapsedMs: Types.Timing.Milli(totalElapsedUs / 1000.0),\n totalMatchAttempts,\n totalMatchCount,\n topElapsedMs: sortByElapsedMs.slice(0, 3),\n topMatchAttempts: sortByMatchAttempts.slice(0, 3),\n });\n}\n"]}
1
+ {"version":3,"file":"SlowCSSSelector.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/SlowCSSSelector.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 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 Helpers from '../helpers/helpers.js';\nimport {type SelectorTiming, SelectorTimingsKey} from '../types/TraceEvents.js';\nimport * as Types from '../types/types.js';\n\nimport {\n InsightCategory,\n InsightKeys,\n type InsightModel,\n type InsightSetContext,\n type PartialInsightModel,\n type RequiredData,\n} from './types.js';\n\nexport const UIStrings = {\n /**\n *@description Title of an insight that provides details about slow CSS selectors.\n */\n title: 'CSS Selector costs',\n\n /**\n * @description Text to describe how to improve the performance of CSS selectors.\n */\n description:\n 'If Recalculate Style costs remain high, selector optimization can reduce them. [Optimize the selectors](https://developer.chrome.com/docs/devtools/performance/selector-stats) with both high elapsed time and high slow-path %. Simpler selectors, fewer selectors, a smaller DOM, and a shallower DOM will all reduce matching costs.',\n /**\n *@description Column name for count of elements that the engine attempted to match against a style rule\n */\n matchAttempts: 'Match attempts',\n /**\n *@description Column name for count of elements that matched a style rule\n */\n matchCount: 'Match count',\n /**\n *@description Column name for elapsed time spent computing a style rule\n */\n elapsed: 'Elapsed time',\n /**\n *@description Column name for the selectors that took the longest amount of time/effort.\n */\n topSelectors: 'Top selectors',\n /**\n *@description Column name for a total sum.\n */\n total: 'Total',\n /**\n * @description Text status indicating that no CSS selector data was found.\n */\n enableSelectorData:\n 'No CSS selector data was found. CSS selector stats need to be enabled in the performance panel settings.',\n} as const;\n\nconst str_ = i18n.i18n.registerUIStrings('models/trace/insights/SlowCSSSelector.ts', UIStrings);\nexport const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);\n\nexport function deps(): ['SelectorStats'] {\n return ['SelectorStats'];\n}\n\nexport type SlowCSSSelectorInsightModel = InsightModel<typeof UIStrings, {\n totalElapsedMs: Types.Timing.Milli,\n totalMatchAttempts: number,\n totalMatchCount: number,\n topElapsedMs: Types.Events.SelectorTiming[],\n topMatchAttempts: Types.Events.SelectorTiming[],\n}>;\n\nfunction aggregateSelectorStats(\n data: Map<Types.Events.UpdateLayoutTree, {\n timings: Types.Events.SelectorTiming[],\n }>,\n context: InsightSetContext): SelectorTiming[] {\n const selectorMap = new Map<String, SelectorTiming>();\n\n for (const [event, value] of data) {\n if (event.args.beginData?.frame !== context.frameId) {\n continue;\n }\n if (!Helpers.Timing.eventIsInBounds(event, context.bounds)) {\n continue;\n }\n for (const timing of value.timings) {\n const key = timing[SelectorTimingsKey.Selector] + '_' + timing[SelectorTimingsKey.StyleSheetId];\n const findTiming = selectorMap.get(key);\n if (findTiming !== undefined) {\n findTiming[SelectorTimingsKey.Elapsed] += timing[SelectorTimingsKey.Elapsed];\n findTiming[SelectorTimingsKey.FastRejectCount] += timing[SelectorTimingsKey.FastRejectCount];\n findTiming[SelectorTimingsKey.MatchAttempts] += timing[SelectorTimingsKey.MatchAttempts];\n findTiming[SelectorTimingsKey.MatchCount] += timing[SelectorTimingsKey.MatchCount];\n } else {\n selectorMap.set(key, {...timing});\n }\n }\n }\n\n return [...selectorMap.values()];\n}\n\nfunction finalize(partialModel: PartialInsightModel<SlowCSSSelectorInsightModel>): SlowCSSSelectorInsightModel {\n return {\n insightKey: InsightKeys.SLOW_CSS_SELECTOR,\n strings: UIStrings,\n title: i18nString(UIStrings.title),\n description: i18nString(UIStrings.description),\n category: InsightCategory.ALL,\n state: partialModel.topElapsedMs.length !== 0 && partialModel.topMatchAttempts.length !== 0 ? 'informative' :\n 'pass',\n ...partialModel,\n };\n}\n\nexport function generateInsight(\n parsedTrace: RequiredData<typeof deps>, context: InsightSetContext): SlowCSSSelectorInsightModel {\n const selectorStatsData = parsedTrace.SelectorStats;\n\n if (!selectorStatsData) {\n throw new Error('no selector stats data');\n }\n\n const selectorTimings = aggregateSelectorStats(selectorStatsData.dataForUpdateLayoutEvent, context);\n\n let totalElapsedUs = 0;\n let totalMatchAttempts = 0;\n let totalMatchCount = 0;\n\n selectorTimings.map(timing => {\n totalElapsedUs += timing[SelectorTimingsKey.Elapsed];\n totalMatchAttempts += timing[SelectorTimingsKey.MatchAttempts];\n totalMatchCount += timing[SelectorTimingsKey.MatchCount];\n });\n\n // sort by elapsed time\n const sortByElapsedMs = [...selectorTimings].sort((a, b) => {\n return b[SelectorTimingsKey.Elapsed] - a[SelectorTimingsKey.Elapsed];\n });\n\n // sort by match attempts\n const sortByMatchAttempts = [...selectorTimings].sort((a, b) => {\n return b[SelectorTimingsKey.MatchAttempts] - a[SelectorTimingsKey.MatchAttempts];\n });\n\n return finalize({\n // TODO: should we identify UpdateLayout events as linked to this insight?\n relatedEvents: [],\n totalElapsedMs: Types.Timing.Milli(totalElapsedUs / 1000.0),\n totalMatchAttempts,\n totalMatchCount,\n topElapsedMs: sortByElapsedMs.slice(0, 3),\n topMatchAttempts: sortByMatchAttempts.slice(0, 3),\n });\n}\n"]}
@@ -3,22 +3,22 @@ import type * as Types from '../types/types.js';
3
3
  import { type InsightModel, type InsightSetContext, type RequiredData } from './types.js';
4
4
  export declare const UIStrings: {
5
5
  /** Title of an insight that provides details about the code on a web page that the user doesn't control (referred to as "third-party code"). */
6
- title: string;
6
+ readonly title: "3rd parties";
7
7
  /**
8
8
  * @description Description of a DevTools insight that identifies the code on the page that the user doesn't control.
9
9
  * This is displayed after a user expands the section to see more. No character length limits.
10
10
  */
11
- description: string;
11
+ readonly description: string;
12
12
  /** Label for a table column that displays the name of a third-party provider. */
13
- columnThirdParty: string;
13
+ readonly columnThirdParty: "3rd party";
14
14
  /** Label for a column in a data table; entries will be the download size of a web resource in kilobytes. */
15
- columnTransferSize: string;
15
+ readonly columnTransferSize: "Transfer size";
16
16
  /** Label for a table column that displays how much time each row spent running on the main thread, entries will be the number of milliseconds spent. */
17
- columnMainThreadTime: string;
17
+ readonly columnMainThreadTime: "Main thread time";
18
18
  /**
19
19
  * @description Text block indicating that no third party content was detected on the page
20
20
  */
21
- noThirdParties: string;
21
+ readonly noThirdParties: "No third parties found";
22
22
  };
23
23
  export declare const i18nString: (id: string, values?: Record<string, string> | undefined) => Record<string, string>;
24
24
  export declare function deps(): ['Meta', 'NetworkRequests', 'Renderer', 'ImagePainting'];
@@ -9,15 +9,15 @@ import * as Helpers from '../helpers/helpers.js';
9
9
  import { InsightCategory } from './types.js';
10
10
  export const UIStrings = {
11
11
  /** Title of an insight that provides details about the code on a web page that the user doesn't control (referred to as "third-party code"). */
12
- title: 'Third parties',
12
+ title: '3rd parties',
13
13
  /**
14
14
  * @description Description of a DevTools insight that identifies the code on the page that the user doesn't control.
15
15
  * This is displayed after a user expands the section to see more. No character length limits.
16
16
  */
17
- description: 'Third party code can significantly impact load performance. ' +
18
- '[Reduce and defer loading of third party code](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/loading-third-party-javascript/) to prioritize your page\'s content.',
17
+ description: '3rd party code can significantly impact load performance. ' +
18
+ '[Reduce and defer loading of 3rd party code](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/loading-third-party-javascript/) to prioritize your page\'s content.',
19
19
  /** Label for a table column that displays the name of a third-party provider. */
20
- columnThirdParty: 'Third party',
20
+ columnThirdParty: '3rd party',
21
21
  /** Label for a column in a data table; entries will be the download size of a web resource in kilobytes. */
22
22
  columnTransferSize: 'Transfer size',
23
23
  /** Label for a table column that displays how much time each row spent running on the main thread, entries will be the number of milliseconds spent. */
@@ -43,11 +43,14 @@ function getRelatedEvents(summaries, firstPartyEntity) {
43
43
  }
44
44
  function finalize(partialModel) {
45
45
  return {
46
+ insightKey: "ThirdParties" /* InsightKeys.THIRD_PARTIES */,
46
47
  strings: UIStrings,
47
48
  title: i18nString(UIStrings.title),
48
49
  description: i18nString(UIStrings.description),
49
50
  category: InsightCategory.ALL,
50
- shouldShow: Boolean([...partialModel.summaryByEntity.entries()].find(kv => kv[0] !== partialModel.firstPartyEntity)),
51
+ state: [...partialModel.summaryByEntity.entries()].find(kv => kv[0] !== partialModel.firstPartyEntity) ?
52
+ 'informative' :
53
+ 'pass',
51
54
  ...partialModel,
52
55
  };
53
56
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ThirdParties.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/ThirdParties.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 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 ThirdPartyWeb from '../../../third_party/third-party-web/third-party-web.js';\nimport * as Extras from '../extras/extras.js';\nimport * as Handlers from '../handlers/handlers.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport type * as Types from '../types/types.js';\n\nimport {\n InsightCategory,\n type InsightModel,\n type InsightSetContext,\n type PartialInsightModel,\n type RequiredData\n} from './types.js';\n\nexport const UIStrings = {\n /** Title of an insight that provides details about the code on a web page that the user doesn't control (referred to as \"third-party code\"). */\n title: 'Third parties',\n /**\n * @description Description of a DevTools insight that identifies the code on the page that the user doesn't control.\n * This is displayed after a user expands the section to see more. No character length limits.\n */\n description: 'Third party code can significantly impact load performance. ' +\n '[Reduce and defer loading of third party code](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/loading-third-party-javascript/) to prioritize your page\\'s content.',\n /** Label for a table column that displays the name of a third-party provider. */\n columnThirdParty: 'Third party',\n /** Label for a column in a data table; entries will be the download size of a web resource in kilobytes. */\n columnTransferSize: 'Transfer size',\n /** Label for a table column that displays how much time each row spent running on the main thread, entries will be the number of milliseconds spent. */\n columnMainThreadTime: 'Main thread time',\n /**\n * @description Text block indicating that no third party content was detected on the page\n */\n noThirdParties: 'No third parties found',\n};\n\nconst str_ = i18n.i18n.registerUIStrings('models/trace/insights/ThirdParties.ts', UIStrings);\nexport const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);\n\nexport function deps(): ['Meta', 'NetworkRequests', 'Renderer', 'ImagePainting'] {\n return ['Meta', 'NetworkRequests', 'Renderer', 'ImagePainting'];\n}\n\nexport type ThirdPartiesInsightModel = InsightModel<typeof UIStrings, {\n eventsByEntity: Map<Extras.ThirdParties.Entity, Types.Events.Event[]>,\n summaryByEntity: Map<Extras.ThirdParties.Entity, Extras.ThirdParties.Summary>,\n summaryByUrl: Map<string, Extras.ThirdParties.Summary>,\n urlsByEntity: Map<Extras.ThirdParties.Entity, Set<string>>,\n /** The entity for this navigation's URL. Any other entity is from a third party. */\n firstPartyEntity?: Extras.ThirdParties.Entity,\n}>;\n\nfunction getRelatedEvents(\n summaries: Extras.ThirdParties.ThirdPartySummary,\n firstPartyEntity: Extras.ThirdParties.Entity|undefined): Types.Events.Event[] {\n const relatedEvents = [];\n\n for (const [entity, events] of summaries.eventsByEntity.entries()) {\n if (entity !== firstPartyEntity) {\n relatedEvents.push(...events);\n }\n }\n\n return relatedEvents;\n}\n\nfunction finalize(partialModel: PartialInsightModel<ThirdPartiesInsightModel>): ThirdPartiesInsightModel {\n return {\n strings: UIStrings,\n title: i18nString(UIStrings.title),\n description: i18nString(UIStrings.description),\n category: InsightCategory.ALL,\n shouldShow:\n Boolean([...partialModel.summaryByEntity.entries()].find(kv => kv[0] !== partialModel.firstPartyEntity)),\n ...partialModel,\n };\n}\n\nexport function generateInsight(\n parsedTrace: RequiredData<typeof deps>, context: InsightSetContext): ThirdPartiesInsightModel {\n const networkRequests = parsedTrace.NetworkRequests.byTime.filter(event => {\n if (!context.navigation) {\n return false;\n }\n\n if (event.args.data.frame !== context.frameId) {\n return false;\n }\n\n return Helpers.Timing.eventIsInBounds(event, context.bounds);\n });\n\n const thirdPartySummary = Extras.ThirdParties.summarizeThirdParties(\n parsedTrace as Handlers.Types.ParsedTrace, context.bounds, networkRequests);\n\n const firstPartyUrl = context.navigation?.args.data?.documentLoaderURL ?? parsedTrace.Meta.mainFrameURL;\n const firstPartyEntity = ThirdPartyWeb.ThirdPartyWeb.getEntity(firstPartyUrl) ||\n Handlers.Helpers.makeUpEntity(thirdPartySummary.madeUpEntityCache, firstPartyUrl);\n\n return finalize({\n relatedEvents: getRelatedEvents(thirdPartySummary, firstPartyEntity),\n eventsByEntity: thirdPartySummary.eventsByEntity,\n summaryByEntity: thirdPartySummary.byEntity,\n summaryByUrl: thirdPartySummary.byUrl,\n urlsByEntity: thirdPartySummary.urlsByEntity,\n firstPartyEntity,\n });\n}\n"]}
1
+ {"version":3,"file":"ThirdParties.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/ThirdParties.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 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 ThirdPartyWeb from '../../../third_party/third-party-web/third-party-web.js';\nimport * as Extras from '../extras/extras.js';\nimport * as Handlers from '../handlers/handlers.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport type * as Types from '../types/types.js';\n\nimport {\n InsightCategory,\n InsightKeys,\n type InsightModel,\n type InsightSetContext,\n type PartialInsightModel,\n type RequiredData\n} from './types.js';\n\nexport const UIStrings = {\n /** Title of an insight that provides details about the code on a web page that the user doesn't control (referred to as \"third-party code\"). */\n title: '3rd parties',\n /**\n * @description Description of a DevTools insight that identifies the code on the page that the user doesn't control.\n * This is displayed after a user expands the section to see more. No character length limits.\n */\n description: '3rd party code can significantly impact load performance. ' +\n '[Reduce and defer loading of 3rd party code](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/loading-third-party-javascript/) to prioritize your page\\'s content.',\n /** Label for a table column that displays the name of a third-party provider. */\n columnThirdParty: '3rd party',\n /** Label for a column in a data table; entries will be the download size of a web resource in kilobytes. */\n columnTransferSize: 'Transfer size',\n /** Label for a table column that displays how much time each row spent running on the main thread, entries will be the number of milliseconds spent. */\n columnMainThreadTime: 'Main thread time',\n /**\n * @description Text block indicating that no third party content was detected on the page\n */\n noThirdParties: 'No third parties found',\n} as const;\n\nconst str_ = i18n.i18n.registerUIStrings('models/trace/insights/ThirdParties.ts', UIStrings);\nexport const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);\n\nexport function deps(): ['Meta', 'NetworkRequests', 'Renderer', 'ImagePainting'] {\n return ['Meta', 'NetworkRequests', 'Renderer', 'ImagePainting'];\n}\n\nexport type ThirdPartiesInsightModel = InsightModel<typeof UIStrings, {\n eventsByEntity: Map<Extras.ThirdParties.Entity, Types.Events.Event[]>,\n summaryByEntity: Map<Extras.ThirdParties.Entity, Extras.ThirdParties.Summary>,\n summaryByUrl: Map<string, Extras.ThirdParties.Summary>,\n urlsByEntity: Map<Extras.ThirdParties.Entity, Set<string>>,\n /** The entity for this navigation's URL. Any other entity is from a third party. */\n firstPartyEntity?: Extras.ThirdParties.Entity,\n}>;\n\nfunction getRelatedEvents(\n summaries: Extras.ThirdParties.ThirdPartySummary,\n firstPartyEntity: Extras.ThirdParties.Entity|undefined): Types.Events.Event[] {\n const relatedEvents = [];\n\n for (const [entity, events] of summaries.eventsByEntity.entries()) {\n if (entity !== firstPartyEntity) {\n relatedEvents.push(...events);\n }\n }\n\n return relatedEvents;\n}\n\nfunction finalize(partialModel: PartialInsightModel<ThirdPartiesInsightModel>): ThirdPartiesInsightModel {\n return {\n insightKey: InsightKeys.THIRD_PARTIES,\n strings: UIStrings,\n title: i18nString(UIStrings.title),\n description: i18nString(UIStrings.description),\n category: InsightCategory.ALL,\n state: [...partialModel.summaryByEntity.entries()].find(kv => kv[0] !== partialModel.firstPartyEntity) ?\n 'informative' :\n 'pass',\n ...partialModel,\n };\n}\n\nexport function generateInsight(\n parsedTrace: RequiredData<typeof deps>, context: InsightSetContext): ThirdPartiesInsightModel {\n const networkRequests = parsedTrace.NetworkRequests.byTime.filter(event => {\n if (!context.navigation) {\n return false;\n }\n\n if (event.args.data.frame !== context.frameId) {\n return false;\n }\n\n return Helpers.Timing.eventIsInBounds(event, context.bounds);\n });\n\n const thirdPartySummary = Extras.ThirdParties.summarizeThirdParties(\n parsedTrace as Handlers.Types.ParsedTrace, context.bounds, networkRequests);\n\n const firstPartyUrl = context.navigation?.args.data?.documentLoaderURL ?? parsedTrace.Meta.mainFrameURL;\n const firstPartyEntity = ThirdPartyWeb.ThirdPartyWeb.getEntity(firstPartyUrl) ||\n Handlers.Helpers.makeUpEntity(thirdPartySummary.madeUpEntityCache, firstPartyUrl);\n\n return finalize({\n relatedEvents: getRelatedEvents(thirdPartySummary, firstPartyEntity),\n eventsByEntity: thirdPartySummary.eventsByEntity,\n summaryByEntity: thirdPartySummary.byEntity,\n summaryByUrl: thirdPartySummary.byUrl,\n urlsByEntity: thirdPartySummary.urlsByEntity,\n firstPartyEntity,\n });\n}\n"]}
@@ -2,11 +2,11 @@ import type * as Types from '../types/types.js';
2
2
  import { type InsightModel, type InsightSetContext, type RequiredData } from './types.js';
3
3
  export declare const UIStrings: {
4
4
  /** Title of an insight that provides details about if the page's viewport is optimized for mobile viewing. */
5
- title: string;
5
+ readonly title: "Optimize viewport for mobile";
6
6
  /**
7
7
  * @description Text to tell the user how a viewport meta element can improve performance. \xa0 is a non-breaking space
8
8
  */
9
- description: string;
9
+ readonly description: "Tap interactions may be [delayed by up to 300 ms](https://developer.chrome.com/blog/300ms-tap-delay-gone-away/) if the viewport is not optimized for mobile.";
10
10
  };
11
11
  export declare const i18nString: (id: string, values?: Record<string, string> | undefined) => Record<string, string>;
12
12
  export declare function deps(): ['Meta', 'UserInteractions'];
@@ -19,11 +19,12 @@ export function deps() {
19
19
  }
20
20
  function finalize(partialModel) {
21
21
  return {
22
+ insightKey: "Viewport" /* InsightKeys.VIEWPORT */,
22
23
  strings: UIStrings,
23
24
  title: i18nString(UIStrings.title),
24
25
  description: i18nString(UIStrings.description),
25
26
  category: InsightCategory.INP,
26
- shouldShow: partialModel.mobileOptimized === false,
27
+ state: partialModel.mobileOptimized === false ? 'fail' : 'pass',
27
28
  ...partialModel,
28
29
  };
29
30
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Viewport.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/Viewport.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,yEAAyE;AACzE,6BAA6B;AAE7B,OAAO,KAAK,IAAI,MAAM,4BAA4B,CAAC;AACnD,OAAO,KAAK,OAAO,MAAM,uBAAuB,CAAC;AAGjD,OAAO,EACL,eAAe,EAGf,cAAc,GAGf,MAAM,YAAY,CAAC;AAEpB,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,8GAA8G;IAC9G,KAAK,EAAE,8BAA8B;IACrC;;OAEG;IACH,WAAW,EACP,iKAAiK;CACtK,CAAC;AAEF,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,mCAAmC,EAAE,SAAS,CAAC,CAAC;AACzF,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;AAE7E,MAAM,UAAU,IAAI;IAClB,OAAO,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;AACtC,CAAC;AAOD,SAAS,QAAQ,CAAC,YAAuD;IACvE,OAAO;QACL,OAAO,EAAE,SAAS;QAClB,KAAK,EAAE,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC;QAClC,WAAW,EAAE,UAAU,CAAC,SAAS,CAAC,WAAW,CAAC;QAC9C,QAAQ,EAAE,eAAe,CAAC,GAAG;QAC7B,UAAU,EAAE,YAAY,CAAC,eAAe,KAAK,KAAK;QAClD,GAAG,YAAY;KAChB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAC3B,WAAsC,EAAE,OAA0B;IACpE,MAAM,gBAAgB,GAAG,WAAW,CAAC,gBAAgB,CAAC,gCAAgC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;QACpG,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC;YACzC,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,gBAAgB,CAAC,MAAM,EAAE,CAAC;QAC7B,uCAAuC;QACvC,OAAO,QAAQ,CAAC;YACd,eAAe,EAAE,IAAI;YACrB,QAAQ,EAAE,CAAC,cAAc,CAAC,SAAS,CAAC;SACrC,CAAC,CAAC;IACL,CAAC;IAED,MAAM,aAAa,GAAG,WAAW,CAAC,gBAAgB,CAAC,uBAAuB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;QACtF,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC;YAC9C,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,wDAAwD;IACxD,KAAK,MAAM,KAAK,IAAI,gBAAgB,EAAE,CAAC;QACrC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC;YACpC,OAAO,QAAQ,CAAC;gBACd,eAAe,EAAE,KAAK;gBACtB,aAAa;gBACb,aAAa,EAAE,EAAC,GAAG,EAAE,GAAyB,EAAC;aAChD,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;QACd,eAAe,EAAE,IAAI;QACrB,aAAa;KACd,CAAC,CAAC;AACL,CAAC","sourcesContent":["// Copyright 2024 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 Helpers from '../helpers/helpers.js';\nimport type * as Types from '../types/types.js';\n\nimport {\n InsightCategory,\n type InsightModel,\n type InsightSetContext,\n InsightWarning,\n type PartialInsightModel,\n type RequiredData,\n} from './types.js';\n\nexport const UIStrings = {\n /** Title of an insight that provides details about if the page's viewport is optimized for mobile viewing. */\n title: 'Optimize viewport for mobile',\n /**\n * @description Text to tell the user how a viewport meta element can improve performance. \\xa0 is a non-breaking space\n */\n description:\n 'Tap interactions may be [delayed by up to 300\\xA0ms](https://developer.chrome.com/blog/300ms-tap-delay-gone-away/) if the viewport is not optimized for mobile.',\n};\n\nconst str_ = i18n.i18n.registerUIStrings('models/trace/insights/Viewport.ts', UIStrings);\nexport const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);\n\nexport function deps(): ['Meta', 'UserInteractions'] {\n return ['Meta', 'UserInteractions'];\n}\n\nexport type ViewportInsightModel = InsightModel<typeof UIStrings, {\n mobileOptimized: boolean | null,\n viewportEvent?: Types.Events.ParseMetaViewport,\n}>;\n\nfunction finalize(partialModel: PartialInsightModel<ViewportInsightModel>): ViewportInsightModel {\n return {\n strings: UIStrings,\n title: i18nString(UIStrings.title),\n description: i18nString(UIStrings.description),\n category: InsightCategory.INP,\n shouldShow: partialModel.mobileOptimized === false,\n ...partialModel,\n };\n}\n\nexport function generateInsight(\n parsedTrace: RequiredData<typeof deps>, context: InsightSetContext): ViewportInsightModel {\n const compositorEvents = parsedTrace.UserInteractions.beginCommitCompositorFrameEvents.filter(event => {\n if (event.args.frame !== context.frameId) {\n return false;\n }\n\n return Helpers.Timing.eventIsInBounds(event, context.bounds);\n });\n\n if (!compositorEvents.length) {\n // Trace doesn't have the data we need.\n return finalize({\n mobileOptimized: null,\n warnings: [InsightWarning.NO_LAYOUT],\n });\n }\n\n const viewportEvent = parsedTrace.UserInteractions.parseMetaViewportEvents.find(event => {\n if (event.args.data.frame !== context.frameId) {\n return false;\n }\n\n return Helpers.Timing.eventIsInBounds(event, context.bounds);\n });\n\n // Returns true only if all events are mobile optimized.\n for (const event of compositorEvents) {\n if (!event.args.is_mobile_optimized) {\n return finalize({\n mobileOptimized: false,\n viewportEvent,\n metricSavings: {INP: 300 as Types.Timing.Milli},\n });\n }\n }\n\n return finalize({\n mobileOptimized: true,\n viewportEvent,\n });\n}\n"]}
1
+ {"version":3,"file":"Viewport.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/Viewport.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,yEAAyE;AACzE,6BAA6B;AAE7B,OAAO,KAAK,IAAI,MAAM,4BAA4B,CAAC;AACnD,OAAO,KAAK,OAAO,MAAM,uBAAuB,CAAC;AAGjD,OAAO,EACL,eAAe,EAIf,cAAc,GAGf,MAAM,YAAY,CAAC;AAEpB,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,8GAA8G;IAC9G,KAAK,EAAE,8BAA8B;IACrC;;OAEG;IACH,WAAW,EACP,iKAAiK;CAC7J,CAAC;AAEX,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,mCAAmC,EAAE,SAAS,CAAC,CAAC;AACzF,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;AAE7E,MAAM,UAAU,IAAI;IAClB,OAAO,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;AACtC,CAAC;AAOD,SAAS,QAAQ,CAAC,YAAuD;IACvE,OAAO;QACL,UAAU,uCAAsB;QAChC,OAAO,EAAE,SAAS;QAClB,KAAK,EAAE,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC;QAClC,WAAW,EAAE,UAAU,CAAC,SAAS,CAAC,WAAW,CAAC;QAC9C,QAAQ,EAAE,eAAe,CAAC,GAAG;QAC7B,KAAK,EAAE,YAAY,CAAC,eAAe,KAAK,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM;QAC/D,GAAG,YAAY;KAChB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAC3B,WAAsC,EAAE,OAA0B;IACpE,MAAM,gBAAgB,GAAG,WAAW,CAAC,gBAAgB,CAAC,gCAAgC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;QACpG,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC;YACzC,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,gBAAgB,CAAC,MAAM,EAAE,CAAC;QAC7B,uCAAuC;QACvC,OAAO,QAAQ,CAAC;YACd,eAAe,EAAE,IAAI;YACrB,QAAQ,EAAE,CAAC,cAAc,CAAC,SAAS,CAAC;SACrC,CAAC,CAAC;IACL,CAAC;IAED,MAAM,aAAa,GAAG,WAAW,CAAC,gBAAgB,CAAC,uBAAuB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;QACtF,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC;YAC9C,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,wDAAwD;IACxD,KAAK,MAAM,KAAK,IAAI,gBAAgB,EAAE,CAAC;QACrC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC;YACpC,OAAO,QAAQ,CAAC;gBACd,eAAe,EAAE,KAAK;gBACtB,aAAa;gBACb,aAAa,EAAE,EAAC,GAAG,EAAE,GAAyB,EAAC;aAChD,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;QACd,eAAe,EAAE,IAAI;QACrB,aAAa;KACd,CAAC,CAAC;AACL,CAAC","sourcesContent":["// Copyright 2024 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 Helpers from '../helpers/helpers.js';\nimport type * as Types from '../types/types.js';\n\nimport {\n InsightCategory,\n InsightKeys,\n type InsightModel,\n type InsightSetContext,\n InsightWarning,\n type PartialInsightModel,\n type RequiredData,\n} from './types.js';\n\nexport const UIStrings = {\n /** Title of an insight that provides details about if the page's viewport is optimized for mobile viewing. */\n title: 'Optimize viewport for mobile',\n /**\n * @description Text to tell the user how a viewport meta element can improve performance. \\xa0 is a non-breaking space\n */\n description:\n 'Tap interactions may be [delayed by up to 300\\xA0ms](https://developer.chrome.com/blog/300ms-tap-delay-gone-away/) if the viewport is not optimized for mobile.',\n} as const;\n\nconst str_ = i18n.i18n.registerUIStrings('models/trace/insights/Viewport.ts', UIStrings);\nexport const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);\n\nexport function deps(): ['Meta', 'UserInteractions'] {\n return ['Meta', 'UserInteractions'];\n}\n\nexport type ViewportInsightModel = InsightModel<typeof UIStrings, {\n mobileOptimized: boolean | null,\n viewportEvent?: Types.Events.ParseMetaViewport,\n}>;\n\nfunction finalize(partialModel: PartialInsightModel<ViewportInsightModel>): ViewportInsightModel {\n return {\n insightKey: InsightKeys.VIEWPORT,\n strings: UIStrings,\n title: i18nString(UIStrings.title),\n description: i18nString(UIStrings.description),\n category: InsightCategory.INP,\n state: partialModel.mobileOptimized === false ? 'fail' : 'pass',\n ...partialModel,\n };\n}\n\nexport function generateInsight(\n parsedTrace: RequiredData<typeof deps>, context: InsightSetContext): ViewportInsightModel {\n const compositorEvents = parsedTrace.UserInteractions.beginCommitCompositorFrameEvents.filter(event => {\n if (event.args.frame !== context.frameId) {\n return false;\n }\n\n return Helpers.Timing.eventIsInBounds(event, context.bounds);\n });\n\n if (!compositorEvents.length) {\n // Trace doesn't have the data we need.\n return finalize({\n mobileOptimized: null,\n warnings: [InsightWarning.NO_LAYOUT],\n });\n }\n\n const viewportEvent = parsedTrace.UserInteractions.parseMetaViewportEvents.find(event => {\n if (event.args.data.frame !== context.frameId) {\n return false;\n }\n\n return Helpers.Timing.eventIsInBounds(event, context.bounds);\n });\n\n // Returns true only if all events are mobile optimized.\n for (const event of compositorEvents) {\n if (!event.args.is_mobile_optimized) {\n return finalize({\n mobileOptimized: false,\n viewportEvent,\n metricSavings: {INP: 300 as Types.Timing.Milli},\n });\n }\n }\n\n return finalize({\n mobileOptimized: true,\n viewportEvent,\n });\n}\n"]}
@@ -33,14 +33,15 @@
33
33
  "../../../../../../../front_end/models/trace/insights/Common.ts",
34
34
  "../../../../../../../front_end/models/trace/insights/DOMSize.ts",
35
35
  "../../../../../../../front_end/models/trace/insights/DocumentLatency.ts",
36
+ "../../../../../../../front_end/models/trace/insights/DuplicateJavaScript.ts",
36
37
  "../../../../../../../front_end/models/trace/insights/FontDisplay.ts",
37
38
  "../../../../../../../front_end/models/trace/insights/ForcedReflow.ts",
38
39
  "../../../../../../../front_end/models/trace/insights/ImageDelivery.ts",
39
40
  "../../../../../../../front_end/models/trace/insights/InteractionToNextPaint.ts",
40
41
  "../../../../../../../front_end/models/trace/insights/LCPDiscovery.ts",
41
42
  "../../../../../../../front_end/models/trace/insights/LCPPhases.ts",
42
- "../../../../../../../front_end/models/trace/insights/LongCriticalNetworkTree.ts",
43
43
  "../../../../../../../front_end/models/trace/insights/Models.ts",
44
+ "../../../../../../../front_end/models/trace/insights/NetworkDependencyTree.ts",
44
45
  "../../../../../../../front_end/models/trace/insights/RenderBlocking.ts",
45
46
  "../../../../../../../front_end/models/trace/insights/SlowCSSSelector.ts",
46
47
  "../../../../../../../front_end/models/trace/insights/Statistics.ts",
@@ -62,18 +62,23 @@ export type Checklist<Keys extends string> = Record<Keys, {
62
62
  value: boolean;
63
63
  }>;
64
64
  export type InsightModel<UIStrings extends Record<string, string>, R extends Record<string, unknown>> = R & {
65
+ /** Used internally to identify the type of a model, not shown visibly to users **/
66
+ insightKey: keyof InsightModelsType;
65
67
  /** Not used within DevTools - this is for external consumers (like Lighthouse). */
66
68
  strings: UIStrings;
67
69
  title: {i18nId: string, values: {[key: string]: string|number}, formattedDefault: string};
68
70
  description: {i18nId: string, values: {[key: string]: string|number}, formattedDefault: string};
69
71
  category: InsightCategory;
70
- /** True if there is anything of interest to display to the user. */
71
- shouldShow: boolean;
72
+ state: 'pass' | 'fail' | 'informative';
72
73
  relatedEvents?: RelatedEventsMap | Types.Events.Event[];
73
74
  warnings?: InsightWarning[];
74
75
  metricSavings?: MetricSavings;
76
+ /**
77
+ * If this insight is attached to a navigation, this stores its ID.
78
+ */
79
+ navigationId?: string;
75
80
  };
76
- export type PartialInsightModel<T> = Omit<T, 'strings' | 'title' | 'description' | 'category' | 'shouldShow'>;
81
+ export type PartialInsightModel<T> = Omit<T, 'strings' | 'title' | 'description' | 'category' | 'state' | 'insightKey' | 'navigationId'>;
77
82
  /**
78
83
  * Contains insights for a specific navigation. If a trace began after a navigation already started,
79
84
  * this could instead represent the duration from the beginning of the trace up to the first recorded
@@ -106,3 +111,20 @@ export type TraceInsightSets = Map<Types.Events.NavigationId, InsightSet>;
106
111
  * Represents the narrow set of dependencies defined by an insight's `deps()` function. `Meta` is always included regardless of `deps()`.
107
112
  */
108
113
  export type RequiredData<D extends () => Array<keyof typeof Handlers.ModelHandlers>> = Handlers.Types.EnabledHandlerDataWithMeta<Pick<typeof Handlers.ModelHandlers, ReturnType<D>[number]>>;
114
+ export declare const enum InsightKeys {
115
+ LCP_PHASES = "LCPPhases",
116
+ INTERACTION_TO_NEXT_PAINT = "InteractionToNextPaint",
117
+ CLS_CULPRITS = "CLSCulprits",
118
+ THIRD_PARTIES = "ThirdParties",
119
+ DOCUMENT_LATENCY = "DocumentLatency",
120
+ DOM_SIZE = "DOMSize",
121
+ DUPLICATE_JAVASCRIPT = "DuplicateJavaScript",
122
+ FONT_DISPLAY = "FontDisplay",
123
+ FORCED_REFLOW = "ForcedReflow",
124
+ IMAGE_DELIVERY = "ImageDelivery",
125
+ LCP_DISCOVERY = "LCPDiscovery",
126
+ NETWORK_DEPENDENCY_TREE = "NetworkDependencyTree",
127
+ RENDER_BLOCKING = "RenderBlocking",
128
+ SLOW_CSS_SELECTOR = "SlowCSSSelector",
129
+ VIEWPORT = "Viewport"
130
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/types.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,yEAAyE;AACzE,6BAA6B;AAkD7B,MAAM,CAAN,IAAY,cAMX;AAND,WAAY,cAAc;IACxB,iCAAe,CAAA;IACf,mCAAiB,CAAA;IACjB,uEAAuE;IACvE,6DAA2C,CAAA;IAC3C,yCAAuB,CAAA;AACzB,CAAC,EANW,cAAc,KAAd,cAAc,QAMzB;AAYD,MAAM,CAAN,IAAY,eAKX;AALD,WAAY,eAAe;IACzB,8BAAW,CAAA;IACX,8BAAW,CAAA;IACX,8BAAW,CAAA;IACX,8BAAW,CAAA;AACb,CAAC,EALW,eAAe,KAAf,eAAe,QAK1B","sourcesContent":["// Copyright 2024 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 type * as Common from '../../../core/common/common.js';\nimport type * as Protocol from '../../../generated/protocol.js';\nimport type * as Handlers from '../handlers/handlers.js';\nimport type * as Lantern from '../lantern/lantern.js';\nimport type * as Types from '../types/types.js';\n\nimport type * as Models from './Models.js';\n\n/**\n * Context for the portion of the trace an insight should look at.\n */\nexport type InsightSetContext = InsightSetContextWithoutNavigation|InsightSetContextWithNavigation;\n\nexport interface InsightSetContextWithoutNavigation {\n bounds: Types.Timing.TraceWindowMicro;\n frameId: string;\n navigation?: never;\n}\n\nexport interface InsightSetContextWithNavigation {\n bounds: Types.Timing.TraceWindowMicro;\n frameId: string;\n navigation: Types.Events.NavigationStart;\n navigationId: string;\n lantern?: LanternContext;\n}\n\nexport interface LanternContext {\n graph: Lantern.Graph.Node<Types.Events.SyntheticNetworkRequest>;\n simulator: Lantern.Simulation.Simulator<Types.Events.SyntheticNetworkRequest>;\n metrics: Record<string, Lantern.Metrics.MetricResult>;\n}\n\nexport interface ForcedReflowAggregatedData {\n topLevelFunctionCall: Types.Events.CallFrame|Protocol.Runtime.CallFrame;\n totalReflowTime: number;\n bottomUpData: Set<string>;\n topLevelFunctionCallEvents: Types.Events.Event[];\n}\n\nexport interface BottomUpCallStack {\n bottomUpData: Types.Events.CallFrame|Protocol.Runtime.CallFrame;\n totalTime: number;\n relatedEvents: Types.Events.Event[];\n}\n\nexport type InsightModelsType = typeof Models;\n\nexport enum InsightWarning {\n NO_FP = 'NO_FP',\n NO_LCP = 'NO_LCP',\n // No network request could be identified as the primary HTML document.\n NO_DOCUMENT_REQUEST = 'NO_DOCUMENT_REQUEST',\n NO_LAYOUT = 'NO_LAYOUT',\n}\n\nexport interface MetricSavings {\n /* eslint-disable @typescript-eslint/naming-convention */\n FCP?: Types.Timing.Milli;\n LCP?: Types.Timing.Milli;\n TBT?: Types.Timing.Milli;\n CLS?: number;\n INP?: Types.Timing.Milli;\n /* eslint-enable @typescript-eslint/naming-convention */\n}\n\nexport enum InsightCategory {\n ALL = 'All',\n INP = 'INP',\n LCP = 'LCP',\n CLS = 'CLS',\n}\n\nexport type RelatedEventsMap = Map<Types.Events.Event, string[]>;\n\nexport type Checklist<Keys extends string> = Record<Keys, {label: Common.UIString.LocalizedString, value: boolean}>;\n\nexport type InsightModel<UIStrings extends Record<string, string>, R extends Record<string, unknown>> = R&{\n /** Not used within DevTools - this is for external consumers (like Lighthouse). */\n strings: UIStrings,\n title: Common.UIString.LocalizedString,\n description: Common.UIString.LocalizedString,\n category: InsightCategory,\n /** True if there is anything of interest to display to the user. */\n shouldShow: boolean,\n relatedEvents?: RelatedEventsMap | Types.Events.Event[],\n warnings?: InsightWarning[],\n metricSavings?: MetricSavings,\n};\n\nexport type PartialInsightModel<T> = Omit<T, 'strings'|'title'|'description'|'category'|'shouldShow'>;\n\n/**\n * Contains insights for a specific navigation. If a trace began after a navigation already started,\n * this could instead represent the duration from the beginning of the trace up to the first recorded\n * navigation (or the end of the trace).\n */\nexport interface InsightSet {\n /** If for a navigation, this is the navigationId. Else it is Trace.Types.Events.NO_NAVIGATION. */\n id: Types.Events.NavigationId;\n /** The URL to show in the accordion list. */\n url: URL;\n frameId: string;\n bounds: Types.Timing.TraceWindowMicro;\n model: InsightModels;\n navigation?: Types.Events.NavigationStart;\n}\n\n/**\n * Contains insights for a specific insight set.\n */\nexport type InsightModels = {\n [I in keyof InsightModelsType]: ReturnType<InsightModelsType[I]['generateInsight']>;\n};\n\n/**\n * Contains insights for the entire trace. Insights are mostly grouped by `navigationId`, with one exception:\n *\n * If the analyzed trace started after the navigation, and has meaningful work with that span, there is no\n * navigation to map it to. In this case `Types.Events.NO_NAVIGATION` is used for the key.\n */\nexport type TraceInsightSets = Map<Types.Events.NavigationId, InsightSet>;\n\n/**\n * Represents the narrow set of dependencies defined by an insight's `deps()` function. `Meta` is always included regardless of `deps()`.\n */\nexport type RequiredData<D extends() => Array<keyof typeof Handlers.ModelHandlers>> =\n Handlers.Types.EnabledHandlerDataWithMeta<Pick<typeof Handlers.ModelHandlers, ReturnType<D>[number]>>;\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/types.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,yEAAyE;AACzE,6BAA6B;AAkD7B,MAAM,CAAN,IAAY,cAMX;AAND,WAAY,cAAc;IACxB,iCAAe,CAAA;IACf,mCAAiB,CAAA;IACjB,uEAAuE;IACvE,6DAA2C,CAAA;IAC3C,yCAAuB,CAAA;AACzB,CAAC,EANW,cAAc,KAAd,cAAc,QAMzB;AAYD,MAAM,CAAN,IAAY,eAKX;AALD,WAAY,eAAe;IACzB,8BAAW,CAAA;IACX,8BAAW,CAAA;IACX,8BAAW,CAAA;IACX,8BAAW,CAAA;AACb,CAAC,EALW,eAAe,KAAf,eAAe,QAK1B","sourcesContent":["// Copyright 2024 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 type * as Common from '../../../core/common/common.js';\nimport type * as Protocol from '../../../generated/protocol.js';\nimport type * as Handlers from '../handlers/handlers.js';\nimport type * as Lantern from '../lantern/lantern.js';\nimport type * as Types from '../types/types.js';\n\nimport type * as Models from './Models.js';\n\n/**\n * Context for the portion of the trace an insight should look at.\n */\nexport type InsightSetContext = InsightSetContextWithoutNavigation|InsightSetContextWithNavigation;\n\nexport interface InsightSetContextWithoutNavigation {\n bounds: Types.Timing.TraceWindowMicro;\n frameId: string;\n navigation?: never;\n}\n\nexport interface InsightSetContextWithNavigation {\n bounds: Types.Timing.TraceWindowMicro;\n frameId: string;\n navigation: Types.Events.NavigationStart;\n navigationId: string;\n lantern?: LanternContext;\n}\n\nexport interface LanternContext {\n graph: Lantern.Graph.Node<Types.Events.SyntheticNetworkRequest>;\n simulator: Lantern.Simulation.Simulator<Types.Events.SyntheticNetworkRequest>;\n metrics: Record<string, Lantern.Metrics.MetricResult>;\n}\n\nexport interface ForcedReflowAggregatedData {\n topLevelFunctionCall: Types.Events.CallFrame|Protocol.Runtime.CallFrame;\n totalReflowTime: number;\n bottomUpData: Set<string>;\n topLevelFunctionCallEvents: Types.Events.Event[];\n}\n\nexport interface BottomUpCallStack {\n bottomUpData: Types.Events.CallFrame|Protocol.Runtime.CallFrame;\n totalTime: number;\n relatedEvents: Types.Events.Event[];\n}\n\nexport type InsightModelsType = typeof Models;\n\nexport enum InsightWarning {\n NO_FP = 'NO_FP',\n NO_LCP = 'NO_LCP',\n // No network request could be identified as the primary HTML document.\n NO_DOCUMENT_REQUEST = 'NO_DOCUMENT_REQUEST',\n NO_LAYOUT = 'NO_LAYOUT',\n}\n\nexport interface MetricSavings {\n /* eslint-disable @typescript-eslint/naming-convention */\n FCP?: Types.Timing.Milli;\n LCP?: Types.Timing.Milli;\n TBT?: Types.Timing.Milli;\n CLS?: number;\n INP?: Types.Timing.Milli;\n /* eslint-enable @typescript-eslint/naming-convention */\n}\n\nexport enum InsightCategory {\n ALL = 'All',\n INP = 'INP',\n LCP = 'LCP',\n CLS = 'CLS',\n}\n\nexport type RelatedEventsMap = Map<Types.Events.Event, string[]>;\n\nexport type Checklist<Keys extends string> = Record<Keys, {label: Common.UIString.LocalizedString, value: boolean}>;\n\nexport type InsightModel<UIStrings extends Record<string, string>, R extends Record<string, unknown>> = R&{\n /** Used internally to identify the type of a model, not shown visibly to users **/\n insightKey: keyof InsightModelsType,\n /** Not used within DevTools - this is for external consumers (like Lighthouse). */\n strings: UIStrings,\n title: Common.UIString.LocalizedString,\n description: Common.UIString.LocalizedString,\n category: InsightCategory,\n state: 'pass' | 'fail' | 'informative',\n relatedEvents?: RelatedEventsMap | Types.Events.Event[],\n warnings?: InsightWarning[],\n metricSavings?: MetricSavings,\n /**\n * If this insight is attached to a navigation, this stores its ID.\n */\n navigationId?: string,\n};\n\nexport type PartialInsightModel<T> =\n Omit<T, 'strings'|'title'|'description'|'category'|'state'|'insightKey'|'navigationId'>;\n\n/**\n * Contains insights for a specific navigation. If a trace began after a navigation already started,\n * this could instead represent the duration from the beginning of the trace up to the first recorded\n * navigation (or the end of the trace).\n */\nexport interface InsightSet {\n /** If for a navigation, this is the navigationId. Else it is Trace.Types.Events.NO_NAVIGATION. */\n id: Types.Events.NavigationId;\n /** The URL to show in the accordion list. */\n url: URL;\n frameId: string;\n bounds: Types.Timing.TraceWindowMicro;\n model: InsightModels;\n navigation?: Types.Events.NavigationStart;\n}\n\n/**\n * Contains insights for a specific insight set.\n */\nexport type InsightModels = {\n [I in keyof InsightModelsType]: ReturnType<InsightModelsType[I]['generateInsight']>;\n};\n\n/**\n * Contains insights for the entire trace. Insights are mostly grouped by `navigationId`, with one exception:\n *\n * If the analyzed trace started after the navigation, and has meaningful work with that span, there is no\n * navigation to map it to. In this case `Types.Events.NO_NAVIGATION` is used for the key.\n */\nexport type TraceInsightSets = Map<Types.Events.NavigationId, InsightSet>;\n\n/**\n * Represents the narrow set of dependencies defined by an insight's `deps()` function. `Meta` is always included regardless of `deps()`.\n */\nexport type RequiredData<D extends() => Array<keyof typeof Handlers.ModelHandlers>> =\n Handlers.Types.EnabledHandlerDataWithMeta<Pick<typeof Handlers.ModelHandlers, ReturnType<D>[number]>>;\n\nexport const enum InsightKeys {\n LCP_PHASES = 'LCPPhases',\n INTERACTION_TO_NEXT_PAINT = 'InteractionToNextPaint',\n CLS_CULPRITS = 'CLSCulprits',\n THIRD_PARTIES = 'ThirdParties',\n DOCUMENT_LATENCY = 'DocumentLatency',\n DOM_SIZE = 'DOMSize',\n DUPLICATE_JAVASCRIPT = 'DuplicateJavaScript',\n FONT_DISPLAY = 'FontDisplay',\n FORCED_REFLOW = 'ForcedReflow',\n IMAGE_DELIVERY = 'ImageDelivery',\n LCP_DISCOVERY = 'LCPDiscovery',\n NETWORK_DEPENDENCY_TREE = 'NetworkDependencyTree',\n RENDER_BLOCKING = 'RenderBlocking',\n SLOW_CSS_SELECTOR = 'SlowCSSSelector',\n VIEWPORT = 'Viewport',\n}\n"]}
@@ -101,8 +101,8 @@ declare class NetworkAnalyzer {
101
101
  serverResponseTimeByOrigin: Map<string, number>;
102
102
  };
103
103
  static analyze(records: Lantern.NetworkRequest[]): Lantern.Simulation.Settings['networkAnalysis'] | null;
104
- static findResourceForUrl<T extends Lantern.NetworkRequest>(records: Array<T>, resourceUrl: string): T | undefined;
105
- static findLastDocumentForUrl<T extends Lantern.NetworkRequest>(records: Array<T>, resourceUrl: string): T | undefined;
104
+ static findResourceForUrl<T extends Lantern.NetworkRequest>(records: T[], resourceUrl: string): T | undefined;
105
+ static findLastDocumentForUrl<T extends Lantern.NetworkRequest>(records: T[], resourceUrl: string): T | undefined;
106
106
  /**
107
107
  * Resolves redirect chain given a main document.
108
108
  * See: {@link NetworkAnalyzer.findLastDocumentForUrl} for how to retrieve main document.
@@ -9,7 +9,7 @@ class UrlUtils {
9
9
  * As a result, the network URL (chrome://chrome/settings/) doesn't match the final document URL (chrome://settings/).
10
10
  */
11
11
  static rewriteChromeInternalUrl(url) {
12
- if (!url || !url.startsWith('chrome://')) {
12
+ if (!url?.startsWith('chrome://')) {
13
13
  return url;
14
14
  }
15
15
  // Chrome adds a trailing slash to `chrome://` URLs, but the spec does not.
@@ -365,7 +365,7 @@ class NetworkAnalyzer {
365
365
  * estimated automatically if not provided.
366
366
  */
367
367
  static estimateServerResponseTimeByOrigin(records, options) {
368
- let rttByOrigin = (options || {}).rttByOrigin;
368
+ let rttByOrigin = options?.rttByOrigin;
369
369
  if (!rttByOrigin) {
370
370
  rttByOrigin = new Map();
371
371
  const rttSummaryByOrigin = NetworkAnalyzer.estimateRTTByOrigin(records, options);
@@ -1 +1 @@
1
- {"version":3,"file":"NetworkAnalyzer.js","sourceRoot":"","sources":["../../../../../../../../front_end/models/trace/lantern/core/NetworkAnalyzer.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 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 type * as Lantern from '../types/types.js';\n\nimport {LanternError} from './LanternError.js';\n\nclass UrlUtils {\n /**\n * There is fancy URL rewriting logic for the chrome://settings page that we need to work around.\n * Why? Special handling was added by Chrome team to allow a pushState transition between chrome:// pages.\n * As a result, the network URL (chrome://chrome/settings/) doesn't match the final document URL (chrome://settings/).\n */\n static rewriteChromeInternalUrl(url: string): string {\n if (!url || !url.startsWith('chrome://')) {\n return url;\n }\n // Chrome adds a trailing slash to `chrome://` URLs, but the spec does not.\n // https://github.com/GoogleChrome/lighthouse/pull/3941#discussion_r154026009\n if (url.endsWith('/')) {\n url = url.replace(/\\/$/, '');\n }\n return url.replace(/^chrome:\\/\\/chrome\\//, 'chrome://');\n }\n\n /**\n * Determine if url1 equals url2, ignoring URL fragments.\n */\n static equalWithExcludedFragments(url1: string, url2: string): boolean {\n [url1, url2] = [url1, url2].map(this.rewriteChromeInternalUrl);\n try {\n const urla = new URL(url1);\n urla.hash = '';\n\n const urlb = new URL(url2);\n urlb.hash = '';\n\n return urla.href === urlb.href;\n } catch {\n return false;\n }\n }\n}\n\ninterface Summary {\n min: number;\n max: number;\n avg: number;\n median: number;\n}\n\ninterface RTTEstimateOptions {\n /**\n * TCP connection handshake information will be used when available, but in\n * some circumstances this data can be unreliable. This flag exposes an\n * option to ignore the handshake data and use the coarse download/TTFB timing data.\n */\n forceCoarseEstimates?: boolean;\n /**\n * Coarse estimates include lots of extra time and noise multiply by some factor\n * to deflate the estimates a bit.\n */\n coarseEstimateMultiplier?: number;\n /** Useful for testing to isolate the different methods of estimation. */\n useDownloadEstimates?: boolean;\n /** Useful for testing to isolate the different methods of estimation. */\n useSendStartEstimates?: boolean;\n /** Useful for testing to isolate the different methods of estimation. */\n useHeadersEndEstimates?: boolean;\n}\n\ninterface RequestInfo {\n request: Lantern.NetworkRequest;\n timing: Lantern.ResourceTiming;\n connectionReused?: boolean;\n}\n\nconst INITIAL_CWD = 14 * 1024;\n\n// Assume that 40% of TTFB was server response time by default for static assets\nconst DEFAULT_SERVER_RESPONSE_PERCENTAGE = 0.4;\n\n/**\n * For certain resource types, server response time takes up a greater percentage of TTFB (dynamic\n * assets like HTML documents, XHR/API calls, etc)\n */\nconst SERVER_RESPONSE_PERCENTAGE_OF_TTFB: Partial<Record<Lantern.ResourceType, number>> = {\n Document: 0.9,\n XHR: 0.9,\n Fetch: 0.9,\n};\n\nclass NetworkAnalyzer {\n static get summary(): string {\n return '__SUMMARY__';\n }\n\n static groupByOrigin(records: Lantern.NetworkRequest[]): Map<string, Lantern.NetworkRequest[]> {\n const grouped = new Map();\n records.forEach(item => {\n const key = item.parsedURL.securityOrigin;\n const group = grouped.get(key) || [];\n group.push(item);\n grouped.set(key, group);\n });\n return grouped;\n }\n\n static getSummary(values: number[]): Summary {\n values.sort((a, b) => a - b);\n\n let median;\n if (values.length === 0) {\n median = values[0];\n } else if (values.length % 2 === 0) {\n const a = values[Math.floor((values.length - 1) / 2)];\n const b = values[Math.floor((values.length - 1) / 2) + 1];\n median = (a + b) / 2;\n } else {\n median = values[Math.floor((values.length - 1) / 2)];\n }\n\n return {\n min: values[0],\n max: values[values.length - 1],\n avg: values.reduce((a, b) => a + b, 0) / values.length,\n median,\n };\n }\n\n static summarize(values: Map<string, number[]>): Map<string, Summary> {\n const summaryByKey = new Map();\n const allEstimates = [];\n for (const [key, estimates] of values) {\n summaryByKey.set(key, NetworkAnalyzer.getSummary(estimates));\n allEstimates.push(...estimates);\n }\n\n summaryByKey.set(NetworkAnalyzer.summary, NetworkAnalyzer.getSummary(allEstimates));\n return summaryByKey;\n }\n\n static estimateValueByOrigin(\n requests: Lantern.NetworkRequest[],\n iteratee: (e: RequestInfo) => number | number[] | undefined): Map<string, number[]> {\n const connectionWasReused = NetworkAnalyzer.estimateIfConnectionWasReused(requests);\n const groupedByOrigin = NetworkAnalyzer.groupByOrigin(requests);\n\n const estimates = new Map();\n for (const [origin, originRequests] of groupedByOrigin.entries()) {\n let originEstimates: number[] = [];\n\n for (const request of originRequests) {\n const timing = request.timing;\n if (!timing) {\n continue;\n }\n\n const value = iteratee({\n request,\n timing,\n connectionReused: connectionWasReused.get(request.requestId),\n });\n if (typeof value !== 'undefined') {\n originEstimates = originEstimates.concat(value);\n }\n }\n\n if (!originEstimates.length) {\n continue;\n }\n estimates.set(origin, originEstimates);\n }\n\n return estimates;\n }\n\n /**\n * Estimates the observed RTT to each origin based on how long the connection setup.\n * For h1 and h2, this could includes two estimates - one for the TCP handshake, another for\n * SSL negotiation.\n * For h3, we get only one estimate since QUIC establishes a secure connection in a\n * single handshake.\n * This is the most accurate and preferred method of measurement when the data is available.\n */\n static estimateRTTViaConnectionTiming(info: RequestInfo): number[]|number|undefined {\n const {timing, connectionReused, request} = info;\n if (connectionReused) {\n return;\n }\n\n const {connectStart, sslStart, sslEnd, connectEnd} = timing;\n if (connectEnd >= 0 && connectStart >= 0 && request.protocol.startsWith('h3')) {\n // These values are equal to sslStart and sslEnd for h3.\n return connectEnd - connectStart;\n }\n if (sslStart >= 0 && sslEnd >= 0 && sslStart !== connectStart) {\n // SSL can also be more than 1 RT but assume False Start was used.\n return [connectEnd - sslStart, sslStart - connectStart];\n }\n if (connectStart >= 0 && connectEnd >= 0) {\n return connectEnd - connectStart;\n }\n\n return;\n }\n\n /**\n * Estimates the observed RTT to each origin based on how long a download took on a fresh connection.\n * NOTE: this will tend to overestimate the actual RTT quite significantly as the download can be\n * slow for other reasons as well such as bandwidth constraints.\n */\n static estimateRTTViaDownloadTiming(info: RequestInfo): number|undefined {\n const {timing, connectionReused, request} = info;\n if (connectionReused) {\n return;\n }\n\n // Only look at downloads that went past the initial congestion window\n if (request.transferSize <= INITIAL_CWD) {\n return;\n }\n if (!Number.isFinite(timing.receiveHeadersEnd) || timing.receiveHeadersEnd < 0) {\n return;\n }\n\n // Compute the amount of time downloading everything after the first congestion window took\n const totalTime = request.networkEndTime - request.networkRequestTime;\n const downloadTimeAfterFirstByte = totalTime - timing.receiveHeadersEnd;\n const numberOfRoundTrips = Math.log2(request.transferSize / INITIAL_CWD);\n\n // Ignore requests that required a high number of round trips since bandwidth starts to play\n // a larger role than latency\n if (numberOfRoundTrips > 5) {\n return;\n }\n\n return downloadTimeAfterFirstByte / numberOfRoundTrips;\n }\n\n /**\n * Estimates the observed RTT to each origin based on how long it took until Chrome could\n * start sending the actual request when a new connection was required.\n * NOTE: this will tend to overestimate the actual RTT as the request can be delayed for other\n * reasons as well such as more SSL handshakes if TLS False Start is not enabled.\n */\n static estimateRTTViaSendStartTiming(info: RequestInfo): number|undefined {\n const {timing, connectionReused, request} = info;\n if (connectionReused) {\n return;\n }\n\n if (!Number.isFinite(timing.sendStart) || timing.sendStart < 0) {\n return;\n }\n\n // Assume everything before sendStart was just DNS + (SSL)? + TCP handshake\n // 1 RT for DNS, 1 RT (maybe) for SSL, 1 RT for TCP\n let roundTrips = 1;\n // TCP\n if (!request.protocol.startsWith('h3')) {\n roundTrips += 1;\n }\n if (request.parsedURL.scheme === 'https') {\n roundTrips += 1;\n }\n return timing.sendStart / roundTrips;\n }\n\n /**\n * Estimates the observed RTT to each origin based on how long it took until Chrome received the\n * headers of the response (~TTFB).\n * NOTE: this is the most inaccurate way to estimate the RTT, but in some environments it's all\n * we have access to :(\n */\n static estimateRTTViaHeadersEndTiming(info: RequestInfo): number|undefined {\n const {timing, connectionReused, request} = info;\n if (!Number.isFinite(timing.receiveHeadersEnd) || timing.receiveHeadersEnd < 0) {\n return;\n }\n if (!request.resourceType) {\n return;\n }\n\n const serverResponseTimePercentage =\n SERVER_RESPONSE_PERCENTAGE_OF_TTFB[request.resourceType] || DEFAULT_SERVER_RESPONSE_PERCENTAGE;\n const estimatedServerResponseTime = timing.receiveHeadersEnd * serverResponseTimePercentage;\n\n // When connection was reused...\n // TTFB = 1 RT for request + server response time\n let roundTrips = 1;\n\n // When connection was fresh...\n // TTFB = DNS + (SSL)? + TCP handshake + 1 RT for request + server response time\n if (!connectionReused) {\n roundTrips += 1; // DNS\n if (!request.protocol.startsWith('h3')) {\n roundTrips += 1; // TCP\n }\n if (request.parsedURL.scheme === 'https') {\n roundTrips += 1; // SSL\n }\n }\n\n // subtract out our estimated server response time\n return Math.max((timing.receiveHeadersEnd - estimatedServerResponseTime) / roundTrips, 3);\n }\n\n /**\n * Given the RTT to each origin, estimates the observed server response times.\n */\n static estimateResponseTimeByOrigin(records: Lantern.NetworkRequest[], rttByOrigin: Map<string, number>):\n Map<string, number[]> {\n return NetworkAnalyzer.estimateValueByOrigin(records, ({request, timing}) => {\n if (request.serverResponseTime !== undefined) {\n return request.serverResponseTime;\n }\n\n if (!Number.isFinite(timing.receiveHeadersEnd) || timing.receiveHeadersEnd < 0) {\n return;\n }\n if (!Number.isFinite(timing.sendEnd) || timing.sendEnd < 0) {\n return;\n }\n\n const ttfb = timing.receiveHeadersEnd - timing.sendEnd;\n const origin = request.parsedURL.securityOrigin;\n const rtt = rttByOrigin.get(origin) || rttByOrigin.get(NetworkAnalyzer.summary) || 0;\n return Math.max(ttfb - rtt, 0);\n });\n }\n\n static canTrustConnectionInformation(requests: Lantern.NetworkRequest[]): boolean {\n const connectionIdWasStarted = new Map();\n for (const request of requests) {\n const started = connectionIdWasStarted.get(request.connectionId) || !request.connectionReused;\n connectionIdWasStarted.set(request.connectionId, started);\n }\n\n // We probably can't trust the network information if all the connection IDs were the same\n if (connectionIdWasStarted.size <= 1) {\n return false;\n }\n // Or if there were connections that were always reused (a connection had to have started at some point)\n return Array.from(connectionIdWasStarted.values()).every(started => started);\n }\n\n /**\n * Returns a map of requestId -> connectionReused, estimating the information if the information\n * available in the records themselves appears untrustworthy.\n */\n static estimateIfConnectionWasReused(records: Lantern.NetworkRequest[], options?: {forceCoarseEstimates: boolean}):\n Map<string, boolean> {\n const {forceCoarseEstimates = false} = options || {};\n\n // Check if we can trust the connection information coming from the protocol\n if (!forceCoarseEstimates && NetworkAnalyzer.canTrustConnectionInformation(records)) {\n return new Map(records.map(request => [request.requestId, Boolean(request.connectionReused)]));\n }\n\n // Otherwise we're on our own, a request may not have needed a fresh connection if...\n // - It was not the first request to the domain\n // - It was H2\n // - It was after the first request to the domain ended\n const connectionWasReused = new Map();\n const groupedByOrigin = NetworkAnalyzer.groupByOrigin(records);\n for (const originRecords of groupedByOrigin.values()) {\n const earliestReusePossible =\n originRecords.map(request => request.networkEndTime).reduce((a, b) => Math.min(a, b), Infinity);\n\n for (const request of originRecords) {\n connectionWasReused.set(\n request.requestId,\n request.networkRequestTime >= earliestReusePossible || request.protocol === 'h2',\n );\n }\n\n const firstRecord = originRecords.reduce((a, b) => {\n return a.networkRequestTime > b.networkRequestTime ? b : a;\n });\n connectionWasReused.set(firstRecord.requestId, false);\n }\n\n return connectionWasReused;\n }\n\n /**\n * Estimates the RTT to each origin by examining observed network timing information.\n * Attempts to use the most accurate information first and falls back to coarser estimates when it\n * is unavailable.\n */\n static estimateRTTByOrigin(records: Lantern.NetworkRequest[], options?: RTTEstimateOptions): Map<string, Summary> {\n const {\n forceCoarseEstimates = false,\n // coarse estimates include lots of extra time and noise\n // multiply by some factor to deflate the estimates a bit.\n coarseEstimateMultiplier = 0.3,\n useDownloadEstimates = true,\n useSendStartEstimates = true,\n useHeadersEndEstimates = true,\n } = options || {};\n\n const connectionWasReused = NetworkAnalyzer.estimateIfConnectionWasReused(records);\n const groupedByOrigin = NetworkAnalyzer.groupByOrigin(records);\n\n const estimatesByOrigin = new Map();\n for (const [origin, originRequests] of groupedByOrigin.entries()) {\n const originEstimates: number[] = [];\n\n function collectEstimates(estimator: (e: RequestInfo) => number[] | number | undefined, multiplier = 1): void {\n for (const request of originRequests) {\n const timing = request.timing;\n if (!timing || !request.transferSize) {\n continue;\n }\n\n const estimates = estimator({\n request,\n timing,\n connectionReused: connectionWasReused.get(request.requestId),\n });\n if (estimates === undefined) {\n continue;\n }\n\n if (!Array.isArray(estimates)) {\n originEstimates.push(estimates * multiplier);\n } else {\n originEstimates.push(...estimates.map(e => e * multiplier));\n }\n }\n }\n\n if (!forceCoarseEstimates) {\n collectEstimates(this.estimateRTTViaConnectionTiming);\n }\n\n // Connection timing can be missing for a few reasons:\n // - Origin was preconnected, which we don't have instrumentation for.\n // - Trace began recording after a connection has already been established (for example, in timespan mode)\n // - Perhaps Chrome established a connection already in the background (service worker? Just guessing here)\n // - Not provided in LR netstack.\n if (!originEstimates.length) {\n if (useDownloadEstimates) {\n collectEstimates(this.estimateRTTViaDownloadTiming, coarseEstimateMultiplier);\n }\n if (useSendStartEstimates) {\n collectEstimates(this.estimateRTTViaSendStartTiming, coarseEstimateMultiplier);\n }\n if (useHeadersEndEstimates) {\n collectEstimates(this.estimateRTTViaHeadersEndTiming, coarseEstimateMultiplier);\n }\n }\n\n if (originEstimates.length) {\n estimatesByOrigin.set(origin, originEstimates);\n }\n }\n\n if (!estimatesByOrigin.size) {\n throw new LanternError('No timing information available');\n }\n return NetworkAnalyzer.summarize(estimatesByOrigin);\n }\n\n /**\n * Estimates the server response time of each origin. RTT times can be passed in or will be\n * estimated automatically if not provided.\n */\n static estimateServerResponseTimeByOrigin(records: Lantern.NetworkRequest[], options?: RTTEstimateOptions&{\n rttByOrigin?: Map<string, number>,\n }): Map<string, Summary> {\n let rttByOrigin = (options || {}).rttByOrigin;\n if (!rttByOrigin) {\n rttByOrigin = new Map();\n\n const rttSummaryByOrigin = NetworkAnalyzer.estimateRTTByOrigin(records, options);\n for (const [origin, summary] of rttSummaryByOrigin.entries()) {\n rttByOrigin.set(origin, summary.min);\n }\n }\n\n const estimatesByOrigin = NetworkAnalyzer.estimateResponseTimeByOrigin(records, rttByOrigin);\n return NetworkAnalyzer.summarize(estimatesByOrigin);\n }\n\n /**\n * Computes the average throughput for the given requests in bits/second.\n * Excludes data URI, failed or otherwise incomplete, and cached requests.\n * Returns null if there were no analyzable network requests.\n */\n static estimateThroughput(records: Lantern.NetworkRequest[]): number|null {\n let totalBytes = 0;\n\n // We will measure throughput by summing the total bytes downloaded by the total time spent\n // downloading those bytes. We slice up all the network requests into start/end boundaries, so\n // it's easier to deal with the gaps in downloading.\n const timeBoundaries = records\n .reduce(\n (boundaries, request) => {\n const scheme = request.parsedURL?.scheme;\n // Requests whose bodies didn't come over the network or didn't completely finish will mess\n // with the computation, just skip over them.\n if (scheme === 'data' || request.failed || !request.finished ||\n request.statusCode > 300 || !request.transferSize) {\n return boundaries;\n }\n\n // If we've made it this far, all the times we need should be valid (i.e. not undefined/-1).\n totalBytes += request.transferSize;\n boundaries.push({time: request.responseHeadersEndTime / 1000, isStart: true});\n boundaries.push({time: request.networkEndTime / 1000, isStart: false});\n return boundaries;\n },\n [] as Array<{time: number, isStart: boolean}>)\n .sort((a, b) => a.time - b.time);\n\n if (!timeBoundaries.length) {\n return null;\n }\n\n let inflight = 0;\n let currentStart = 0;\n let totalDuration = 0;\n\n timeBoundaries.forEach(boundary => {\n if (boundary.isStart) {\n if (inflight === 0) {\n // We just ended a quiet period, keep track of when the download period started\n currentStart = boundary.time;\n }\n inflight++;\n } else {\n inflight--;\n if (inflight === 0) {\n // We just entered a quiet period, update our duration with the time we spent downloading\n totalDuration += boundary.time - currentStart;\n }\n }\n });\n\n return totalBytes * 8 / totalDuration;\n }\n\n static computeRTTAndServerResponseTime(records: Lantern.NetworkRequest[]):\n {rtt: number, additionalRttByOrigin: Map<string, number>, serverResponseTimeByOrigin: Map<string, number>} {\n // First pass compute the estimated observed RTT to each origin's servers.\n const rttByOrigin = new Map<string, number>();\n for (const [origin, summary] of NetworkAnalyzer.estimateRTTByOrigin(records).entries()) {\n rttByOrigin.set(origin, summary.min);\n }\n\n // We'll use the minimum RTT as the assumed connection latency since we care about how much addt'l\n // latency each origin introduces as Lantern will be simulating with its own connection latency.\n const minimumRtt = Math.min(...Array.from(rttByOrigin.values()));\n // We'll use the observed RTT information to help estimate the server response time\n const responseTimeSummaries = NetworkAnalyzer.estimateServerResponseTimeByOrigin(records, {\n rttByOrigin,\n });\n\n const additionalRttByOrigin = new Map<string, number>();\n const serverResponseTimeByOrigin = new Map<string, number>();\n for (const [origin, summary] of responseTimeSummaries.entries()) {\n // Not all origins have usable timing data, we'll default to using no additional latency.\n const rttForOrigin = rttByOrigin.get(origin) || minimumRtt;\n additionalRttByOrigin.set(origin, rttForOrigin - minimumRtt);\n serverResponseTimeByOrigin.set(origin, summary.median);\n }\n\n return {\n rtt: minimumRtt,\n additionalRttByOrigin,\n serverResponseTimeByOrigin,\n };\n }\n\n static analyze(records: Lantern.NetworkRequest[]): Lantern.Simulation.Settings['networkAnalysis']|null {\n const throughput = NetworkAnalyzer.estimateThroughput(records);\n if (throughput === null) {\n return null;\n }\n\n return {\n throughput,\n ...NetworkAnalyzer.computeRTTAndServerResponseTime(records),\n };\n }\n\n static findResourceForUrl<T extends Lantern.NetworkRequest>(records: Array<T>, resourceUrl: string): T|undefined {\n // equalWithExcludedFragments is expensive, so check that the resourceUrl starts with the request url first\n return records.find(\n request => resourceUrl.startsWith(request.url) && UrlUtils.equalWithExcludedFragments(request.url, resourceUrl),\n );\n }\n\n static findLastDocumentForUrl<T extends Lantern.NetworkRequest>(records: Array<T>, resourceUrl: string): T|undefined {\n // equalWithExcludedFragments is expensive, so check that the resourceUrl starts with the request url first\n const matchingRequests = records.filter(\n request => request.resourceType === 'Document' && !request.failed &&\n // Note: `request.url` should never have a fragment, else this optimization gives wrong results.\n resourceUrl.startsWith(request.url) && UrlUtils.equalWithExcludedFragments(request.url, resourceUrl),\n );\n return matchingRequests[matchingRequests.length - 1];\n }\n\n /**\n * Resolves redirect chain given a main document.\n * See: {@link NetworkAnalyzer.findLastDocumentForUrl} for how to retrieve main document.\n */\n static resolveRedirects<T extends Lantern.NetworkRequest>(request: T): T {\n while (request.redirectDestination) {\n request = request.redirectDestination as T;\n }\n return request;\n }\n}\n\nexport {NetworkAnalyzer};\n"]}
1
+ {"version":3,"file":"NetworkAnalyzer.js","sourceRoot":"","sources":["../../../../../../../../front_end/models/trace/lantern/core/NetworkAnalyzer.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 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 type * as Lantern from '../types/types.js';\n\nimport {LanternError} from './LanternError.js';\n\nclass UrlUtils {\n /**\n * There is fancy URL rewriting logic for the chrome://settings page that we need to work around.\n * Why? Special handling was added by Chrome team to allow a pushState transition between chrome:// pages.\n * As a result, the network URL (chrome://chrome/settings/) doesn't match the final document URL (chrome://settings/).\n */\n static rewriteChromeInternalUrl(url: string): string {\n if (!url?.startsWith('chrome://')) {\n return url;\n }\n // Chrome adds a trailing slash to `chrome://` URLs, but the spec does not.\n // https://github.com/GoogleChrome/lighthouse/pull/3941#discussion_r154026009\n if (url.endsWith('/')) {\n url = url.replace(/\\/$/, '');\n }\n return url.replace(/^chrome:\\/\\/chrome\\//, 'chrome://');\n }\n\n /**\n * Determine if url1 equals url2, ignoring URL fragments.\n */\n static equalWithExcludedFragments(url1: string, url2: string): boolean {\n [url1, url2] = [url1, url2].map(this.rewriteChromeInternalUrl);\n try {\n const urla = new URL(url1);\n urla.hash = '';\n\n const urlb = new URL(url2);\n urlb.hash = '';\n\n return urla.href === urlb.href;\n } catch {\n return false;\n }\n }\n}\n\ninterface Summary {\n min: number;\n max: number;\n avg: number;\n median: number;\n}\n\ninterface RTTEstimateOptions {\n /**\n * TCP connection handshake information will be used when available, but in\n * some circumstances this data can be unreliable. This flag exposes an\n * option to ignore the handshake data and use the coarse download/TTFB timing data.\n */\n forceCoarseEstimates?: boolean;\n /**\n * Coarse estimates include lots of extra time and noise multiply by some factor\n * to deflate the estimates a bit.\n */\n coarseEstimateMultiplier?: number;\n /** Useful for testing to isolate the different methods of estimation. */\n useDownloadEstimates?: boolean;\n /** Useful for testing to isolate the different methods of estimation. */\n useSendStartEstimates?: boolean;\n /** Useful for testing to isolate the different methods of estimation. */\n useHeadersEndEstimates?: boolean;\n}\n\ninterface RequestInfo {\n request: Lantern.NetworkRequest;\n timing: Lantern.ResourceTiming;\n connectionReused?: boolean;\n}\n\nconst INITIAL_CWD = 14 * 1024;\n\n// Assume that 40% of TTFB was server response time by default for static assets\nconst DEFAULT_SERVER_RESPONSE_PERCENTAGE = 0.4;\n\n/**\n * For certain resource types, server response time takes up a greater percentage of TTFB (dynamic\n * assets like HTML documents, XHR/API calls, etc)\n */\nconst SERVER_RESPONSE_PERCENTAGE_OF_TTFB: Partial<Record<Lantern.ResourceType, number>> = {\n Document: 0.9,\n XHR: 0.9,\n Fetch: 0.9,\n};\n\nclass NetworkAnalyzer {\n static get summary(): string {\n return '__SUMMARY__';\n }\n\n static groupByOrigin(records: Lantern.NetworkRequest[]): Map<string, Lantern.NetworkRequest[]> {\n const grouped = new Map();\n records.forEach(item => {\n const key = item.parsedURL.securityOrigin;\n const group = grouped.get(key) || [];\n group.push(item);\n grouped.set(key, group);\n });\n return grouped;\n }\n\n static getSummary(values: number[]): Summary {\n values.sort((a, b) => a - b);\n\n let median;\n if (values.length === 0) {\n median = values[0];\n } else if (values.length % 2 === 0) {\n const a = values[Math.floor((values.length - 1) / 2)];\n const b = values[Math.floor((values.length - 1) / 2) + 1];\n median = (a + b) / 2;\n } else {\n median = values[Math.floor((values.length - 1) / 2)];\n }\n\n return {\n min: values[0],\n max: values[values.length - 1],\n avg: values.reduce((a, b) => a + b, 0) / values.length,\n median,\n };\n }\n\n static summarize(values: Map<string, number[]>): Map<string, Summary> {\n const summaryByKey = new Map();\n const allEstimates = [];\n for (const [key, estimates] of values) {\n summaryByKey.set(key, NetworkAnalyzer.getSummary(estimates));\n allEstimates.push(...estimates);\n }\n\n summaryByKey.set(NetworkAnalyzer.summary, NetworkAnalyzer.getSummary(allEstimates));\n return summaryByKey;\n }\n\n static estimateValueByOrigin(\n requests: Lantern.NetworkRequest[],\n iteratee: (e: RequestInfo) => number | number[] | undefined): Map<string, number[]> {\n const connectionWasReused = NetworkAnalyzer.estimateIfConnectionWasReused(requests);\n const groupedByOrigin = NetworkAnalyzer.groupByOrigin(requests);\n\n const estimates = new Map();\n for (const [origin, originRequests] of groupedByOrigin.entries()) {\n let originEstimates: number[] = [];\n\n for (const request of originRequests) {\n const timing = request.timing;\n if (!timing) {\n continue;\n }\n\n const value = iteratee({\n request,\n timing,\n connectionReused: connectionWasReused.get(request.requestId),\n });\n if (typeof value !== 'undefined') {\n originEstimates = originEstimates.concat(value);\n }\n }\n\n if (!originEstimates.length) {\n continue;\n }\n estimates.set(origin, originEstimates);\n }\n\n return estimates;\n }\n\n /**\n * Estimates the observed RTT to each origin based on how long the connection setup.\n * For h1 and h2, this could includes two estimates - one for the TCP handshake, another for\n * SSL negotiation.\n * For h3, we get only one estimate since QUIC establishes a secure connection in a\n * single handshake.\n * This is the most accurate and preferred method of measurement when the data is available.\n */\n static estimateRTTViaConnectionTiming(info: RequestInfo): number[]|number|undefined {\n const {timing, connectionReused, request} = info;\n if (connectionReused) {\n return;\n }\n\n const {connectStart, sslStart, sslEnd, connectEnd} = timing;\n if (connectEnd >= 0 && connectStart >= 0 && request.protocol.startsWith('h3')) {\n // These values are equal to sslStart and sslEnd for h3.\n return connectEnd - connectStart;\n }\n if (sslStart >= 0 && sslEnd >= 0 && sslStart !== connectStart) {\n // SSL can also be more than 1 RT but assume False Start was used.\n return [connectEnd - sslStart, sslStart - connectStart];\n }\n if (connectStart >= 0 && connectEnd >= 0) {\n return connectEnd - connectStart;\n }\n\n return;\n }\n\n /**\n * Estimates the observed RTT to each origin based on how long a download took on a fresh connection.\n * NOTE: this will tend to overestimate the actual RTT quite significantly as the download can be\n * slow for other reasons as well such as bandwidth constraints.\n */\n static estimateRTTViaDownloadTiming(info: RequestInfo): number|undefined {\n const {timing, connectionReused, request} = info;\n if (connectionReused) {\n return;\n }\n\n // Only look at downloads that went past the initial congestion window\n if (request.transferSize <= INITIAL_CWD) {\n return;\n }\n if (!Number.isFinite(timing.receiveHeadersEnd) || timing.receiveHeadersEnd < 0) {\n return;\n }\n\n // Compute the amount of time downloading everything after the first congestion window took\n const totalTime = request.networkEndTime - request.networkRequestTime;\n const downloadTimeAfterFirstByte = totalTime - timing.receiveHeadersEnd;\n const numberOfRoundTrips = Math.log2(request.transferSize / INITIAL_CWD);\n\n // Ignore requests that required a high number of round trips since bandwidth starts to play\n // a larger role than latency\n if (numberOfRoundTrips > 5) {\n return;\n }\n\n return downloadTimeAfterFirstByte / numberOfRoundTrips;\n }\n\n /**\n * Estimates the observed RTT to each origin based on how long it took until Chrome could\n * start sending the actual request when a new connection was required.\n * NOTE: this will tend to overestimate the actual RTT as the request can be delayed for other\n * reasons as well such as more SSL handshakes if TLS False Start is not enabled.\n */\n static estimateRTTViaSendStartTiming(info: RequestInfo): number|undefined {\n const {timing, connectionReused, request} = info;\n if (connectionReused) {\n return;\n }\n\n if (!Number.isFinite(timing.sendStart) || timing.sendStart < 0) {\n return;\n }\n\n // Assume everything before sendStart was just DNS + (SSL)? + TCP handshake\n // 1 RT for DNS, 1 RT (maybe) for SSL, 1 RT for TCP\n let roundTrips = 1;\n // TCP\n if (!request.protocol.startsWith('h3')) {\n roundTrips += 1;\n }\n if (request.parsedURL.scheme === 'https') {\n roundTrips += 1;\n }\n return timing.sendStart / roundTrips;\n }\n\n /**\n * Estimates the observed RTT to each origin based on how long it took until Chrome received the\n * headers of the response (~TTFB).\n * NOTE: this is the most inaccurate way to estimate the RTT, but in some environments it's all\n * we have access to :(\n */\n static estimateRTTViaHeadersEndTiming(info: RequestInfo): number|undefined {\n const {timing, connectionReused, request} = info;\n if (!Number.isFinite(timing.receiveHeadersEnd) || timing.receiveHeadersEnd < 0) {\n return;\n }\n if (!request.resourceType) {\n return;\n }\n\n const serverResponseTimePercentage =\n SERVER_RESPONSE_PERCENTAGE_OF_TTFB[request.resourceType] || DEFAULT_SERVER_RESPONSE_PERCENTAGE;\n const estimatedServerResponseTime = timing.receiveHeadersEnd * serverResponseTimePercentage;\n\n // When connection was reused...\n // TTFB = 1 RT for request + server response time\n let roundTrips = 1;\n\n // When connection was fresh...\n // TTFB = DNS + (SSL)? + TCP handshake + 1 RT for request + server response time\n if (!connectionReused) {\n roundTrips += 1; // DNS\n if (!request.protocol.startsWith('h3')) {\n roundTrips += 1; // TCP\n }\n if (request.parsedURL.scheme === 'https') {\n roundTrips += 1; // SSL\n }\n }\n\n // subtract out our estimated server response time\n return Math.max((timing.receiveHeadersEnd - estimatedServerResponseTime) / roundTrips, 3);\n }\n\n /**\n * Given the RTT to each origin, estimates the observed server response times.\n */\n static estimateResponseTimeByOrigin(records: Lantern.NetworkRequest[], rttByOrigin: Map<string, number>):\n Map<string, number[]> {\n return NetworkAnalyzer.estimateValueByOrigin(records, ({request, timing}) => {\n if (request.serverResponseTime !== undefined) {\n return request.serverResponseTime;\n }\n\n if (!Number.isFinite(timing.receiveHeadersEnd) || timing.receiveHeadersEnd < 0) {\n return;\n }\n if (!Number.isFinite(timing.sendEnd) || timing.sendEnd < 0) {\n return;\n }\n\n const ttfb = timing.receiveHeadersEnd - timing.sendEnd;\n const origin = request.parsedURL.securityOrigin;\n const rtt = rttByOrigin.get(origin) || rttByOrigin.get(NetworkAnalyzer.summary) || 0;\n return Math.max(ttfb - rtt, 0);\n });\n }\n\n static canTrustConnectionInformation(requests: Lantern.NetworkRequest[]): boolean {\n const connectionIdWasStarted = new Map();\n for (const request of requests) {\n const started = connectionIdWasStarted.get(request.connectionId) || !request.connectionReused;\n connectionIdWasStarted.set(request.connectionId, started);\n }\n\n // We probably can't trust the network information if all the connection IDs were the same\n if (connectionIdWasStarted.size <= 1) {\n return false;\n }\n // Or if there were connections that were always reused (a connection had to have started at some point)\n return Array.from(connectionIdWasStarted.values()).every(started => started);\n }\n\n /**\n * Returns a map of requestId -> connectionReused, estimating the information if the information\n * available in the records themselves appears untrustworthy.\n */\n static estimateIfConnectionWasReused(records: Lantern.NetworkRequest[], options?: {forceCoarseEstimates: boolean}):\n Map<string, boolean> {\n const {forceCoarseEstimates = false} = options || {};\n\n // Check if we can trust the connection information coming from the protocol\n if (!forceCoarseEstimates && NetworkAnalyzer.canTrustConnectionInformation(records)) {\n return new Map(records.map(request => [request.requestId, Boolean(request.connectionReused)]));\n }\n\n // Otherwise we're on our own, a request may not have needed a fresh connection if...\n // - It was not the first request to the domain\n // - It was H2\n // - It was after the first request to the domain ended\n const connectionWasReused = new Map();\n const groupedByOrigin = NetworkAnalyzer.groupByOrigin(records);\n for (const originRecords of groupedByOrigin.values()) {\n const earliestReusePossible =\n originRecords.map(request => request.networkEndTime).reduce((a, b) => Math.min(a, b), Infinity);\n\n for (const request of originRecords) {\n connectionWasReused.set(\n request.requestId,\n request.networkRequestTime >= earliestReusePossible || request.protocol === 'h2',\n );\n }\n\n const firstRecord = originRecords.reduce((a, b) => {\n return a.networkRequestTime > b.networkRequestTime ? b : a;\n });\n connectionWasReused.set(firstRecord.requestId, false);\n }\n\n return connectionWasReused;\n }\n\n /**\n * Estimates the RTT to each origin by examining observed network timing information.\n * Attempts to use the most accurate information first and falls back to coarser estimates when it\n * is unavailable.\n */\n static estimateRTTByOrigin(records: Lantern.NetworkRequest[], options?: RTTEstimateOptions): Map<string, Summary> {\n const {\n forceCoarseEstimates = false,\n // coarse estimates include lots of extra time and noise\n // multiply by some factor to deflate the estimates a bit.\n coarseEstimateMultiplier = 0.3,\n useDownloadEstimates = true,\n useSendStartEstimates = true,\n useHeadersEndEstimates = true,\n } = options || {};\n\n const connectionWasReused = NetworkAnalyzer.estimateIfConnectionWasReused(records);\n const groupedByOrigin = NetworkAnalyzer.groupByOrigin(records);\n\n const estimatesByOrigin = new Map();\n for (const [origin, originRequests] of groupedByOrigin.entries()) {\n const originEstimates: number[] = [];\n\n function collectEstimates(estimator: (e: RequestInfo) => number[] | number | undefined, multiplier = 1): void {\n for (const request of originRequests) {\n const timing = request.timing;\n if (!timing || !request.transferSize) {\n continue;\n }\n\n const estimates = estimator({\n request,\n timing,\n connectionReused: connectionWasReused.get(request.requestId),\n });\n if (estimates === undefined) {\n continue;\n }\n\n if (!Array.isArray(estimates)) {\n originEstimates.push(estimates * multiplier);\n } else {\n originEstimates.push(...estimates.map(e => e * multiplier));\n }\n }\n }\n\n if (!forceCoarseEstimates) {\n collectEstimates(this.estimateRTTViaConnectionTiming);\n }\n\n // Connection timing can be missing for a few reasons:\n // - Origin was preconnected, which we don't have instrumentation for.\n // - Trace began recording after a connection has already been established (for example, in timespan mode)\n // - Perhaps Chrome established a connection already in the background (service worker? Just guessing here)\n // - Not provided in LR netstack.\n if (!originEstimates.length) {\n if (useDownloadEstimates) {\n collectEstimates(this.estimateRTTViaDownloadTiming, coarseEstimateMultiplier);\n }\n if (useSendStartEstimates) {\n collectEstimates(this.estimateRTTViaSendStartTiming, coarseEstimateMultiplier);\n }\n if (useHeadersEndEstimates) {\n collectEstimates(this.estimateRTTViaHeadersEndTiming, coarseEstimateMultiplier);\n }\n }\n\n if (originEstimates.length) {\n estimatesByOrigin.set(origin, originEstimates);\n }\n }\n\n if (!estimatesByOrigin.size) {\n throw new LanternError('No timing information available');\n }\n return NetworkAnalyzer.summarize(estimatesByOrigin);\n }\n\n /**\n * Estimates the server response time of each origin. RTT times can be passed in or will be\n * estimated automatically if not provided.\n */\n static estimateServerResponseTimeByOrigin(records: Lantern.NetworkRequest[], options?: RTTEstimateOptions&{\n rttByOrigin?: Map<string, number>,\n }): Map<string, Summary> {\n let rttByOrigin = options?.rttByOrigin;\n if (!rttByOrigin) {\n rttByOrigin = new Map();\n\n const rttSummaryByOrigin = NetworkAnalyzer.estimateRTTByOrigin(records, options);\n for (const [origin, summary] of rttSummaryByOrigin.entries()) {\n rttByOrigin.set(origin, summary.min);\n }\n }\n\n const estimatesByOrigin = NetworkAnalyzer.estimateResponseTimeByOrigin(records, rttByOrigin);\n return NetworkAnalyzer.summarize(estimatesByOrigin);\n }\n\n /**\n * Computes the average throughput for the given requests in bits/second.\n * Excludes data URI, failed or otherwise incomplete, and cached requests.\n * Returns null if there were no analyzable network requests.\n */\n static estimateThroughput(records: Lantern.NetworkRequest[]): number|null {\n let totalBytes = 0;\n\n // We will measure throughput by summing the total bytes downloaded by the total time spent\n // downloading those bytes. We slice up all the network requests into start/end boundaries, so\n // it's easier to deal with the gaps in downloading.\n const timeBoundaries = records\n .reduce(\n (boundaries, request) => {\n const scheme = request.parsedURL?.scheme;\n // Requests whose bodies didn't come over the network or didn't completely finish will mess\n // with the computation, just skip over them.\n if (scheme === 'data' || request.failed || !request.finished ||\n request.statusCode > 300 || !request.transferSize) {\n return boundaries;\n }\n\n // If we've made it this far, all the times we need should be valid (i.e. not undefined/-1).\n totalBytes += request.transferSize;\n boundaries.push({time: request.responseHeadersEndTime / 1000, isStart: true});\n boundaries.push({time: request.networkEndTime / 1000, isStart: false});\n return boundaries;\n },\n [] as Array<{time: number, isStart: boolean}>)\n .sort((a, b) => a.time - b.time);\n\n if (!timeBoundaries.length) {\n return null;\n }\n\n let inflight = 0;\n let currentStart = 0;\n let totalDuration = 0;\n\n timeBoundaries.forEach(boundary => {\n if (boundary.isStart) {\n if (inflight === 0) {\n // We just ended a quiet period, keep track of when the download period started\n currentStart = boundary.time;\n }\n inflight++;\n } else {\n inflight--;\n if (inflight === 0) {\n // We just entered a quiet period, update our duration with the time we spent downloading\n totalDuration += boundary.time - currentStart;\n }\n }\n });\n\n return totalBytes * 8 / totalDuration;\n }\n\n static computeRTTAndServerResponseTime(records: Lantern.NetworkRequest[]):\n {rtt: number, additionalRttByOrigin: Map<string, number>, serverResponseTimeByOrigin: Map<string, number>} {\n // First pass compute the estimated observed RTT to each origin's servers.\n const rttByOrigin = new Map<string, number>();\n for (const [origin, summary] of NetworkAnalyzer.estimateRTTByOrigin(records).entries()) {\n rttByOrigin.set(origin, summary.min);\n }\n\n // We'll use the minimum RTT as the assumed connection latency since we care about how much addt'l\n // latency each origin introduces as Lantern will be simulating with its own connection latency.\n const minimumRtt = Math.min(...Array.from(rttByOrigin.values()));\n // We'll use the observed RTT information to help estimate the server response time\n const responseTimeSummaries = NetworkAnalyzer.estimateServerResponseTimeByOrigin(records, {\n rttByOrigin,\n });\n\n const additionalRttByOrigin = new Map<string, number>();\n const serverResponseTimeByOrigin = new Map<string, number>();\n for (const [origin, summary] of responseTimeSummaries.entries()) {\n // Not all origins have usable timing data, we'll default to using no additional latency.\n const rttForOrigin = rttByOrigin.get(origin) || minimumRtt;\n additionalRttByOrigin.set(origin, rttForOrigin - minimumRtt);\n serverResponseTimeByOrigin.set(origin, summary.median);\n }\n\n return {\n rtt: minimumRtt,\n additionalRttByOrigin,\n serverResponseTimeByOrigin,\n };\n }\n\n static analyze(records: Lantern.NetworkRequest[]): Lantern.Simulation.Settings['networkAnalysis']|null {\n const throughput = NetworkAnalyzer.estimateThroughput(records);\n if (throughput === null) {\n return null;\n }\n\n return {\n throughput,\n ...NetworkAnalyzer.computeRTTAndServerResponseTime(records),\n };\n }\n\n static findResourceForUrl<T extends Lantern.NetworkRequest>(records: T[], resourceUrl: string): T|undefined {\n // equalWithExcludedFragments is expensive, so check that the resourceUrl starts with the request url first\n return records.find(\n request => resourceUrl.startsWith(request.url) && UrlUtils.equalWithExcludedFragments(request.url, resourceUrl),\n );\n }\n\n static findLastDocumentForUrl<T extends Lantern.NetworkRequest>(records: T[], resourceUrl: string): T|undefined {\n // equalWithExcludedFragments is expensive, so check that the resourceUrl starts with the request url first\n const matchingRequests = records.filter(\n request => request.resourceType === 'Document' && !request.failed &&\n // Note: `request.url` should never have a fragment, else this optimization gives wrong results.\n resourceUrl.startsWith(request.url) && UrlUtils.equalWithExcludedFragments(request.url, resourceUrl),\n );\n return matchingRequests[matchingRequests.length - 1];\n }\n\n /**\n * Resolves redirect chain given a main document.\n * See: {@link NetworkAnalyzer.findLastDocumentForUrl} for how to retrieve main document.\n */\n static resolveRedirects<T extends Lantern.NetworkRequest>(request: T): T {\n while (request.redirectDestination) {\n request = request.redirectDestination as T;\n }\n return request;\n }\n}\n\nexport {NetworkAnalyzer};\n"]}
@@ -78,7 +78,7 @@ declare class BaseNode<T = Lantern.AnyNetworkObject> {
78
78
  * The `getNextNodes` function takes a visited node and returns which nodes to
79
79
  * visit next. It defaults to returning the node's dependents.
80
80
  */
81
- traverse(callback: (node: Node<T>, traversalPath: Node<T>[]) => void, getNextNodes?: (arg0: Node<T>) => Node<T>[]): void;
81
+ traverse(callback: (node: Node<T>, traversalPath: Array<Node<T>>) => void, getNextNodes?: (arg0: Node<T>) => Array<Node<T>>): void;
82
82
  /**
83
83
  * @see BaseNode.traverse
84
84
  */