@paulirish/trace_engine 0.0.60 → 0.0.62

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 (302) hide show
  1. package/.tmp/tsbuildinfo/analyze-trace.d.mts.map +1 -1
  2. package/.tmp/tsbuildinfo/tsconfig.tsbuildinfo +1 -1
  3. package/analyze-inspector-issues.mjs +1 -1
  4. package/analyze-trace.mjs +1 -2
  5. package/core/platform/ArrayUtilities.d.ts +2 -0
  6. package/core/platform/ArrayUtilities.js +11 -1
  7. package/core/platform/ArrayUtilities.js.map +1 -1
  8. package/core/platform/HostRuntime.d.ts +4 -0
  9. package/core/platform/HostRuntime.js +25 -0
  10. package/core/platform/HostRuntime.js.map +1 -0
  11. package/core/platform/KeyboardUtilities.d.ts +6 -2
  12. package/core/platform/KeyboardUtilities.js.map +1 -1
  13. package/core/platform/StringUtilities.d.ts +2 -0
  14. package/core/platform/StringUtilities.js +64 -13
  15. package/core/platform/StringUtilities.js.map +1 -1
  16. package/core/platform/api/HostRuntime.d.ts +36 -0
  17. package/core/platform/api/HostRuntime.js +5 -0
  18. package/core/platform/api/HostRuntime.js.map +1 -0
  19. package/core/platform/api/api-tsconfig.json +43 -0
  20. package/core/platform/api/api.d.ts +2 -0
  21. package/core/platform/api/api.js +6 -0
  22. package/core/platform/api/api.js.map +1 -0
  23. package/core/platform/api/api_node_typecheck-tsconfig.json +48 -0
  24. package/core/platform/api/bundle-tsconfig.json +1 -0
  25. package/core/platform/api/devtools_entrypoint-bundle-typescript-tsconfig.json +48 -0
  26. package/core/platform/browser/HostRuntime.d.ts +2 -0
  27. package/core/platform/browser/HostRuntime.js +64 -0
  28. package/core/platform/browser/HostRuntime.js.map +1 -0
  29. package/core/platform/browser/browser-tsconfig.json +48 -0
  30. package/core/platform/browser/browser.d.ts +2 -0
  31. package/core/platform/browser/browser.js +6 -0
  32. package/core/platform/browser/browser.js.map +1 -0
  33. package/core/platform/browser/bundle-tsconfig.json +1 -0
  34. package/core/platform/browser/devtools_entrypoint-bundle-typescript-tsconfig.json +48 -0
  35. package/core/platform/devtools_entrypoint-bundle-typescript-tsconfig.json +4 -3
  36. package/core/platform/node/HostRuntime.d.ts +2 -0
  37. package/core/platform/node/HostRuntime.js +73 -0
  38. package/core/platform/node/HostRuntime.js.map +1 -0
  39. package/core/platform/node/bundle-tsconfig.json +1 -0
  40. package/core/platform/node/devtools_entrypoint-bundle-typescript-tsconfig.json +48 -0
  41. package/core/platform/node/node-tsconfig.json +52 -0
  42. package/core/platform/node/node.d.ts +2 -0
  43. package/core/platform/node/node.js +6 -0
  44. package/core/platform/node/node.js.map +1 -0
  45. package/core/platform/platform-tsconfig.json +17 -5
  46. package/core/platform/platform.d.ts +2 -2
  47. package/core/platform/platform.js +2 -2
  48. package/core/platform/platform.js.map +1 -1
  49. package/core/platform/platform_node_typecheck-tsconfig.json +74 -0
  50. package/generated/protocol.d.ts +1517 -592
  51. package/locales/af.json +83 -38
  52. package/locales/am.json +83 -38
  53. package/locales/ar.json +86 -41
  54. package/locales/as.json +83 -38
  55. package/locales/az.json +83 -38
  56. package/locales/be.json +81 -36
  57. package/locales/bg.json +81 -36
  58. package/locales/bn.json +83 -38
  59. package/locales/bs.json +82 -37
  60. package/locales/ca.json +81 -36
  61. package/locales/cs.json +81 -36
  62. package/locales/cy.json +83 -38
  63. package/locales/da.json +83 -38
  64. package/locales/de.json +81 -36
  65. package/locales/el.json +82 -37
  66. package/locales/en-GB.json +83 -38
  67. package/locales/en-US.json +104 -35
  68. package/locales/en-XL.json +104 -35
  69. package/locales/es-419.json +81 -36
  70. package/locales/es.json +82 -37
  71. package/locales/et.json +83 -38
  72. package/locales/eu.json +81 -36
  73. package/locales/fa.json +84 -39
  74. package/locales/fi.json +81 -36
  75. package/locales/fil.json +83 -38
  76. package/locales/fr-CA.json +82 -37
  77. package/locales/fr.json +168 -123
  78. package/locales/gl.json +82 -37
  79. package/locales/gu.json +82 -37
  80. package/locales/he.json +96 -51
  81. package/locales/hi.json +82 -37
  82. package/locales/hr.json +81 -36
  83. package/locales/hu.json +82 -37
  84. package/locales/hy.json +82 -37
  85. package/locales/id.json +83 -38
  86. package/locales/is.json +82 -37
  87. package/locales/it.json +81 -36
  88. package/locales/ja.json +81 -36
  89. package/locales/ka.json +83 -38
  90. package/locales/kk.json +81 -36
  91. package/locales/km.json +83 -38
  92. package/locales/kn.json +82 -37
  93. package/locales/ko.json +82 -37
  94. package/locales/ky.json +81 -36
  95. package/locales/lo.json +82 -37
  96. package/locales/lt.json +81 -36
  97. package/locales/lv.json +81 -36
  98. package/locales/mk.json +84 -39
  99. package/locales/ml.json +82 -37
  100. package/locales/mn.json +82 -37
  101. package/locales/mr.json +83 -38
  102. package/locales/ms.json +81 -36
  103. package/locales/my.json +82 -37
  104. package/locales/ne.json +82 -37
  105. package/locales/nl.json +82 -37
  106. package/locales/no.json +81 -36
  107. package/locales/or.json +81 -36
  108. package/locales/pa.json +81 -36
  109. package/locales/pl.json +81 -36
  110. package/locales/pt-PT.json +81 -36
  111. package/locales/pt.json +83 -38
  112. package/locales/ro.json +82 -37
  113. package/locales/ru.json +81 -36
  114. package/locales/si.json +81 -36
  115. package/locales/sk.json +81 -36
  116. package/locales/sl.json +81 -36
  117. package/locales/sq.json +82 -37
  118. package/locales/sr-Latn.json +82 -37
  119. package/locales/sr.json +82 -37
  120. package/locales/sv.json +84 -39
  121. package/locales/sw.json +83 -38
  122. package/locales/ta.json +82 -37
  123. package/locales/te.json +82 -37
  124. package/locales/th.json +82 -37
  125. package/locales/tr.json +81 -36
  126. package/locales/uk.json +81 -36
  127. package/locales/ur.json +82 -37
  128. package/locales/uz.json +82 -37
  129. package/locales/vi.json +83 -38
  130. package/locales/zh-HK.json +81 -36
  131. package/locales/zh-TW.json +84 -39
  132. package/locales/zh.json +84 -39
  133. package/locales/zu.json +82 -37
  134. package/models/cpu_profile/CPUProfileDataModel.d.ts +9 -0
  135. package/models/cpu_profile/CPUProfileDataModel.js +9 -7
  136. package/models/cpu_profile/CPUProfileDataModel.js.map +1 -1
  137. package/models/cpu_profile/ProfileTreeModel.d.ts +3 -2
  138. package/models/cpu_profile/ProfileTreeModel.js +6 -7
  139. package/models/cpu_profile/ProfileTreeModel.js.map +1 -1
  140. package/models/cpu_profile/cpu_profile-tsconfig.json +4 -3
  141. package/models/cpu_profile/devtools_entrypoint-bundle-typescript-tsconfig.json +4 -3
  142. package/models/trace/EntityMapper.d.ts +1 -0
  143. package/models/trace/EntityMapper.js +10 -0
  144. package/models/trace/EntityMapper.js.map +1 -1
  145. package/models/trace/EventsSerializer.js +10 -2
  146. package/models/trace/EventsSerializer.js.map +1 -1
  147. package/models/trace/LanternComputationData.d.ts +1 -1
  148. package/models/trace/LanternComputationData.js +3 -8
  149. package/models/trace/LanternComputationData.js.map +1 -1
  150. package/models/trace/ModelImpl.d.ts +1 -0
  151. package/models/trace/ModelImpl.js +9 -6
  152. package/models/trace/ModelImpl.js.map +1 -1
  153. package/models/trace/Processor.js +23 -23
  154. package/models/trace/Processor.js.map +1 -1
  155. package/models/trace/Styles.js +13 -5
  156. package/models/trace/Styles.js.map +1 -1
  157. package/models/trace/devtools_entrypoint-bundle-typescript-tsconfig.json +4 -3
  158. package/models/trace/extras/Initiators.d.ts +12 -0
  159. package/models/trace/extras/Initiators.js +47 -0
  160. package/models/trace/extras/Initiators.js.map +1 -0
  161. package/models/trace/extras/TraceTree.js +13 -5
  162. package/models/trace/extras/TraceTree.js.map +1 -1
  163. package/models/trace/extras/devtools_entrypoint-bundle-typescript-tsconfig.json +4 -3
  164. package/models/trace/extras/extras-tsconfig.json +11 -3
  165. package/models/trace/extras/extras.d.ts +0 -3979
  166. package/models/trace/extras/extras.js +0 -3979
  167. package/models/trace/extras/extras.js.map +1 -1
  168. package/models/trace/handlers/LargestImagePaintHandler.js +2 -2
  169. package/models/trace/handlers/LargestImagePaintHandler.js.map +1 -1
  170. package/models/trace/handlers/LayoutShiftsHandler.js +1 -1
  171. package/models/trace/handlers/LayoutShiftsHandler.js.map +1 -1
  172. package/models/trace/handlers/MetaHandler.d.ts +12 -1
  173. package/models/trace/handlers/MetaHandler.js +10 -1
  174. package/models/trace/handlers/MetaHandler.js.map +1 -1
  175. package/models/trace/handlers/NetworkRequestsHandler.d.ts +8 -1
  176. package/models/trace/handlers/NetworkRequestsHandler.js +22 -4
  177. package/models/trace/handlers/NetworkRequestsHandler.js.map +1 -1
  178. package/models/trace/handlers/PageLoadMetricsHandler.d.ts +13 -3
  179. package/models/trace/handlers/PageLoadMetricsHandler.js +71 -27
  180. package/models/trace/handlers/PageLoadMetricsHandler.js.map +1 -1
  181. package/models/trace/handlers/SamplesHandler.js +59 -6
  182. package/models/trace/handlers/SamplesHandler.js.map +1 -1
  183. package/models/trace/handlers/ScriptsHandler.js +24 -0
  184. package/models/trace/handlers/ScriptsHandler.js.map +1 -1
  185. package/models/trace/handlers/UserTimingsHandler.d.ts +1 -1
  186. package/models/trace/handlers/UserTimingsHandler.js +1 -1
  187. package/models/trace/handlers/UserTimingsHandler.js.map +1 -1
  188. package/models/trace/handlers/devtools_entrypoint-bundle-typescript-tsconfig.json +4 -3
  189. package/models/trace/handlers/handlers-tsconfig.json +13 -3
  190. package/models/trace/helpers/Network.js +1 -1
  191. package/models/trace/helpers/Network.js.map +1 -1
  192. package/models/trace/helpers/SamplesIntegrator.js +1 -8
  193. package/models/trace/helpers/SamplesIntegrator.js.map +1 -1
  194. package/models/trace/helpers/Timing.d.ts +1 -1
  195. package/models/trace/helpers/Timing.js +9 -2
  196. package/models/trace/helpers/Timing.js.map +1 -1
  197. package/models/trace/helpers/Trace.d.ts +1 -0
  198. package/models/trace/helpers/Trace.js +12 -5
  199. package/models/trace/helpers/Trace.js.map +1 -1
  200. package/models/trace/helpers/devtools_entrypoint-bundle-typescript-tsconfig.json +4 -3
  201. package/models/trace/helpers/helpers-tsconfig.json +7 -3
  202. package/models/trace/insights/CLSCulprits.d.ts +1 -1
  203. package/models/trace/insights/CLSCulprits.js +2 -1
  204. package/models/trace/insights/CLSCulprits.js.map +1 -1
  205. package/models/trace/insights/Cache.d.ts +1 -1
  206. package/models/trace/insights/Cache.js +2 -1
  207. package/models/trace/insights/Cache.js.map +1 -1
  208. package/models/trace/insights/CharacterSet.d.ts +49 -0
  209. package/models/trace/insights/CharacterSet.js +132 -0
  210. package/models/trace/insights/CharacterSet.js.map +1 -0
  211. package/models/trace/insights/Common.d.ts +2 -2
  212. package/models/trace/insights/Common.js +1 -6
  213. package/models/trace/insights/Common.js.map +1 -1
  214. package/models/trace/insights/DOMSize.d.ts +1 -1
  215. package/models/trace/insights/DOMSize.js +2 -1
  216. package/models/trace/insights/DOMSize.js.map +1 -1
  217. package/models/trace/insights/DocumentLatency.d.ts +1 -1
  218. package/models/trace/insights/DocumentLatency.js +2 -1
  219. package/models/trace/insights/DocumentLatency.js.map +1 -1
  220. package/models/trace/insights/DuplicatedJavaScript.d.ts +1 -1
  221. package/models/trace/insights/DuplicatedJavaScript.js +2 -1
  222. package/models/trace/insights/DuplicatedJavaScript.js.map +1 -1
  223. package/models/trace/insights/FontDisplay.d.ts +1 -1
  224. package/models/trace/insights/FontDisplay.js +2 -1
  225. package/models/trace/insights/FontDisplay.js.map +1 -1
  226. package/models/trace/insights/ForcedReflow.d.ts +2 -2
  227. package/models/trace/insights/ForcedReflow.js +3 -2
  228. package/models/trace/insights/ForcedReflow.js.map +1 -1
  229. package/models/trace/insights/INPBreakdown.d.ts +1 -1
  230. package/models/trace/insights/INPBreakdown.js +2 -1
  231. package/models/trace/insights/INPBreakdown.js.map +1 -1
  232. package/models/trace/insights/ImageDelivery.d.ts +1 -1
  233. package/models/trace/insights/ImageDelivery.js +2 -1
  234. package/models/trace/insights/ImageDelivery.js.map +1 -1
  235. package/models/trace/insights/LCPBreakdown.d.ts +2 -2
  236. package/models/trace/insights/LCPBreakdown.js +4 -3
  237. package/models/trace/insights/LCPBreakdown.js.map +1 -1
  238. package/models/trace/insights/LCPDiscovery.d.ts +8 -4
  239. package/models/trace/insights/LCPDiscovery.js +18 -11
  240. package/models/trace/insights/LCPDiscovery.js.map +1 -1
  241. package/models/trace/insights/LegacyJavaScript.d.ts +1 -1
  242. package/models/trace/insights/LegacyJavaScript.js +2 -1
  243. package/models/trace/insights/LegacyJavaScript.js.map +1 -1
  244. package/models/trace/insights/Models.d.ts +1 -0
  245. package/models/trace/insights/Models.js +1 -0
  246. package/models/trace/insights/Models.js.map +1 -1
  247. package/models/trace/insights/ModernHTTP.d.ts +1 -1
  248. package/models/trace/insights/ModernHTTP.js +2 -1
  249. package/models/trace/insights/ModernHTTP.js.map +1 -1
  250. package/models/trace/insights/NetworkDependencyTree.d.ts +1 -1
  251. package/models/trace/insights/NetworkDependencyTree.js +6 -4
  252. package/models/trace/insights/NetworkDependencyTree.js.map +1 -1
  253. package/models/trace/insights/RenderBlocking.d.ts +2 -2
  254. package/models/trace/insights/RenderBlocking.js +8 -7
  255. package/models/trace/insights/RenderBlocking.js.map +1 -1
  256. package/models/trace/insights/SlowCSSSelector.d.ts +1 -1
  257. package/models/trace/insights/SlowCSSSelector.js +2 -1
  258. package/models/trace/insights/SlowCSSSelector.js.map +1 -1
  259. package/models/trace/insights/ThirdParties.js +2 -1
  260. package/models/trace/insights/ThirdParties.js.map +1 -1
  261. package/models/trace/insights/Viewport.d.ts +1 -1
  262. package/models/trace/insights/Viewport.js +2 -1
  263. package/models/trace/insights/Viewport.js.map +1 -1
  264. package/models/trace/insights/devtools_entrypoint-bundle-typescript-tsconfig.json +4 -3
  265. package/models/trace/insights/insights-tsconfig.json +26 -3
  266. package/models/trace/insights/types.d.ts +17 -6
  267. package/models/trace/insights/types.js +1 -0
  268. package/models/trace/insights/types.js.map +1 -1
  269. package/models/trace/lantern/core/core-tsconfig.json +4 -3
  270. package/models/trace/lantern/core/devtools_entrypoint-bundle-typescript-tsconfig.json +4 -3
  271. package/models/trace/lantern/devtools_entrypoint-bundle-typescript-tsconfig.json +4 -3
  272. package/models/trace/lantern/graph/devtools_entrypoint-bundle-typescript-tsconfig.json +4 -3
  273. package/models/trace/lantern/graph/graph-tsconfig.json +4 -3
  274. package/models/trace/lantern/lantern-tsconfig.json +4 -3
  275. package/models/trace/lantern/metrics/FirstContentfulPaint.js +6 -6
  276. package/models/trace/lantern/metrics/FirstContentfulPaint.js.map +1 -1
  277. package/models/trace/lantern/metrics/devtools_entrypoint-bundle-typescript-tsconfig.json +4 -3
  278. package/models/trace/lantern/metrics/metrics-tsconfig.json +4 -3
  279. package/models/trace/lantern/simulation/devtools_entrypoint-bundle-typescript-tsconfig.json +4 -3
  280. package/models/trace/lantern/simulation/simulation-tsconfig.json +4 -3
  281. package/models/trace/lantern/types/Lantern.d.ts +7 -7
  282. package/models/trace/lantern/types/Lantern.js.map +1 -1
  283. package/models/trace/lantern/types/devtools_entrypoint-bundle-typescript-tsconfig.json +4 -3
  284. package/models/trace/lantern/types/types-tsconfig.json +4 -3
  285. package/models/trace/trace-tsconfig.json +7 -3
  286. package/models/trace/types/Configuration.d.ts +1 -4
  287. package/models/trace/types/Configuration.js +0 -1
  288. package/models/trace/types/Configuration.js.map +1 -1
  289. package/models/trace/types/File.d.ts +8 -0
  290. package/models/trace/types/File.js.map +1 -1
  291. package/models/trace/types/TraceEvents.d.ts +97 -15
  292. package/models/trace/types/TraceEvents.js +44 -11
  293. package/models/trace/types/TraceEvents.js.map +1 -1
  294. package/models/trace/types/devtools_entrypoint-bundle-typescript-tsconfig.json +4 -3
  295. package/models/trace/types/types-tsconfig.json +10 -3
  296. package/package.json +1 -1
  297. package/test/test-trace-engine.mjs +8 -9
  298. package/.tmp/tsbuildinfo/models/trace/extras/polyfills.d.ts +0 -4
  299. package/.tmp/tsbuildinfo/models/trace/extras/polyfills.d.ts.map +0 -1
  300. package/core/platform/DOMUtilities.d.ts +0 -16
  301. package/core/platform/DOMUtilities.js +0 -123
  302. package/core/platform/DOMUtilities.js.map +0 -1
@@ -9,12 +9,12 @@ export const UIStrings = {
9
9
  /**
10
10
  * @description Title of an insight that provides the user with the list of network requests that blocked and therefore slowed down the page rendering and becoming visible to the user.
11
11
  */
12
- title: 'Render blocking requests',
12
+ title: 'Render-blocking requests',
13
13
  /**
14
14
  * @description Text to describe that there are requests blocking rendering, which may affect LCP.
15
15
  */
16
16
  description: 'Requests are blocking the page\'s initial render, which may delay LCP. ' +
17
- '[Deferring or inlining](https://web.dev/learn/performance/understanding-the-critical-path#render-blocking_resources) ' +
17
+ '[Deferring or inlining](https://developer.chrome.com/docs/performance/insights/render-blocking) ' +
18
18
  'can move these network requests out of the critical path.',
19
19
  /**
20
20
  * @description Label to describe a network request (that happens to be render-blocking).
@@ -27,7 +27,7 @@ export const UIStrings = {
27
27
  /**
28
28
  * @description Text status indicating that no requests blocked the initial render of a navigation
29
29
  */
30
- noRenderBlocking: 'No render blocking requests for this navigation',
30
+ noRenderBlocking: 'No render-blocking requests for this navigation',
31
31
  };
32
32
  // const str_ = i18n.i18n.registerUIStrings('models/trace/insights/RenderBlocking.ts', UIStrings);
33
33
  export const i18nString = (i18nId, values) => ({i18nId, values}); // i18n.i18n.getLocalizedString.bind(undefined, str_);
@@ -104,7 +104,7 @@ function computeSavings(data, context, renderBlockingRequests) {
104
104
  }
105
105
  if (requestIdToWastedMs.size) {
106
106
  metricSavings.FCP = estimateSavingsWithGraphs(deferredNodeIds, context.lantern);
107
- // In most cases, render blocking resources only affect LCP if LCP isn't an image.
107
+ // In most cases, render-blocking resources only affect LCP if LCP isn't an image.
108
108
  if (!hasImageLCP(data, context)) {
109
109
  metricSavings.LCP = metricSavings.FCP;
110
110
  }
@@ -117,6 +117,7 @@ function finalize(partialModel) {
117
117
  strings: UIStrings,
118
118
  title: i18nString(UIStrings.title),
119
119
  description: i18nString(UIStrings.description),
120
+ docs: 'https://developer.chrome.com/docs/performance/insights/render-blocking',
120
121
  category: InsightCategory.LCP,
121
122
  state: partialModel.renderBlockingRequests.length > 0 ? 'fail' : 'pass',
122
123
  ...partialModel,
@@ -129,7 +130,7 @@ export function generateInsight(data, context) {
129
130
  });
130
131
  }
131
132
  const firstPaintTs = data.PageLoadMetrics.metricScoresByFrameId.get(context.frameId)
132
- ?.get(context.navigationId)
133
+ ?.get(context.navigation)
133
134
  ?.get(Handlers.ModelHandlers.PageLoadMetrics.MetricName.FP)
134
135
  ?.event?.ts;
135
136
  if (!firstPaintTs) {
@@ -149,12 +150,12 @@ export function generateInsight(data, context) {
149
150
  if (req.args.data.syntheticData.finishTime > firstPaintTs) {
150
151
  continue;
151
152
  }
152
- // If a request is marked `in_body_parser_blocking` it should only be considered render blocking if it is a
153
+ // If a request is marked `in_body_parser_blocking` it should only be considered render-blocking if it is a
153
154
  // high enough priority. Some requests (e.g. scripts) are not marked as high priority if they are fetched
154
155
  // after a non-preloaded image. (See "early" definition in https://web.dev/articles/fetch-priority)
155
156
  //
156
157
  // There are edge cases and exceptions (e.g. priority hints) but this gives us the best approximation
157
- // of render blocking resources in the document body.
158
+ // of render-blocking resources in the document body.
158
159
  if (req.args.data.renderBlocking === 'in_body_parser_blocking') {
159
160
  const priority = req.args.data.priority;
160
161
  const isScript = req.args.data.resourceType === "Script" /* Protocol.Network.ResourceType.Script */;
@@ -1 +1 @@
1
- {"version":3,"file":"RenderBlocking.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/RenderBlocking.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 The Chromium Authors\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 Protocol from '../../../generated/protocol.js';\nimport * as Handlers from '../handlers/handlers.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport type * as Lantern from '../lantern/lantern.js';\nimport type * as Types from '../types/types.js';\n\nimport {\n InsightCategory,\n InsightKeys,\n type InsightModel,\n type InsightSetContext,\n type InsightSetContextWithNavigation,\n InsightWarning,\n type LanternContext,\n type PartialInsightModel,\n} from './types.js';\n\nexport const UIStrings = {\n /**\n * @description Title of an insight that provides the user with the list of network requests that blocked and therefore slowed down the page rendering and becoming visible to the user.\n */\n title: 'Render blocking requests',\n /**\n * @description Text to describe that there are requests blocking rendering, which may affect LCP.\n */\n description: 'Requests are blocking the page\\'s initial render, which may delay LCP. ' +\n '[Deferring or inlining](https://web.dev/learn/performance/understanding-the-critical-path#render-blocking_resources) ' +\n 'can move these network requests out of the critical path.',\n /**\n * @description Label to describe a network request (that happens to be render-blocking).\n */\n renderBlockingRequest: 'Request',\n /**\n * @description Label used for a time duration.\n */\n duration: 'Duration',\n /**\n * @description Text status indicating that no requests blocked the initial render of a navigation\n */\n noRenderBlocking: 'No render blocking requests for this navigation',\n} as const;\n\nconst str_ = i18n.i18n.registerUIStrings('models/trace/insights/RenderBlocking.ts', UIStrings);\nexport const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);\n\nexport function isRenderBlockingInsight(insight: InsightModel): insight is RenderBlockingInsightModel {\n return insight.insightKey === 'RenderBlocking';\n}\n\nexport type RenderBlockingInsightModel = InsightModel<typeof UIStrings, {\n renderBlockingRequests: Types.Events.SyntheticNetworkRequest[],\n requestIdToWastedMs?: Map<string, number>,\n}>;\n\n// Because of the way we detect blocking stylesheets, asynchronously loaded\n// CSS with link[rel=preload] and an onload handler (see https://github.com/filamentgroup/loadCSS)\n// can be falsely flagged as blocking. Therefore, ignore stylesheets that loaded fast enough\n// to possibly be non-blocking (and they have minimal impact anyway).\nconst MINIMUM_WASTED_MS = 50;\n\n/**\n * Given a simulation's nodeTimings, return an object with the nodes/timing keyed by network URL\n */\nfunction getNodesAndTimingByRequestId(nodeTimings: Lantern.Simulation.Result['nodeTimings']):\n Map<string, {node: Lantern.Graph.Node, nodeTiming: Lantern.Types.Simulation.NodeTiming}> {\n const requestIdToNode =\n new Map<string, {node: Lantern.Graph.Node, nodeTiming: Lantern.Types.Simulation.NodeTiming}>();\n\n for (const [node, nodeTiming] of nodeTimings) {\n if (node.type !== 'network') {\n continue;\n }\n\n requestIdToNode.set(node.request.requestId, {node, nodeTiming});\n }\n\n return requestIdToNode;\n}\n\nfunction estimateSavingsWithGraphs(deferredIds: Set<string>, lanternContext: LanternContext): Types.Timing.Milli {\n const simulator = lanternContext.simulator;\n const fcpGraph = lanternContext.metrics.firstContentfulPaint.optimisticGraph;\n const {nodeTimings} = lanternContext.simulator.simulate(fcpGraph);\n const adjustedNodeTimings = new Map(nodeTimings);\n\n const totalChildNetworkBytes = 0;\n const minimalFCPGraph = fcpGraph.cloneWithRelationships(node => {\n // If a node can be deferred, exclude it from the new FCP graph\n const canDeferRequest = deferredIds.has(node.id);\n return !canDeferRequest;\n });\n\n if (minimalFCPGraph.type !== 'network') {\n throw new Error('minimalFCPGraph not a NetworkNode');\n }\n\n // Recalculate the \"before\" time based on our adjusted node timings.\n const estimateBeforeInline = Math.max(...Array.from(\n Array.from(adjustedNodeTimings).map(timing => timing[1].endTime),\n ));\n\n // Add the inlined bytes to the HTML response\n const originalTransferSize = minimalFCPGraph.request.transferSize;\n const safeTransferSize = originalTransferSize || 0;\n minimalFCPGraph.request.transferSize = safeTransferSize + totalChildNetworkBytes;\n const estimateAfterInline = simulator.simulate(minimalFCPGraph).timeInMs;\n minimalFCPGraph.request.transferSize = originalTransferSize;\n return Math.round(Math.max(estimateBeforeInline - estimateAfterInline, 0)) as Types.Timing.Milli;\n}\n\nfunction hasImageLCP(data: Handlers.Types.HandlerData, context: InsightSetContextWithNavigation): boolean {\n return data.LargestImagePaint.lcpRequestByNavigationId.has(context.navigationId);\n}\n\nfunction computeSavings(\n data: Handlers.Types.HandlerData, context: InsightSetContextWithNavigation,\n renderBlockingRequests: Types.Events.SyntheticNetworkRequest[]):\n Pick<RenderBlockingInsightModel, 'metricSavings'|'requestIdToWastedMs'>|undefined {\n if (!context.lantern) {\n return;\n }\n\n const nodesAndTimingsByRequestId =\n getNodesAndTimingByRequestId(context.lantern.metrics.firstContentfulPaint.optimisticEstimate.nodeTimings);\n\n const metricSavings = {FCP: 0 as Types.Timing.Milli, LCP: 0 as Types.Timing.Milli};\n const requestIdToWastedMs = new Map<string, number>();\n const deferredNodeIds = new Set<string>();\n for (const request of renderBlockingRequests) {\n const nodeAndTiming = nodesAndTimingsByRequestId.get(request.args.data.requestId);\n if (!nodeAndTiming) {\n continue;\n }\n\n const {node, nodeTiming} = nodeAndTiming;\n\n // Mark this node and all its dependents as deferrable\n node.traverse(node => deferredNodeIds.add(node.id));\n\n // \"wastedMs\" is the download time of the network request, responseReceived - requestSent\n const wastedMs = Math.round(nodeTiming.duration);\n if (wastedMs < MINIMUM_WASTED_MS) {\n continue;\n }\n\n requestIdToWastedMs.set(node.id, wastedMs);\n }\n\n if (requestIdToWastedMs.size) {\n metricSavings.FCP = estimateSavingsWithGraphs(deferredNodeIds, context.lantern);\n\n // In most cases, render blocking resources only affect LCP if LCP isn't an image.\n if (!hasImageLCP(data, context)) {\n metricSavings.LCP = metricSavings.FCP;\n }\n }\n\n return {metricSavings, requestIdToWastedMs};\n}\n\nfunction finalize(partialModel: PartialInsightModel<RenderBlockingInsightModel>): RenderBlockingInsightModel {\n return {\n insightKey: InsightKeys.RENDER_BLOCKING,\n strings: UIStrings,\n title: i18nString(UIStrings.title),\n description: i18nString(UIStrings.description),\n category: InsightCategory.LCP,\n state: partialModel.renderBlockingRequests.length > 0 ? 'fail' : 'pass',\n ...partialModel,\n };\n}\n\nexport function generateInsight(\n data: Handlers.Types.HandlerData, context: InsightSetContext): RenderBlockingInsightModel {\n if (!context.navigation) {\n return finalize({\n renderBlockingRequests: [],\n });\n }\n\n const firstPaintTs = data.PageLoadMetrics.metricScoresByFrameId.get(context.frameId)\n ?.get(context.navigationId)\n ?.get(Handlers.ModelHandlers.PageLoadMetrics.MetricName.FP)\n ?.event?.ts;\n if (!firstPaintTs) {\n return finalize({\n renderBlockingRequests: [],\n warnings: [InsightWarning.NO_FP],\n });\n }\n\n let renderBlockingRequests: Types.Events.SyntheticNetworkRequest[] = [];\n for (const req of data.NetworkRequests.byTime) {\n if (req.args.data.frame !== context.frameId) {\n continue;\n }\n\n if (!Helpers.Network.isSyntheticNetworkRequestEventRenderBlocking(req)) {\n continue;\n }\n\n if (req.args.data.syntheticData.finishTime > firstPaintTs) {\n continue;\n }\n\n // If a request is marked `in_body_parser_blocking` it should only be considered render blocking if it is a\n // high enough priority. Some requests (e.g. scripts) are not marked as high priority if they are fetched\n // after a non-preloaded image. (See \"early\" definition in https://web.dev/articles/fetch-priority)\n //\n // There are edge cases and exceptions (e.g. priority hints) but this gives us the best approximation\n // of render blocking resources in the document body.\n if (req.args.data.renderBlocking === 'in_body_parser_blocking') {\n const priority = req.args.data.priority;\n const isScript = req.args.data.resourceType === Protocol.Network.ResourceType.Script;\n const isBlockingScript = isScript && priority === Protocol.Network.ResourcePriority.High;\n if (priority !== Protocol.Network.ResourcePriority.VeryHigh && !isBlockingScript) {\n continue;\n }\n }\n\n const navigation = Helpers.Trace.getNavigationForTraceEvent(req, context.frameId, data.Meta.navigationsByFrameId);\n if (navigation === context.navigation) {\n renderBlockingRequests.push(req);\n }\n }\n\n const savings = computeSavings(data, context, renderBlockingRequests);\n\n // Sort by request duration for insights.\n renderBlockingRequests = renderBlockingRequests.sort((a, b) => {\n return b.dur - a.dur;\n });\n\n return finalize({\n relatedEvents: renderBlockingRequests,\n renderBlockingRequests,\n ...savings,\n });\n}\n\nexport function createOverlayForRequest(request: Types.Events.SyntheticNetworkRequest): Types.Overlays.EntryOutline {\n return {\n type: 'ENTRY_OUTLINE',\n entry: request,\n outlineReason: 'ERROR',\n };\n}\n\nexport function createOverlays(model: RenderBlockingInsightModel): Types.Overlays.Overlay[] {\n return model.renderBlockingRequests.map(request => createOverlayForRequest(request));\n}\n"]}
1
+ {"version":3,"file":"RenderBlocking.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/RenderBlocking.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 The Chromium Authors\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 Protocol from '../../../generated/protocol.js';\nimport * as Handlers from '../handlers/handlers.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport type * as Lantern from '../lantern/lantern.js';\nimport type * as Types from '../types/types.js';\n\nimport {\n InsightCategory,\n InsightKeys,\n type InsightModel,\n type InsightSetContext,\n type InsightSetContextWithNavigation,\n InsightWarning,\n type LanternContext,\n type PartialInsightModel,\n} from './types.js';\n\nexport const UIStrings = {\n /**\n * @description Title of an insight that provides the user with the list of network requests that blocked and therefore slowed down the page rendering and becoming visible to the user.\n */\n title: 'Render-blocking requests',\n /**\n * @description Text to describe that there are requests blocking rendering, which may affect LCP.\n */\n description: 'Requests are blocking the page\\'s initial render, which may delay LCP. ' +\n '[Deferring or inlining](https://developer.chrome.com/docs/performance/insights/render-blocking) ' +\n 'can move these network requests out of the critical path.',\n /**\n * @description Label to describe a network request (that happens to be render-blocking).\n */\n renderBlockingRequest: 'Request',\n /**\n * @description Label used for a time duration.\n */\n duration: 'Duration',\n /**\n * @description Text status indicating that no requests blocked the initial render of a navigation\n */\n noRenderBlocking: 'No render-blocking requests for this navigation',\n} as const;\n\nconst str_ = i18n.i18n.registerUIStrings('models/trace/insights/RenderBlocking.ts', UIStrings);\nexport const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);\n\nexport function isRenderBlockingInsight(insight: InsightModel): insight is RenderBlockingInsightModel {\n return insight.insightKey === 'RenderBlocking';\n}\n\nexport type RenderBlockingInsightModel = InsightModel<typeof UIStrings, {\n renderBlockingRequests: Types.Events.SyntheticNetworkRequest[],\n requestIdToWastedMs?: Map<string, number>,\n}>;\n\n// Because of the way we detect blocking stylesheets, asynchronously loaded\n// CSS with link[rel=preload] and an onload handler (see https://github.com/filamentgroup/loadCSS)\n// can be falsely flagged as blocking. Therefore, ignore stylesheets that loaded fast enough\n// to possibly be non-blocking (and they have minimal impact anyway).\nconst MINIMUM_WASTED_MS = 50;\n\n/**\n * Given a simulation's nodeTimings, return an object with the nodes/timing keyed by network URL\n */\nfunction getNodesAndTimingByRequestId(nodeTimings: Lantern.Simulation.Result['nodeTimings']):\n Map<string, {node: Lantern.Graph.Node, nodeTiming: Lantern.Types.Simulation.NodeTiming}> {\n const requestIdToNode =\n new Map<string, {node: Lantern.Graph.Node, nodeTiming: Lantern.Types.Simulation.NodeTiming}>();\n\n for (const [node, nodeTiming] of nodeTimings) {\n if (node.type !== 'network') {\n continue;\n }\n\n requestIdToNode.set(node.request.requestId, {node, nodeTiming});\n }\n\n return requestIdToNode;\n}\n\nfunction estimateSavingsWithGraphs(deferredIds: Set<string>, lanternContext: LanternContext): Types.Timing.Milli {\n const simulator = lanternContext.simulator;\n const fcpGraph = lanternContext.metrics.firstContentfulPaint.optimisticGraph;\n const {nodeTimings} = lanternContext.simulator.simulate(fcpGraph);\n const adjustedNodeTimings = new Map(nodeTimings);\n\n const totalChildNetworkBytes = 0;\n const minimalFCPGraph = fcpGraph.cloneWithRelationships(node => {\n // If a node can be deferred, exclude it from the new FCP graph\n const canDeferRequest = deferredIds.has(node.id);\n return !canDeferRequest;\n });\n\n if (minimalFCPGraph.type !== 'network') {\n throw new Error('minimalFCPGraph not a NetworkNode');\n }\n\n // Recalculate the \"before\" time based on our adjusted node timings.\n const estimateBeforeInline = Math.max(...Array.from(\n Array.from(adjustedNodeTimings).map(timing => timing[1].endTime),\n ));\n\n // Add the inlined bytes to the HTML response\n const originalTransferSize = minimalFCPGraph.request.transferSize;\n const safeTransferSize = originalTransferSize || 0;\n minimalFCPGraph.request.transferSize = safeTransferSize + totalChildNetworkBytes;\n const estimateAfterInline = simulator.simulate(minimalFCPGraph).timeInMs;\n minimalFCPGraph.request.transferSize = originalTransferSize;\n return Math.round(Math.max(estimateBeforeInline - estimateAfterInline, 0)) as Types.Timing.Milli;\n}\n\nfunction hasImageLCP(data: Handlers.Types.HandlerData, context: InsightSetContextWithNavigation): boolean {\n return data.LargestImagePaint.lcpRequestByNavigationId.has(context.navigationId);\n}\n\nfunction computeSavings(\n data: Handlers.Types.HandlerData, context: InsightSetContextWithNavigation,\n renderBlockingRequests: Types.Events.SyntheticNetworkRequest[]):\n Pick<RenderBlockingInsightModel, 'metricSavings'|'requestIdToWastedMs'>|undefined {\n if (!context.lantern) {\n return;\n }\n\n const nodesAndTimingsByRequestId =\n getNodesAndTimingByRequestId(context.lantern.metrics.firstContentfulPaint.optimisticEstimate.nodeTimings);\n\n const metricSavings = {FCP: 0 as Types.Timing.Milli, LCP: 0 as Types.Timing.Milli};\n const requestIdToWastedMs = new Map<string, number>();\n const deferredNodeIds = new Set<string>();\n for (const request of renderBlockingRequests) {\n const nodeAndTiming = nodesAndTimingsByRequestId.get(request.args.data.requestId);\n if (!nodeAndTiming) {\n continue;\n }\n\n const {node, nodeTiming} = nodeAndTiming;\n\n // Mark this node and all its dependents as deferrable\n node.traverse(node => deferredNodeIds.add(node.id));\n\n // \"wastedMs\" is the download time of the network request, responseReceived - requestSent\n const wastedMs = Math.round(nodeTiming.duration);\n if (wastedMs < MINIMUM_WASTED_MS) {\n continue;\n }\n\n requestIdToWastedMs.set(node.id, wastedMs);\n }\n\n if (requestIdToWastedMs.size) {\n metricSavings.FCP = estimateSavingsWithGraphs(deferredNodeIds, context.lantern);\n\n // In most cases, render-blocking resources only affect LCP if LCP isn't an image.\n if (!hasImageLCP(data, context)) {\n metricSavings.LCP = metricSavings.FCP;\n }\n }\n\n return {metricSavings, requestIdToWastedMs};\n}\n\nfunction finalize(partialModel: PartialInsightModel<RenderBlockingInsightModel>): RenderBlockingInsightModel {\n return {\n insightKey: InsightKeys.RENDER_BLOCKING,\n strings: UIStrings,\n title: i18nString(UIStrings.title),\n description: i18nString(UIStrings.description),\n docs: 'https://developer.chrome.com/docs/performance/insights/render-blocking',\n category: InsightCategory.LCP,\n state: partialModel.renderBlockingRequests.length > 0 ? 'fail' : 'pass',\n ...partialModel,\n };\n}\n\nexport function generateInsight(\n data: Handlers.Types.HandlerData, context: InsightSetContext): RenderBlockingInsightModel {\n if (!context.navigation) {\n return finalize({\n renderBlockingRequests: [],\n });\n }\n\n const firstPaintTs = data.PageLoadMetrics.metricScoresByFrameId.get(context.frameId)\n ?.get(context.navigation)\n ?.get(Handlers.ModelHandlers.PageLoadMetrics.MetricName.FP)\n ?.event?.ts;\n if (!firstPaintTs) {\n return finalize({\n renderBlockingRequests: [],\n warnings: [InsightWarning.NO_FP],\n });\n }\n\n let renderBlockingRequests: Types.Events.SyntheticNetworkRequest[] = [];\n for (const req of data.NetworkRequests.byTime) {\n if (req.args.data.frame !== context.frameId) {\n continue;\n }\n\n if (!Helpers.Network.isSyntheticNetworkRequestEventRenderBlocking(req)) {\n continue;\n }\n\n if (req.args.data.syntheticData.finishTime > firstPaintTs) {\n continue;\n }\n\n // If a request is marked `in_body_parser_blocking` it should only be considered render-blocking if it is a\n // high enough priority. Some requests (e.g. scripts) are not marked as high priority if they are fetched\n // after a non-preloaded image. (See \"early\" definition in https://web.dev/articles/fetch-priority)\n //\n // There are edge cases and exceptions (e.g. priority hints) but this gives us the best approximation\n // of render-blocking resources in the document body.\n if (req.args.data.renderBlocking === 'in_body_parser_blocking') {\n const priority = req.args.data.priority;\n const isScript = req.args.data.resourceType === Protocol.Network.ResourceType.Script;\n const isBlockingScript = isScript && priority === Protocol.Network.ResourcePriority.High;\n if (priority !== Protocol.Network.ResourcePriority.VeryHigh && !isBlockingScript) {\n continue;\n }\n }\n\n const navigation = Helpers.Trace.getNavigationForTraceEvent(req, context.frameId, data.Meta.navigationsByFrameId);\n if (navigation === context.navigation) {\n renderBlockingRequests.push(req);\n }\n }\n\n const savings = computeSavings(data, context, renderBlockingRequests);\n\n // Sort by request duration for insights.\n renderBlockingRequests = renderBlockingRequests.sort((a, b) => {\n return b.dur - a.dur;\n });\n\n return finalize({\n relatedEvents: renderBlockingRequests,\n renderBlockingRequests,\n ...savings,\n });\n}\n\nexport function createOverlayForRequest(request: Types.Events.SyntheticNetworkRequest): Types.Overlays.EntryOutline {\n return {\n type: 'ENTRY_OUTLINE',\n entry: request,\n outlineReason: 'ERROR',\n };\n}\n\nexport function createOverlays(model: RenderBlockingInsightModel): Types.Overlays.Overlay[] {\n return model.renderBlockingRequests.map(request => createOverlayForRequest(request));\n}\n"]}
@@ -9,7 +9,7 @@ export declare const UIStrings: {
9
9
  /**
10
10
  * @description Text to describe how to improve the performance of CSS selectors.
11
11
  */
12
- readonly description: "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.";
12
+ readonly description: "If Recalculate Style costs remain high, selector optimization can reduce them. [Optimize the selectors](https://developer.chrome.com/docs/performance/insights/slow-css-selector) 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.";
13
13
  /**
14
14
  * @description Column name for count of elements that the engine attempted to match against a style rule
15
15
  */
@@ -14,7 +14,7 @@ export const UIStrings = {
14
14
  /**
15
15
  * @description Text to describe how to improve the performance of CSS selectors.
16
16
  */
17
- description: '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.',
17
+ description: 'If Recalculate Style costs remain high, selector optimization can reduce them. [Optimize the selectors](https://developer.chrome.com/docs/performance/insights/slow-css-selector) 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.',
18
18
  /**
19
19
  * @description Column name for count of elements that the engine attempted to match against a style rule
20
20
  */
@@ -82,6 +82,7 @@ function finalize(partialModel) {
82
82
  strings: UIStrings,
83
83
  title: i18nString(UIStrings.title),
84
84
  description: i18nString(UIStrings.description),
85
+ docs: 'https://developer.chrome.com/docs/performance/insights/slow-css-selector',
85
86
  category: InsightCategory.ALL,
86
87
  state: partialModel.topSelectorElapsedMs && partialModel.topSelectorMatchAttempts ? 'informative' : 'pass',
87
88
  ...partialModel,
@@ -1 +1 @@
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\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 type * as Handlers from '../handlers/handlers.js';\nimport type {SelectorStatsData} from '../handlers/SelectorStatsHandler.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} 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 * @description top CSS selector when ranked by elapsed time in ms\n */\n topSelectorElapsedTime: 'Top selector elapsed time',\n /**\n * @description top CSS selector when ranked by match attempt\n */\n topSelectorMatchAttempt: 'Top selector match attempt',\n} as const;\n\nconst str_ = i18n.i18n.registerUIStrings('models/trace/insights/SlowCSSSelector.ts', UIStrings);\nexport const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);\nconst slowCSSSelectorThreshold = 500; // 500us threshold for slow selectors\n\nexport type SlowCSSSelectorInsightModel = InsightModel<typeof UIStrings, {\n totalElapsedMs: Types.Timing.Milli,\n totalMatchAttempts: number,\n totalMatchCount: number,\n topSelectorElapsedMs: Types.Events.SelectorTiming | null,\n topSelectorMatchAttempts: Types.Events.SelectorTiming | null,\n}>;\n\nfunction aggregateSelectorStats(data: SelectorStatsData, context: InsightSetContext): SelectorTiming[] {\n const selectorMap = new Map<String, SelectorTiming>();\n\n for (const [event, value] of data.dataForRecalcStyleEvent) {\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.topSelectorElapsedMs && partialModel.topSelectorMatchAttempts ? 'informative' : 'pass',\n ...partialModel,\n };\n}\n\nexport function isSlowCSSSelectorInsight(model: InsightModel): model is SlowCSSSelectorInsightModel {\n return model.insightKey === InsightKeys.SLOW_CSS_SELECTOR;\n}\n\nexport function generateInsight(\n data: Handlers.Types.HandlerData, context: InsightSetContext): SlowCSSSelectorInsightModel {\n const selectorStatsData = data.SelectorStats;\n\n if (!selectorStatsData) {\n throw new Error('no selector stats data');\n }\n\n const selectorTimings = aggregateSelectorStats(selectorStatsData, 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 let topSelectorElapsedMs: SelectorTiming|null = null;\n let topSelectorMatchAttempts: SelectorTiming|null = null;\n\n if (selectorTimings.length > 0) {\n // find the selector with most elapsed time\n topSelectorElapsedMs = selectorTimings.reduce((a, b) => {\n return a[SelectorTimingsKey.Elapsed] > b[SelectorTimingsKey.Elapsed] ? a : b;\n });\n\n // check if the slowest selector is slow enough to trigger insights info\n if (topSelectorElapsedMs && topSelectorElapsedMs[SelectorTimingsKey.Elapsed] < slowCSSSelectorThreshold) {\n topSelectorElapsedMs = null;\n }\n\n // find the selector with most match attempts\n topSelectorMatchAttempts = selectorTimings.reduce((a, b) => {\n return a[SelectorTimingsKey.MatchAttempts] > b[SelectorTimingsKey.MatchAttempts] ? a : b;\n });\n }\n\n return finalize({\n // TODO: should we identify RecalcStyle events as linked to this insight?\n relatedEvents: [],\n totalElapsedMs: Types.Timing.Milli(totalElapsedUs / 1000.0),\n totalMatchAttempts,\n totalMatchCount,\n topSelectorElapsedMs,\n topSelectorMatchAttempts,\n });\n}\n\nexport function createOverlays(_: SlowCSSSelectorInsightModel): Types.Overlays.Overlay[] {\n return [];\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\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 type * as Handlers from '../handlers/handlers.js';\nimport type {SelectorStatsData} from '../handlers/SelectorStatsHandler.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} 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/performance/insights/slow-css-selector) 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 * @description top CSS selector when ranked by elapsed time in ms\n */\n topSelectorElapsedTime: 'Top selector elapsed time',\n /**\n * @description top CSS selector when ranked by match attempt\n */\n topSelectorMatchAttempt: 'Top selector match attempt',\n} as const;\n\nconst str_ = i18n.i18n.registerUIStrings('models/trace/insights/SlowCSSSelector.ts', UIStrings);\nexport const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);\nconst slowCSSSelectorThreshold = 500; // 500us threshold for slow selectors\n\nexport type SlowCSSSelectorInsightModel = InsightModel<typeof UIStrings, {\n totalElapsedMs: Types.Timing.Milli,\n totalMatchAttempts: number,\n totalMatchCount: number,\n topSelectorElapsedMs: Types.Events.SelectorTiming | null,\n topSelectorMatchAttempts: Types.Events.SelectorTiming | null,\n}>;\n\nfunction aggregateSelectorStats(data: SelectorStatsData, context: InsightSetContext): SelectorTiming[] {\n const selectorMap = new Map<String, SelectorTiming>();\n\n for (const [event, value] of data.dataForRecalcStyleEvent) {\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 docs: 'https://developer.chrome.com/docs/performance/insights/slow-css-selector',\n category: InsightCategory.ALL,\n state: partialModel.topSelectorElapsedMs && partialModel.topSelectorMatchAttempts ? 'informative' : 'pass',\n ...partialModel,\n };\n}\n\nexport function isSlowCSSSelectorInsight(model: InsightModel): model is SlowCSSSelectorInsightModel {\n return model.insightKey === InsightKeys.SLOW_CSS_SELECTOR;\n}\n\nexport function generateInsight(\n data: Handlers.Types.HandlerData, context: InsightSetContext): SlowCSSSelectorInsightModel {\n const selectorStatsData = data.SelectorStats;\n\n if (!selectorStatsData) {\n throw new Error('no selector stats data');\n }\n\n const selectorTimings = aggregateSelectorStats(selectorStatsData, 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 let topSelectorElapsedMs: SelectorTiming|null = null;\n let topSelectorMatchAttempts: SelectorTiming|null = null;\n\n if (selectorTimings.length > 0) {\n // find the selector with most elapsed time\n topSelectorElapsedMs = selectorTimings.reduce((a, b) => {\n return a[SelectorTimingsKey.Elapsed] > b[SelectorTimingsKey.Elapsed] ? a : b;\n });\n\n // check if the slowest selector is slow enough to trigger insights info\n if (topSelectorElapsedMs && topSelectorElapsedMs[SelectorTimingsKey.Elapsed] < slowCSSSelectorThreshold) {\n topSelectorElapsedMs = null;\n }\n\n // find the selector with most match attempts\n topSelectorMatchAttempts = selectorTimings.reduce((a, b) => {\n return a[SelectorTimingsKey.MatchAttempts] > b[SelectorTimingsKey.MatchAttempts] ? a : b;\n });\n }\n\n return finalize({\n // TODO: should we identify RecalcStyle events as linked to this insight?\n relatedEvents: [],\n totalElapsedMs: Types.Timing.Milli(totalElapsedUs / 1000.0),\n totalMatchAttempts,\n totalMatchCount,\n topSelectorElapsedMs,\n topSelectorMatchAttempts,\n });\n}\n\nexport function createOverlays(_: SlowCSSSelectorInsightModel): Types.Overlays.Overlay[] {\n return [];\n}\n"]}
@@ -14,7 +14,7 @@ export const UIStrings = {
14
14
  * This is displayed after a user expands the section to see more. No character length limits.
15
15
  */
16
16
  description: '3rd party code can significantly impact load performance. ' +
17
- '[Reduce and defer loading of 3rd party code](https://web.dev/articles/optimizing-content-efficiency-loading-third-party-javascript/) to prioritize your page\'s content.',
17
+ '[Reduce and defer loading of 3rd party code](https://developer.chrome.com/docs/performance/insights/third-parties) to prioritize your page\'s content.',
18
18
  /** Label for a table column that displays the name of a third-party provider. */
19
19
  columnThirdParty: '3rd party',
20
20
  /** Label for a column in a data table; entries will be the download size of a web resource in kilobytes. */
@@ -43,6 +43,7 @@ function finalize(partialModel) {
43
43
  strings: UIStrings,
44
44
  title: i18nString(UIStrings.title),
45
45
  description: i18nString(UIStrings.description),
46
+ docs: 'https://developer.chrome.com/docs/performance/insights/third-parties',
46
47
  category: InsightCategory.ALL,
47
48
  state: partialModel.entitySummaries.find(summary => summary.entity !== partialModel.firstPartyEntity) ?
48
49
  'informative' :
@@ -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\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 type * as Types from '../types/types.js';\n\nimport {\n InsightCategory,\n InsightKeys,\n type InsightModel,\n type InsightSetContext,\n type PartialInsightModel,\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://web.dev/articles/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 type ThirdPartiesInsightModel = InsightModel<typeof UIStrings, {\n /** The entity for this navigation's URL. Any other entity is from a third party. */\n entitySummaries: Extras.ThirdParties.EntitySummary[],\n firstPartyEntity?: Extras.ThirdParties.Entity,\n}>;\n\nfunction getRelatedEvents(\n summaries: Extras.ThirdParties.EntitySummary[],\n firstPartyEntity: Extras.ThirdParties.Entity|undefined): Types.Events.Event[] {\n const relatedEvents = [];\n for (const summary of summaries) {\n if (summary.entity !== firstPartyEntity) {\n relatedEvents.push(...summary.relatedEvents);\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.entitySummaries.find(summary => summary.entity !== partialModel.firstPartyEntity) ?\n 'informative' :\n 'pass',\n ...partialModel,\n };\n}\n\nexport function isThirdPartyInsight(model: InsightModel): model is ThirdPartiesInsightModel {\n return model.insightKey === InsightKeys.THIRD_PARTIES;\n}\n\nexport function generateInsight(\n data: Handlers.Types.HandlerData, context: InsightSetContext): ThirdPartiesInsightModel {\n const entitySummaries = Extras.ThirdParties.summarizeByThirdParty(data as Handlers.Types.HandlerData, context.bounds);\n\n const firstPartyUrl = context.navigation?.args.data?.documentLoaderURL ?? data.Meta.mainFrameURL;\n const firstPartyEntity = ThirdPartyWeb.ThirdPartyWeb.getEntity(firstPartyUrl) ||\n Handlers.Helpers.makeUpEntity(data.Renderer.entityMappings.createdEntityCache, firstPartyUrl);\n\n return finalize({\n relatedEvents: getRelatedEvents(entitySummaries, firstPartyEntity),\n firstPartyEntity,\n entitySummaries,\n });\n}\n\nexport function createOverlaysForSummary(summary: Extras.ThirdParties.EntitySummary): Types.Overlays.Overlay[] {\n const overlays = [];\n for (const event of summary.relatedEvents) {\n // The events found for a third party can be vast, as they gather every\n // single main thread task along with everything else on the page. If the\n // main thread is busy with large icicles, we can easily create tens of\n // thousands of overlays. Therefore, only create overlays for events of at least 1ms.\n if (event.dur === undefined || event.dur < 1_000) {\n continue;\n }\n\n const overlay: Types.Overlays.Overlay = {\n type: 'ENTRY_OUTLINE',\n entry: event,\n outlineReason: 'INFO',\n };\n overlays.push(overlay);\n }\n return overlays;\n}\n\nexport function createOverlays(model: ThirdPartiesInsightModel): Types.Overlays.Overlay[] {\n const overlays: Types.Overlays.Overlay[] = [];\n const summaries = model.entitySummaries ?? [];\n for (const summary of summaries) {\n if (summary.entity === model.firstPartyEntity) {\n continue;\n }\n\n const summaryOverlays = createOverlaysForSummary(summary);\n overlays.push(...summaryOverlays);\n }\n\n return overlays;\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\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 type * as Types from '../types/types.js';\n\nimport {\n InsightCategory,\n InsightKeys,\n type InsightModel,\n type InsightSetContext,\n type PartialInsightModel,\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://developer.chrome.com/docs/performance/insights/third-parties) 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 type ThirdPartiesInsightModel = InsightModel<typeof UIStrings, {\n /** The entity for this navigation's URL. Any other entity is from a third party. */\n entitySummaries: Extras.ThirdParties.EntitySummary[],\n firstPartyEntity?: Extras.ThirdParties.Entity,\n}>;\n\nfunction getRelatedEvents(\n summaries: Extras.ThirdParties.EntitySummary[],\n firstPartyEntity: Extras.ThirdParties.Entity|undefined): Types.Events.Event[] {\n const relatedEvents = [];\n for (const summary of summaries) {\n if (summary.entity !== firstPartyEntity) {\n relatedEvents.push(...summary.relatedEvents);\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 docs: 'https://developer.chrome.com/docs/performance/insights/third-parties',\n category: InsightCategory.ALL,\n state: partialModel.entitySummaries.find(summary => summary.entity !== partialModel.firstPartyEntity) ?\n 'informative' :\n 'pass',\n ...partialModel,\n };\n}\n\nexport function isThirdPartyInsight(model: InsightModel): model is ThirdPartiesInsightModel {\n return model.insightKey === InsightKeys.THIRD_PARTIES;\n}\n\nexport function generateInsight(\n data: Handlers.Types.HandlerData, context: InsightSetContext): ThirdPartiesInsightModel {\n const entitySummaries = Extras.ThirdParties.summarizeByThirdParty(data as Handlers.Types.HandlerData, context.bounds);\n\n const firstPartyUrl = context.navigation?.args.data?.documentLoaderURL ?? data.Meta.mainFrameURL;\n const firstPartyEntity = ThirdPartyWeb.ThirdPartyWeb.getEntity(firstPartyUrl) ||\n Handlers.Helpers.makeUpEntity(data.Renderer.entityMappings.createdEntityCache, firstPartyUrl);\n\n return finalize({\n relatedEvents: getRelatedEvents(entitySummaries, firstPartyEntity),\n firstPartyEntity,\n entitySummaries,\n });\n}\n\nexport function createOverlaysForSummary(summary: Extras.ThirdParties.EntitySummary): Types.Overlays.Overlay[] {\n const overlays = [];\n for (const event of summary.relatedEvents) {\n // The events found for a third party can be vast, as they gather every\n // single main thread task along with everything else on the page. If the\n // main thread is busy with large icicles, we can easily create tens of\n // thousands of overlays. Therefore, only create overlays for events of at least 1ms.\n if (event.dur === undefined || event.dur < 1_000) {\n continue;\n }\n\n const overlay: Types.Overlays.Overlay = {\n type: 'ENTRY_OUTLINE',\n entry: event,\n outlineReason: 'INFO',\n };\n overlays.push(overlay);\n }\n return overlays;\n}\n\nexport function createOverlays(model: ThirdPartiesInsightModel): Types.Overlays.Overlay[] {\n const overlays: Types.Overlays.Overlay[] = [];\n const summaries = model.entitySummaries ?? [];\n for (const summary of summaries) {\n if (summary.entity === model.firstPartyEntity) {\n continue;\n }\n\n const summaryOverlays = createOverlaysForSummary(summary);\n overlays.push(...summaryOverlays);\n }\n\n return overlays;\n}\n"]}
@@ -8,7 +8,7 @@ export declare const UIStrings: {
8
8
  /**
9
9
  * @description Text to tell the user how a viewport meta element can improve performance. \xa0 is a non-breaking space
10
10
  */
11
- 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.";
11
+ readonly description: "Tap interactions may be [delayed by up to 300 ms](https://developer.chrome.com/docs/performance/insights/viewport) if the viewport is not optimized for mobile.";
12
12
  /**
13
13
  * @description Text for a label describing the portion of an interaction event that was delayed due to a bad mobile viewport.
14
14
  */
@@ -13,7 +13,7 @@ export const UIStrings = {
13
13
  /**
14
14
  * @description Text to tell the user how a viewport meta element can improve performance. \xa0 is a non-breaking space
15
15
  */
16
- description: '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.',
16
+ description: 'Tap interactions may be [delayed by up to 300\xA0ms](https://developer.chrome.com/docs/performance/insights/viewport) if the viewport is not optimized for mobile.',
17
17
  /**
18
18
  * @description Text for a label describing the portion of an interaction event that was delayed due to a bad mobile viewport.
19
19
  */
@@ -27,6 +27,7 @@ function finalize(partialModel) {
27
27
  strings: UIStrings,
28
28
  title: i18nString(UIStrings.title),
29
29
  description: i18nString(UIStrings.description),
30
+ docs: 'https://developer.chrome.com/docs/performance/insights/viewport',
30
31
  category: InsightCategory.INP,
31
32
  state: partialModel.mobileOptimized === false ? 'fail' : 'pass',
32
33
  ...partialModel,
@@ -1 +1 @@
1
- {"version":3,"file":"Viewport.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/Viewport.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 The Chromium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as i18n from '../../../core/i18n/i18n.js';\nimport * as Platform from '../../../core/platform/platform.js';\nimport * as Handlers from '../handlers/handlers.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nimport {\n InsightCategory,\n InsightKeys,\n type InsightModel,\n type InsightSetContext,\n InsightWarning,\n type PartialInsightModel,\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 * @description Text for a label describing the portion of an interaction event that was delayed due to a bad mobile viewport.\n */\n mobileTapDelayLabel: 'Mobile tap delay',\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 type ViewportInsightModel = InsightModel<typeof UIStrings, {\n mobileOptimized: boolean | null,\n viewportEvent?: Types.Events.ParseMetaViewport,\n longPointerInteractions?: Types.Events.SyntheticInteractionPair[],\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 isViewportInsight(model: InsightModel): model is ViewportInsightModel {\n return model.insightKey === InsightKeys.VIEWPORT;\n}\n\nexport function generateInsight(data: Handlers.Types.HandlerData, context: InsightSetContext): ViewportInsightModel {\n const viewportEvent = data.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 const compositorEvents = data.UserInteractions.beginCommitCompositorFrameEvents.filter(event => {\n if (event.args.frame !== context.frameId) {\n return false;\n }\n\n // Commit compositor frame events can be emitted before the viewport tag is parsed.\n // We shouldn't count these since the browser hasn't had time to make the viewport mobile optimized.\n if (viewportEvent && event.ts < viewportEvent.ts) {\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 // Returns true only if all events are mobile optimized.\n for (const event of compositorEvents) {\n if (!event.args.is_mobile_optimized) {\n // Grab all the pointer events with at least 50ms of input delay.\n const longPointerInteractions = [...data.UserInteractions.interactionsOverThreshold.values()].filter(\n interaction => Handlers.ModelHandlers.UserInteractions.categoryOfInteraction(interaction) === 'POINTER' &&\n interaction.inputDelay >= 50_000);\n\n // The actual impact varies between 0 and 300.\n // Using inputDelay as the closest thing we have for measuring this, though inputDelay may be high for other reasons.\n // b/371566378#comment8\n const inputDelay = Math.max(0, ...longPointerInteractions.map(interaction => interaction.inputDelay)) / 1000;\n const inpMetricSavings = Platform.NumberUtilities.clamp(inputDelay, 0, 300);\n\n return finalize({\n mobileOptimized: false,\n viewportEvent,\n longPointerInteractions,\n metricSavings: {INP: inpMetricSavings as Types.Timing.Milli},\n });\n }\n }\n\n return finalize({\n mobileOptimized: true,\n viewportEvent,\n });\n}\n\nexport function createOverlays(model: ViewportInsightModel): Types.Overlays.Overlay[] {\n if (!model.longPointerInteractions) {\n return [];\n }\n\n return model.longPointerInteractions.map(interaction => {\n const delay = Math.min(interaction.inputDelay, 300 * 1000);\n const bounds = Helpers.Timing.traceWindowFromMicroSeconds(\n Types.Timing.Micro(interaction.ts),\n Types.Timing.Micro(interaction.ts + delay),\n );\n return {\n type: 'TIMESPAN_BREAKDOWN',\n entry: interaction,\n sections: [{bounds, label: i18nString(UIStrings.mobileTapDelayLabel), showDuration: true}],\n renderLocation: 'ABOVE_EVENT',\n };\n });\n}\n"]}
1
+ {"version":3,"file":"Viewport.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/Viewport.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 The Chromium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as i18n from '../../../core/i18n/i18n.js';\nimport * as Platform from '../../../core/platform/platform.js';\nimport * as Handlers from '../handlers/handlers.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nimport {\n InsightCategory,\n InsightKeys,\n type InsightModel,\n type InsightSetContext,\n InsightWarning,\n type PartialInsightModel,\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/docs/performance/insights/viewport) if the viewport is not optimized for mobile.',\n /**\n * @description Text for a label describing the portion of an interaction event that was delayed due to a bad mobile viewport.\n */\n mobileTapDelayLabel: 'Mobile tap delay',\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 type ViewportInsightModel = InsightModel<typeof UIStrings, {\n mobileOptimized: boolean | null,\n viewportEvent?: Types.Events.ParseMetaViewport,\n longPointerInteractions?: Types.Events.SyntheticInteractionPair[],\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 docs: 'https://developer.chrome.com/docs/performance/insights/viewport',\n category: InsightCategory.INP,\n state: partialModel.mobileOptimized === false ? 'fail' : 'pass',\n ...partialModel,\n };\n}\n\nexport function isViewportInsight(model: InsightModel): model is ViewportInsightModel {\n return model.insightKey === InsightKeys.VIEWPORT;\n}\n\nexport function generateInsight(data: Handlers.Types.HandlerData, context: InsightSetContext): ViewportInsightModel {\n const viewportEvent = data.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 const compositorEvents = data.UserInteractions.beginCommitCompositorFrameEvents.filter(event => {\n if (event.args.frame !== context.frameId) {\n return false;\n }\n\n // Commit compositor frame events can be emitted before the viewport tag is parsed.\n // We shouldn't count these since the browser hasn't had time to make the viewport mobile optimized.\n if (viewportEvent && event.ts < viewportEvent.ts) {\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 // Returns true only if all events are mobile optimized.\n for (const event of compositorEvents) {\n if (!event.args.is_mobile_optimized) {\n // Grab all the pointer events with at least 50ms of input delay.\n const longPointerInteractions = [...data.UserInteractions.interactionsOverThreshold.values()].filter(\n interaction => Handlers.ModelHandlers.UserInteractions.categoryOfInteraction(interaction) === 'POINTER' &&\n interaction.inputDelay >= 50_000);\n\n // The actual impact varies between 0 and 300.\n // Using inputDelay as the closest thing we have for measuring this, though inputDelay may be high for other reasons.\n // b/371566378#comment8\n const inputDelay = Math.max(0, ...longPointerInteractions.map(interaction => interaction.inputDelay)) / 1000;\n const inpMetricSavings = Platform.NumberUtilities.clamp(inputDelay, 0, 300);\n\n return finalize({\n mobileOptimized: false,\n viewportEvent,\n longPointerInteractions,\n metricSavings: {INP: inpMetricSavings as Types.Timing.Milli},\n });\n }\n }\n\n return finalize({\n mobileOptimized: true,\n viewportEvent,\n });\n}\n\nexport function createOverlays(model: ViewportInsightModel): Types.Overlays.Overlay[] {\n if (!model.longPointerInteractions) {\n return [];\n }\n\n return model.longPointerInteractions.map(interaction => {\n const delay = Math.min(interaction.inputDelay, 300 * 1000);\n const bounds = Helpers.Timing.traceWindowFromMicroSeconds(\n Types.Timing.Micro(interaction.ts),\n Types.Timing.Micro(interaction.ts + delay),\n );\n return {\n type: 'TIMESPAN_BREAKDOWN',\n entry: interaction,\n sections: [{bounds, label: i18nString(UIStrings.mobileTapDelayLabel), showDuration: true}],\n renderLocation: 'ABOVE_EVENT',\n };\n });\n}\n"]}
@@ -8,13 +8,13 @@
8
8
  "forceConsistentCasingInFileNames": true,
9
9
  "inlineSources": true,
10
10
  "lib": [
11
+ "dom",
12
+ "dom.iterable",
11
13
  "ES2023",
12
14
  "ES2024.Promise",
13
15
  "ESNext.Iterator",
14
16
  "ESNext.Collection",
15
- "ESNext.Array",
16
- "dom",
17
- "dom.iterable"
17
+ "ESNext.Array"
18
18
  ],
19
19
  "module": "esnext",
20
20
  "noEmitOnError": true,
@@ -31,6 +31,7 @@
31
31
  "target": "ES2023",
32
32
  "tsBuildInfoFile": "devtools_entrypoint-bundle-typescript-tsconfig.json.tsbuildinfo",
33
33
  "typeRoots": [],
34
+ "types": [],
34
35
  "useUnknownInCatchVariables": false
35
36
  },
36
37
  "files": [
@@ -8,13 +8,13 @@
8
8
  "forceConsistentCasingInFileNames": true,
9
9
  "inlineSources": true,
10
10
  "lib": [
11
+ "dom",
12
+ "dom.iterable",
11
13
  "ES2023",
12
14
  "ES2024.Promise",
13
15
  "ESNext.Iterator",
14
16
  "ESNext.Collection",
15
- "ESNext.Array",
16
- "dom",
17
- "dom.iterable"
17
+ "ESNext.Array"
18
18
  ],
19
19
  "module": "esnext",
20
20
  "noEmitOnError": true,
@@ -31,11 +31,13 @@
31
31
  "target": "ES2023",
32
32
  "tsBuildInfoFile": "insights-tsconfig.json.tsbuildinfo",
33
33
  "typeRoots": [],
34
+ "types": [],
34
35
  "useUnknownInCatchVariables": false
35
36
  },
36
37
  "files": [
37
38
  "../../../../../../../front_end/models/trace/insights/CLSCulprits.ts",
38
39
  "../../../../../../../front_end/models/trace/insights/Cache.ts",
40
+ "../../../../../../../front_end/models/trace/insights/CharacterSet.ts",
39
41
  "../../../../../../../front_end/models/trace/insights/Common.ts",
40
42
  "../../../../../../../front_end/models/trace/insights/DOMSize.ts",
41
43
  "../../../../../../../front_end/models/trace/insights/DocumentLatency.ts",
@@ -61,20 +63,41 @@
61
63
  "../../../../../../../node_modules/@types/filesystem/index.d.ts"
62
64
  ],
63
65
  "references": [
66
+ {
67
+ "path": "../../../core/common/bundle-tsconfig.json"
68
+ },
69
+ {
70
+ "path": "../../../core/i18n/bundle-tsconfig.json"
71
+ },
72
+ {
73
+ "path": "../../../core/platform/bundle-tsconfig.json"
74
+ },
75
+ {
76
+ "path": "../../../generated/protocol-tsconfig.json"
77
+ },
64
78
  {
65
79
  "path": "../../../third_party/legacy-javascript/bundle-tsconfig.json"
66
80
  },
67
81
  {
68
82
  "path": "../../../third_party/third-party-web/bundle-tsconfig.json"
69
83
  },
84
+ {
85
+ "path": "../../crux-manager/bundle-tsconfig.json"
86
+ },
70
87
  {
71
88
  "path": "../extras/bundle-tsconfig.json"
72
89
  },
73
90
  {
74
91
  "path": "../handlers/bundle-tsconfig.json"
75
92
  },
93
+ {
94
+ "path": "../helpers/bundle-tsconfig.json"
95
+ },
76
96
  {
77
97
  "path": "../lantern/bundle-tsconfig.json"
98
+ },
99
+ {
100
+ "path": "../types/bundle-tsconfig.json"
78
101
  }
79
102
  ]
80
103
  }
@@ -58,6 +58,7 @@ export type InsightModel<UIStrings extends Record<string, string> = Record<strin
58
58
  strings: UIStrings;
59
59
  title: {i18nId: string, values: Record<string, string|number>, formattedDefault: string};
60
60
  description: {i18nId: string, values: Record<string, string|number>, formattedDefault: string};
61
+ docs: string;
61
62
  category: InsightCategory;
62
63
  state: 'pass' | 'fail' | 'informative';
63
64
  /** Used by RelatedInsightChips.ts */
@@ -77,31 +78,40 @@ export type InsightModel<UIStrings extends Record<string, string> = Record<strin
77
78
  /**
78
79
  * If this insight is attached to a navigation, this stores its ID.
79
80
  */
80
- navigationId?: string;
81
+ navigation?: Types.Events.NavigationStart;
81
82
  /** This is lazily-generated because some insights may create many overlays. */
82
83
  createOverlays?: () => Types.Overlays.Overlay[];
83
84
  };
84
- export type PartialInsightModel<T> = Omit<T, 'strings' | 'title' | 'description' | 'category' | 'state' | 'insightKey' | 'navigationId' | 'frameId'>;
85
+ export type PartialInsightModel<T> = Omit<T, 'strings' | 'title' | 'description' | 'docs' | 'category' | 'state' | 'insightKey' | 'navigationId' | 'frameId'>;
85
86
  /**
86
87
  * Contains insights for a specific navigation. If a trace began after a navigation already started,
87
88
  * this could instead represent the duration from the beginning of the trace up to the first recorded
88
89
  * navigation (or the end of the trace).
89
90
  */
90
91
  export interface InsightSet {
91
- /** If for a navigation, this is the navigationId. Else it is Trace.Types.Events.NO_NAVIGATION. */
92
+ /** If for a navigation, this is of the form "NAVIGATION_(index)". Else it is Trace.Types.Events.NO_NAVIGATION. */
92
93
  id: Types.Events.NavigationId;
93
94
  /** The URL to show in the accordion list. */
94
95
  url: URL;
95
96
  frameId: string;
96
97
  bounds: Types.Timing.TraceWindowMicro;
98
+ /** Contains results for all non-errored insights. */
97
99
  model: InsightModels;
100
+ /** Contains errors for all insights that had an internal error. */
101
+ modelErrors: InsightModelErrors;
98
102
  navigation?: Types.Events.NavigationStart;
99
103
  }
100
104
  /**
101
- * Contains insights for a specific insight set.
105
+ * Contains insights for a specific insight set. If missing, it error'd.
102
106
  */
103
107
  export type InsightModels = {
104
- [I in keyof InsightModelsType]: ReturnType<InsightModelsType[I]['generateInsight']>;
108
+ [I in keyof InsightModelsType]?: ReturnType<InsightModelsType[I]['generateInsight']>;
109
+ };
110
+ /**
111
+ * Contains an internal error for each insight in a specific insight set.
112
+ */
113
+ export type InsightModelErrors = {
114
+ [I in keyof InsightModelsType]?: Error;
105
115
  };
106
116
  /**
107
117
  * Contains insights for the entire trace. Insights are mostly grouped by `navigationId`, with one exception:
@@ -128,5 +138,6 @@ export declare enum InsightKeys {
128
138
  SLOW_CSS_SELECTOR = "SlowCSSSelector",
129
139
  VIEWPORT = "Viewport",
130
140
  MODERN_HTTP = "ModernHTTP",
131
- CACHE = "Cache"
141
+ CACHE = "Cache",
142
+ CHARACTER_SET = "CharacterSet"
132
143
  }
@@ -36,5 +36,6 @@ export var InsightKeys;
36
36
  InsightKeys["VIEWPORT"] = "Viewport";
37
37
  InsightKeys["MODERN_HTTP"] = "ModernHTTP";
38
38
  InsightKeys["CACHE"] = "Cache";
39
+ InsightKeys["CHARACTER_SET"] = "CharacterSet";
39
40
  })(InsightKeys || (InsightKeys = {}));
40
41
  //# sourceMappingURL=types.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/types.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,yEAAyE;AACzE,6BAA6B;AAsC7B,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;AAyED,MAAM,CAAN,IAAY,WAmBX;AAnBD,WAAY,WAAW;IACrB,6CAA8B,CAAA;IAC9B,6CAA8B,CAAA;IAC9B,2CAA4B,CAAA;IAC5B,6CAA8B,CAAA;IAC9B,mDAAoC,CAAA;IACpC,mCAAoB,CAAA;IACpB,4DAA6C,CAAA;IAC7C,2CAA4B,CAAA;IAC5B,6CAA8B,CAAA;IAC9B,+CAAgC,CAAA;IAChC,6CAA8B,CAAA;IAC9B,qDAAsC,CAAA;IACtC,gEAAiD,CAAA;IACjD,iDAAkC,CAAA;IAClC,oDAAqC,CAAA;IACrC,oCAAqB,CAAA;IACrB,yCAA0B,CAAA;IAC1B,8BAAe,CAAA;AACjB,CAAC,EAnBW,WAAW,KAAX,WAAW,QAmBtB","sourcesContent":["// Copyright 2024 The Chromium Authors\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 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 options: Types.Configuration.ParseOptions;\n bounds: Types.Timing.TraceWindowMicro;\n frameId: string;\n navigation?: never;\n}\n\nexport interface InsightSetContextWithNavigation {\n options: Types.Configuration.ParseOptions;\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 requests: Array<Lantern.Types.NetworkRequest<Types.Events.SyntheticNetworkRequest>>;\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 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> = Record<string, string>,\n ExtraDetail extends Record<string, unknown> = Record<string, unknown>> =\n ExtraDetail&{\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 /** Used by RelatedInsightChips.ts */\n relatedEvents?: RelatedEventsMap | Types.Events.Event[],\n warnings?: InsightWarning[],\n metricSavings?: MetricSavings,\n /**\n * An estimate for the number of bytes that this insight deems to have been wasted.\n * Bytes are in terms of transfer size: for each component of savings related to an\n * individual request, the insight will estimate its impact on transfer size by using\n * the compression ratio of the resource.\n *\n * This field is only displayed for informational purposes.\n */\n wastedBytes?: number,\n frameId?: string,\n /**\n * If this insight is attached to a navigation, this stores its ID.\n */\n navigationId?: string,\n /** This is lazily-generated because some insights may create many overlays. */\n createOverlays?: () => Types.Overlays.Overlay[],\n };\n\nexport type PartialInsightModel<T> =\n Omit<T, 'strings'|'title'|'description'|'category'|'state'|'insightKey'|'navigationId'|'frameId'>;\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\nexport enum InsightKeys {\n LCP_BREAKDOWN = 'LCPBreakdown',\n INP_BREAKDOWN = 'INPBreakdown',\n CLS_CULPRITS = 'CLSCulprits',\n THIRD_PARTIES = 'ThirdParties',\n DOCUMENT_LATENCY = 'DocumentLatency',\n DOM_SIZE = 'DOMSize',\n DUPLICATE_JAVASCRIPT = 'DuplicatedJavaScript',\n FONT_DISPLAY = 'FontDisplay',\n FORCED_REFLOW = 'ForcedReflow',\n IMAGE_DELIVERY = 'ImageDelivery',\n LCP_DISCOVERY = 'LCPDiscovery',\n LEGACY_JAVASCRIPT = 'LegacyJavaScript',\n NETWORK_DEPENDENCY_TREE = 'NetworkDependencyTree',\n RENDER_BLOCKING = 'RenderBlocking',\n SLOW_CSS_SELECTOR = 'SlowCSSSelector',\n VIEWPORT = 'Viewport',\n MODERN_HTTP = 'ModernHTTP',\n CACHE = 'Cache',\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/types.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,yEAAyE;AACzE,6BAA6B;AAsC7B,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;AAoFD,MAAM,CAAN,IAAY,WAoBX;AApBD,WAAY,WAAW;IACrB,6CAA8B,CAAA;IAC9B,6CAA8B,CAAA;IAC9B,2CAA4B,CAAA;IAC5B,6CAA8B,CAAA;IAC9B,mDAAoC,CAAA;IACpC,mCAAoB,CAAA;IACpB,4DAA6C,CAAA;IAC7C,2CAA4B,CAAA;IAC5B,6CAA8B,CAAA;IAC9B,+CAAgC,CAAA;IAChC,6CAA8B,CAAA;IAC9B,qDAAsC,CAAA;IACtC,gEAAiD,CAAA;IACjD,iDAAkC,CAAA;IAClC,oDAAqC,CAAA;IACrC,oCAAqB,CAAA;IACrB,yCAA0B,CAAA;IAC1B,8BAAe,CAAA;IACf,6CAA8B,CAAA;AAChC,CAAC,EApBW,WAAW,KAAX,WAAW,QAoBtB","sourcesContent":["// Copyright 2024 The Chromium Authors\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 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 options: Types.Configuration.ParseOptions;\n bounds: Types.Timing.TraceWindowMicro;\n frameId: string;\n navigation?: never;\n}\n\nexport interface InsightSetContextWithNavigation {\n options: Types.Configuration.ParseOptions;\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 requests: Array<Lantern.Types.NetworkRequest<Types.Events.SyntheticNetworkRequest>>;\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 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> = Record<string, string>,\n ExtraDetail extends Record<string, unknown> = Record<string, unknown>> =\n ExtraDetail&{\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 docs: string,\n category: InsightCategory,\n state: 'pass' | 'fail' | 'informative',\n /** Used by RelatedInsightChips.ts */\n relatedEvents?: RelatedEventsMap | Types.Events.Event[],\n warnings?: InsightWarning[],\n metricSavings?: MetricSavings,\n /**\n * An estimate for the number of bytes that this insight deems to have been wasted.\n * Bytes are in terms of transfer size: for each component of savings related to an\n * individual request, the insight will estimate its impact on transfer size by using\n * the compression ratio of the resource.\n *\n * This field is only displayed for informational purposes.\n */\n wastedBytes?: number,\n frameId?: string,\n /**\n * If this insight is attached to a navigation, this stores its ID.\n */\n navigation?: Types.Events.NavigationStart,\n /** This is lazily-generated because some insights may create many overlays. */\n createOverlays?: () => Types.Overlays.Overlay[],\n };\n\nexport type PartialInsightModel<T> =\n Omit<T, 'strings'|'title'|'description'|'docs'|'category'|'state'|'insightKey'|'navigationId'|'frameId'>;\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 of the form \"NAVIGATION_(index)\". 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 /** Contains results for all non-errored insights. */\n model: InsightModels;\n /** Contains errors for all insights that had an internal error. */\n modelErrors: InsightModelErrors;\n navigation?: Types.Events.NavigationStart;\n}\n\n/**\n * Contains insights for a specific insight set. If missing, it error'd.\n */\nexport type InsightModels = {\n [I in keyof InsightModelsType]?: ReturnType<InsightModelsType[I]['generateInsight']>;\n};\n\n/**\n * Contains an internal error for each insight in a specific insight set.\n */\nexport type InsightModelErrors = {\n [I in keyof InsightModelsType]?: Error;\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\nexport enum InsightKeys {\n LCP_BREAKDOWN = 'LCPBreakdown',\n INP_BREAKDOWN = 'INPBreakdown',\n CLS_CULPRITS = 'CLSCulprits',\n THIRD_PARTIES = 'ThirdParties',\n DOCUMENT_LATENCY = 'DocumentLatency',\n DOM_SIZE = 'DOMSize',\n DUPLICATE_JAVASCRIPT = 'DuplicatedJavaScript',\n FONT_DISPLAY = 'FontDisplay',\n FORCED_REFLOW = 'ForcedReflow',\n IMAGE_DELIVERY = 'ImageDelivery',\n LCP_DISCOVERY = 'LCPDiscovery',\n LEGACY_JAVASCRIPT = 'LegacyJavaScript',\n NETWORK_DEPENDENCY_TREE = 'NetworkDependencyTree',\n RENDER_BLOCKING = 'RenderBlocking',\n SLOW_CSS_SELECTOR = 'SlowCSSSelector',\n VIEWPORT = 'Viewport',\n MODERN_HTTP = 'ModernHTTP',\n CACHE = 'Cache',\n CHARACTER_SET = 'CharacterSet',\n}\n"]}
@@ -8,13 +8,13 @@
8
8
  "forceConsistentCasingInFileNames": true,
9
9
  "inlineSources": true,
10
10
  "lib": [
11
+ "dom",
12
+ "dom.iterable",
11
13
  "ES2023",
12
14
  "ES2024.Promise",
13
15
  "ESNext.Iterator",
14
16
  "ESNext.Collection",
15
- "ESNext.Array",
16
- "dom",
17
- "dom.iterable"
17
+ "ESNext.Array"
18
18
  ],
19
19
  "module": "esnext",
20
20
  "noEmitOnError": true,
@@ -31,6 +31,7 @@
31
31
  "target": "ES2023",
32
32
  "tsBuildInfoFile": "core-tsconfig.json.tsbuildinfo",
33
33
  "typeRoots": [],
34
+ "types": [],
34
35
  "useUnknownInCatchVariables": false
35
36
  },
36
37
  "files": [