@paulirish/trace_engine 0.0.49 → 0.0.51

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 (225) hide show
  1. package/.tmp/tsbuildinfo/tsconfig.tsbuildinfo +1 -1
  2. package/core/platform/Constructor.d.ts +2 -2
  3. package/core/platform/Constructor.js.map +1 -1
  4. package/core/platform/StringUtilities.d.ts +2 -5
  5. package/core/platform/StringUtilities.js +0 -3
  6. package/core/platform/StringUtilities.js.map +1 -1
  7. package/core/platform/TypescriptUtilities.d.ts +1 -1
  8. package/core/platform/TypescriptUtilities.js +1 -1
  9. package/core/platform/TypescriptUtilities.js.map +1 -1
  10. package/core/platform/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -2
  11. package/core/platform/platform-tsconfig.json +2 -3
  12. package/core/platform/platform.d.ts +1 -2
  13. package/core/platform/platform.js +1 -2
  14. package/core/platform/platform.js.map +1 -1
  15. package/generated/protocol.d.ts +156 -31
  16. package/locales/af.json +63 -3
  17. package/locales/am.json +63 -3
  18. package/locales/ar.json +63 -3
  19. package/locales/as.json +63 -3
  20. package/locales/az.json +63 -3
  21. package/locales/be.json +64 -4
  22. package/locales/bg.json +62 -2
  23. package/locales/bn.json +63 -3
  24. package/locales/bs.json +63 -3
  25. package/locales/ca.json +62 -2
  26. package/locales/cs.json +62 -2
  27. package/locales/cy.json +63 -3
  28. package/locales/da.json +63 -3
  29. package/locales/de.json +63 -3
  30. package/locales/el.json +62 -2
  31. package/locales/en-GB.json +63 -3
  32. package/locales/en-US.json +55 -22
  33. package/locales/en-XL.json +55 -22
  34. package/locales/es-419.json +63 -3
  35. package/locales/es.json +64 -4
  36. package/locales/et.json +64 -4
  37. package/locales/eu.json +79 -19
  38. package/locales/fa.json +62 -2
  39. package/locales/fi.json +63 -3
  40. package/locales/fil.json +63 -3
  41. package/locales/fr-CA.json +63 -3
  42. package/locales/fr.json +63 -3
  43. package/locales/gl.json +62 -2
  44. package/locales/gu.json +63 -3
  45. package/locales/he.json +63 -3
  46. package/locales/hi.json +62 -2
  47. package/locales/hr.json +63 -3
  48. package/locales/hu.json +62 -2
  49. package/locales/hy.json +63 -3
  50. package/locales/id.json +62 -2
  51. package/locales/is.json +64 -4
  52. package/locales/it.json +64 -4
  53. package/locales/ja.json +63 -3
  54. package/locales/ka.json +63 -3
  55. package/locales/kk.json +62 -2
  56. package/locales/km.json +62 -2
  57. package/locales/kn.json +63 -3
  58. package/locales/ko.json +63 -3
  59. package/locales/ky.json +63 -3
  60. package/locales/lo.json +63 -3
  61. package/locales/lt.json +62 -2
  62. package/locales/lv.json +62 -2
  63. package/locales/mk.json +62 -2
  64. package/locales/ml.json +63 -3
  65. package/locales/mn.json +63 -3
  66. package/locales/mr.json +64 -4
  67. package/locales/ms.json +63 -3
  68. package/locales/my.json +63 -3
  69. package/locales/ne.json +64 -4
  70. package/locales/nl.json +63 -3
  71. package/locales/no.json +62 -2
  72. package/locales/or.json +63 -3
  73. package/locales/pa.json +62 -2
  74. package/locales/pl.json +62 -2
  75. package/locales/pt-PT.json +62 -2
  76. package/locales/pt.json +63 -3
  77. package/locales/ro.json +63 -3
  78. package/locales/ru.json +63 -3
  79. package/locales/si.json +63 -3
  80. package/locales/sk.json +63 -3
  81. package/locales/sl.json +62 -2
  82. package/locales/sq.json +63 -3
  83. package/locales/sr-Latn.json +62 -2
  84. package/locales/sr.json +62 -2
  85. package/locales/sv.json +62 -2
  86. package/locales/sw.json +63 -3
  87. package/locales/ta.json +66 -6
  88. package/locales/te.json +63 -3
  89. package/locales/th.json +63 -3
  90. package/locales/tr.json +63 -3
  91. package/locales/uk.json +63 -3
  92. package/locales/ur.json +64 -4
  93. package/locales/uz.json +62 -2
  94. package/locales/vi.json +62 -2
  95. package/locales/zh-HK.json +63 -3
  96. package/locales/zh-TW.json +63 -3
  97. package/locales/zh.json +62 -2
  98. package/locales/zu.json +63 -3
  99. package/models/cpu_profile/CPUProfileDataModel.d.ts +8 -0
  100. package/models/cpu_profile/CPUProfileDataModel.js.map +1 -1
  101. package/models/cpu_profile/cpu_profile-tsconfig.json +2 -2
  102. package/models/cpu_profile/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -2
  103. package/models/trace/Processor.d.ts +1 -1
  104. package/models/trace/Processor.js +94 -74
  105. package/models/trace/Processor.js.map +1 -1
  106. package/models/trace/TracingManager.js.map +1 -1
  107. package/models/trace/bundle-tsconfig.json +1 -1
  108. package/models/trace/devtools_entrypoint-bundle-typescript-tsconfig.json +20 -2
  109. package/models/trace/extras/ScriptDuplication.d.ts +11 -15
  110. package/models/trace/extras/ScriptDuplication.js +59 -77
  111. package/models/trace/extras/ScriptDuplication.js.map +1 -1
  112. package/models/trace/extras/ThirdParties.d.ts +6 -13
  113. package/models/trace/extras/ThirdParties.js +69 -133
  114. package/models/trace/extras/ThirdParties.js.map +1 -1
  115. package/models/trace/extras/TraceTree.d.ts +15 -3
  116. package/models/trace/extras/TraceTree.js +36 -8
  117. package/models/trace/extras/TraceTree.js.map +1 -1
  118. package/models/trace/extras/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -2
  119. package/models/trace/extras/extras-tsconfig.json +2 -2
  120. package/models/trace/extras/extras.d.ts +881 -787
  121. package/models/trace/extras/extras.js +881 -787
  122. package/models/trace/handlers/AsyncJSCallsHandler.js +36 -4
  123. package/models/trace/handlers/AsyncJSCallsHandler.js.map +1 -1
  124. package/models/trace/handlers/InvalidationsHandler.js +1 -0
  125. package/models/trace/handlers/InvalidationsHandler.js.map +1 -1
  126. package/models/trace/handlers/ModelHandlers.d.ts +0 -1
  127. package/models/trace/handlers/ModelHandlers.js +0 -1
  128. package/models/trace/handlers/ModelHandlers.js.map +1 -1
  129. package/models/trace/handlers/NetworkRequestsHandler.js +1 -1
  130. package/models/trace/handlers/NetworkRequestsHandler.js.map +1 -1
  131. package/models/trace/handlers/RendererHandler.d.ts +1 -1
  132. package/models/trace/handlers/RendererHandler.js +2 -2
  133. package/models/trace/handlers/RendererHandler.js.map +1 -1
  134. package/models/trace/handlers/ScreenshotsHandler.js +3 -1
  135. package/models/trace/handlers/ScreenshotsHandler.js.map +1 -1
  136. package/models/trace/handlers/ScriptsHandler.d.ts +12 -0
  137. package/models/trace/handlers/ScriptsHandler.js +93 -1
  138. package/models/trace/handlers/ScriptsHandler.js.map +1 -1
  139. package/models/trace/handlers/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -2
  140. package/models/trace/handlers/handlers-tsconfig.json +2 -3
  141. package/models/trace/helpers/Network.d.ts +5 -0
  142. package/models/trace/helpers/Network.js +17 -0
  143. package/models/trace/helpers/Network.js.map +1 -1
  144. package/models/trace/helpers/SamplesIntegrator.js +19 -23
  145. package/models/trace/helpers/SamplesIntegrator.js.map +1 -1
  146. package/models/trace/helpers/SyntheticEvents.d.ts +0 -1
  147. package/models/trace/helpers/SyntheticEvents.js +0 -4
  148. package/models/trace/helpers/SyntheticEvents.js.map +1 -1
  149. package/models/trace/helpers/Trace.d.ts +2 -1
  150. package/models/trace/helpers/Trace.js +101 -1
  151. package/models/trace/helpers/Trace.js.map +1 -1
  152. package/models/trace/helpers/TreeHelpers.d.ts +2 -5
  153. package/models/trace/helpers/TreeHelpers.js +0 -4
  154. package/models/trace/helpers/TreeHelpers.js.map +1 -1
  155. package/models/trace/helpers/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -2
  156. package/models/trace/helpers/helpers-tsconfig.json +2 -2
  157. package/models/trace/insights/{UseCache.d.ts → Cache.d.ts} +2 -2
  158. package/models/trace/insights/{UseCache.js → Cache.js} +11 -5
  159. package/models/trace/insights/Cache.js.map +1 -0
  160. package/models/trace/insights/Common.d.ts +21 -2
  161. package/models/trace/insights/Common.js +86 -2
  162. package/models/trace/insights/Common.js.map +1 -1
  163. package/models/trace/insights/DocumentLatency.js +2 -8
  164. package/models/trace/insights/DocumentLatency.js.map +1 -1
  165. package/models/trace/insights/DuplicatedJavaScript.d.ts +7 -4
  166. package/models/trace/insights/DuplicatedJavaScript.js +25 -5
  167. package/models/trace/insights/DuplicatedJavaScript.js.map +1 -1
  168. package/models/trace/insights/ForcedReflow.d.ts +5 -1
  169. package/models/trace/insights/ForcedReflow.js +6 -2
  170. package/models/trace/insights/ForcedReflow.js.map +1 -1
  171. package/models/trace/insights/InteractionToNextPaint.d.ts +1 -0
  172. package/models/trace/insights/InteractionToNextPaint.js +3 -0
  173. package/models/trace/insights/InteractionToNextPaint.js.map +1 -1
  174. package/models/trace/insights/LegacyJavaScript.d.ts +32 -0
  175. package/models/trace/insights/LegacyJavaScript.js +77 -0
  176. package/models/trace/insights/LegacyJavaScript.js.map +1 -0
  177. package/models/trace/insights/Models.d.ts +3 -1
  178. package/models/trace/insights/Models.js +3 -1
  179. package/models/trace/insights/Models.js.map +1 -1
  180. package/models/trace/insights/ModernHTTP.d.ts +51 -0
  181. package/models/trace/insights/ModernHTTP.js +187 -0
  182. package/models/trace/insights/ModernHTTP.js.map +1 -0
  183. package/models/trace/insights/NetworkDependencyTree.js +1 -1
  184. package/models/trace/insights/NetworkDependencyTree.js.map +1 -1
  185. package/models/trace/insights/ThirdParties.d.ts +1 -5
  186. package/models/trace/insights/ThirdParties.js +8 -21
  187. package/models/trace/insights/ThirdParties.js.map +1 -1
  188. package/models/trace/insights/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -2
  189. package/models/trace/insights/insights-tsconfig.json +8 -3
  190. package/models/trace/insights/types.d.ts +1 -0
  191. package/models/trace/insights/types.js.map +1 -1
  192. package/models/trace/lantern/core/core-tsconfig.json +2 -2
  193. package/models/trace/lantern/core/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -2
  194. package/models/trace/lantern/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -2
  195. package/models/trace/lantern/graph/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -2
  196. package/models/trace/lantern/graph/graph-tsconfig.json +2 -2
  197. package/models/trace/lantern/lantern-tsconfig.json +2 -2
  198. package/models/trace/lantern/metrics/Metric.d.ts +4 -4
  199. package/models/trace/lantern/metrics/Metric.js +4 -6
  200. package/models/trace/lantern/metrics/Metric.js.map +1 -1
  201. package/models/trace/lantern/metrics/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -2
  202. package/models/trace/lantern/metrics/metrics-tsconfig.json +2 -2
  203. package/models/trace/lantern/simulation/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -2
  204. package/models/trace/lantern/simulation/simulation-tsconfig.json +2 -2
  205. package/models/trace/lantern/types/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -2
  206. package/models/trace/lantern/types/types-tsconfig.json +2 -2
  207. package/models/trace/trace-tsconfig.json +2 -2
  208. package/models/trace/types/Configuration.d.ts +2 -0
  209. package/models/trace/types/Configuration.js.map +1 -1
  210. package/models/trace/types/TraceEvents.d.ts +28 -50
  211. package/models/trace/types/TraceEvents.js +8 -23
  212. package/models/trace/types/TraceEvents.js.map +1 -1
  213. package/models/trace/types/devtools_entrypoint-bundle-typescript-tsconfig.json +2 -2
  214. package/models/trace/types/types-tsconfig.json +2 -2
  215. package/package.json +3 -2
  216. package/test/test-trace-engine.mjs +19 -17
  217. package/third_party/legacy-javascript/legacy-javascript.d.ts +1 -0
  218. package/third_party/legacy-javascript/legacy-javascript.js +1 -0
  219. package/core/platform/ServerTiming.d.ts +0 -31
  220. package/core/platform/ServerTiming.js +0 -212
  221. package/core/platform/ServerTiming.js.map +0 -1
  222. package/models/trace/handlers/ServerTimingsHandler.d.ts +0 -9
  223. package/models/trace/handlers/ServerTimingsHandler.js +0 -106
  224. package/models/trace/handlers/ServerTimingsHandler.js.map +0 -1
  225. package/models/trace/insights/UseCache.js.map +0 -1
@@ -12,12 +12,15 @@ export declare const UIStrings: {
12
12
  readonly description: "Remove large, duplicate JavaScript modules from bundles to reduce unnecessary bytes consumed by network activity.";
13
13
  /** Label for a column in a data table; entries will be the locations of JavaScript or CSS code, e.g. the name of a Javascript package or module. */
14
14
  readonly columnSource: "Source";
15
- /** Label for a column in a data table; entries will be the file size of a web resource in kilobytes. */
16
- readonly columnResourceSize: "Resource size";
15
+ /** Label for a column in a data table; entries will be the number of wasted bytes due to duplication of a web resource. */
16
+ readonly columnDuplicatedBytes: "Duplicated bytes";
17
17
  };
18
18
  export declare const i18nString: (id: string, values?: Record<string, string> | undefined) => Record<string, string>;
19
- export type DuplicateJavaScriptInsightModel = InsightModel<typeof UIStrings, {
19
+ export type DuplicatedJavaScriptInsightModel = InsightModel<typeof UIStrings, {
20
20
  duplication: Extras.ScriptDuplication.ScriptDuplication;
21
+ duplicationGroupedByNodeModules: Extras.ScriptDuplication.ScriptDuplication;
21
22
  scriptsWithDuplication: Handlers.ModelHandlers.Scripts.Script[];
23
+ scripts: Handlers.ModelHandlers.Scripts.Script[];
24
+ mainDocumentUrl: string;
22
25
  }>;
23
- export declare function generateInsight(parsedTrace: Handlers.Types.ParsedTrace, context: InsightSetContext): DuplicateJavaScriptInsightModel;
26
+ export declare function generateInsight(parsedTrace: Handlers.Types.ParsedTrace, context: InsightSetContext): DuplicatedJavaScriptInsightModel;
@@ -4,6 +4,7 @@
4
4
  // import * as i18n from '../../../core/i18n/i18n.js';
5
5
  import * as Extras from '../extras/extras.js';
6
6
  import * as Helpers from '../helpers/helpers.js';
7
+ import { estimateCompressionRatioForScript, metricSavingsForWastedBytes } from './Common.js';
7
8
  import { InsightCategory, } from './types.js';
8
9
  export const UIStrings = {
9
10
  /**
@@ -16,14 +17,13 @@ export const UIStrings = {
16
17
  description: 'Remove large, duplicate JavaScript modules from bundles to reduce unnecessary bytes consumed by network activity.',
17
18
  /** Label for a column in a data table; entries will be the locations of JavaScript or CSS code, e.g. the name of a Javascript package or module. */
18
19
  columnSource: 'Source',
19
- /** Label for a column in a data table; entries will be the file size of a web resource in kilobytes. */
20
- columnResourceSize: 'Resource size',
20
+ /** Label for a column in a data table; entries will be the number of wasted bytes due to duplication of a web resource. */
21
+ columnDuplicatedBytes: 'Duplicated bytes',
21
22
  };
22
23
  // const str_ = i18n.i18n.registerUIStrings('models/trace/insights/DuplicatedJavaScript.ts', UIStrings);
23
24
  export const i18nString = (i18nId, values) => ({i18nId, values}); // i18n.i18n.getLocalizedString.bind(undefined, str_);
24
25
  function finalize(partialModel) {
25
- const requests = partialModel.scriptsWithDuplication.map(script => script.request)
26
- .filter(e => !!e); // eslint-disable-line no-implicit-coercion
26
+ const requests = partialModel.scriptsWithDuplication.map(script => script.request).filter(e => !!e);
27
27
  return {
28
28
  insightKey: "DuplicatedJavaScript" /* InsightKeys.DUPLICATE_JAVASCRIPT */,
29
29
  strings: UIStrings,
@@ -43,13 +43,33 @@ export function generateInsight(parsedTrace, context) {
43
43
  if (script.frame !== context.frameId) {
44
44
  return false;
45
45
  }
46
+ if (script.url?.startsWith('chrome-extension://')) {
47
+ return false;
48
+ }
46
49
  return Helpers.Timing.timestampIsInBounds(context.bounds, script.ts);
47
50
  });
48
- const duplication = Extras.ScriptDuplication.computeScriptDuplication({ scripts });
51
+ const { duplication, duplicationGroupedByNodeModules } = Extras.ScriptDuplication.computeScriptDuplication({ scripts });
49
52
  const scriptsWithDuplication = [...duplication.values().flatMap(data => data.duplicates.map(d => d.script))];
53
+ const wastedBytesByRequestId = new Map();
54
+ for (const { duplicates } of duplication.values()) {
55
+ for (let i = 1; i < duplicates.length; i++) {
56
+ const sourceData = duplicates[i];
57
+ if (!sourceData.script.request) {
58
+ continue;
59
+ }
60
+ const compressionRatio = estimateCompressionRatioForScript(sourceData.script);
61
+ const transferSize = Math.round(sourceData.attributedSize * compressionRatio);
62
+ const requestId = sourceData.script.request.args.data.requestId;
63
+ wastedBytesByRequestId.set(requestId, (wastedBytesByRequestId.get(requestId) || 0) + transferSize);
64
+ }
65
+ }
50
66
  return finalize({
51
67
  duplication,
68
+ duplicationGroupedByNodeModules,
52
69
  scriptsWithDuplication: [...new Set(scriptsWithDuplication)],
70
+ scripts,
71
+ mainDocumentUrl: context.navigation?.args.data?.url ?? parsedTrace.Meta.mainFrameURL,
72
+ metricSavings: metricSavingsForWastedBytes(wastedBytesByRequestId, context),
53
73
  });
54
74
  }
55
75
  //# sourceMappingURL=DuplicatedJavaScript.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"DuplicatedJavaScript.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/DuplicatedJavaScript.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,yEAAyE;AACzE,6BAA6B;AAE7B,OAAO,KAAK,IAAI,MAAM,4BAA4B,CAAC;AACnD,OAAO,KAAK,MAAM,MAAM,qBAAqB,CAAC;AAE9C,OAAO,KAAK,OAAO,MAAM,uBAAuB,CAAC;AAEjD,OAAO,EACL,eAAe,GAKhB,MAAM,YAAY,CAAC;AAEpB,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB;;OAEG;IACH,KAAK,EAAE,uBAAuB;IAC9B;;OAEG;IACH,WAAW,EACP,mHAAmH;IACvH,oJAAoJ;IACpJ,YAAY,EAAE,QAAQ;IACtB,wGAAwG;IACxG,kBAAkB,EAAE,eAAe;CAC3B,CAAC;AAEX,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,+CAA+C,EAAE,SAAS,CAAC,CAAC;AACrG,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;AAO7E,SAAS,QAAQ,CAAC,YAAkE;IAClF,MAAM,QAAQ,GAAG,YAAY,CAAC,sBAAsB,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC;SAC5D,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,2CAA2C;IAEpF,OAAO;QACL,UAAU,+DAAkC;QAC5C,OAAO,EAAE,SAAS;QAClB,KAAK,EAAE,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC;QAClC,WAAW,EAAE,UAAU,CAAC,SAAS,CAAC,WAAW,CAAC;QAC9C,QAAQ,EAAE,eAAe,CAAC,GAAG;QAC7B,KAAK,EAAE,OAAO,CAAC,YAAY,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM;QAChF,aAAa,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;QACrC,GAAG,YAAY;KAChB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAC3B,WAAuC,EAAE,OAA0B;IACrE,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE;QAC1D,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;YACxB,OAAO,KAAK,CAAC;QACf,CAAC;QAED,IAAI,MAAM,CAAC,KAAK,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC;YACrC,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,OAAO,CAAC,MAAM,CAAC,mBAAmB,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;IAEH,MAAM,WAAW,GAAG,MAAM,CAAC,iBAAiB,CAAC,wBAAwB,CAAC,EAAC,OAAO,EAAC,CAAC,CAAC;IACjF,MAAM,sBAAsB,GAAG,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAC7G,OAAO,QAAQ,CAAC;QACd,WAAW;QACX,sBAAsB,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,sBAAsB,CAAC,CAAC;KAC7D,CAAC,CAAC;AACL,CAAC","sourcesContent":["// Copyright 2025 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as i18n from '../../../core/i18n/i18n.js';\nimport * as Extras from '../extras/extras.js';\nimport type * as Handlers from '../handlers/handlers.js';\nimport * as Helpers from '../helpers/helpers.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 identifies multiple copies of the same JavaScript sources, and recommends removing the duplication.\n */\n title: 'Duplicated JavaScript',\n /**\n * @description Description of an insight that identifies multiple copies of the same JavaScript sources, and recommends removing the duplication.\n */\n description:\n 'Remove large, duplicate JavaScript modules from bundles to reduce unnecessary bytes consumed by network activity.',\n /** Label for a column in a data table; entries will be the locations of JavaScript or CSS code, e.g. the name of a Javascript package or module. */\n columnSource: 'Source',\n /** Label for a column in a data table; entries will be the file size of a web resource in kilobytes. */\n columnResourceSize: 'Resource size',\n} as const;\n\nconst str_ = i18n.i18n.registerUIStrings('models/trace/insights/DuplicatedJavaScript.ts', UIStrings);\nexport const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);\n\nexport type DuplicateJavaScriptInsightModel = InsightModel<typeof UIStrings, {\n duplication: Extras.ScriptDuplication.ScriptDuplication,\n scriptsWithDuplication: Handlers.ModelHandlers.Scripts.Script[],\n}>;\n\nfunction finalize(partialModel: PartialInsightModel<DuplicateJavaScriptInsightModel>): DuplicateJavaScriptInsightModel {\n const requests = partialModel.scriptsWithDuplication.map(script => script.request)\n .filter(e => !!e); // eslint-disable-line no-implicit-coercion\n\n return {\n insightKey: InsightKeys.DUPLICATE_JAVASCRIPT,\n strings: UIStrings,\n title: i18nString(UIStrings.title),\n description: i18nString(UIStrings.description),\n category: InsightCategory.LCP,\n state: Boolean(partialModel.duplication.values().next().value) ? 'fail' : 'pass',\n relatedEvents: [...new Set(requests)],\n ...partialModel,\n };\n}\n\nexport function generateInsight(\n parsedTrace: Handlers.Types.ParsedTrace, context: InsightSetContext): DuplicateJavaScriptInsightModel {\n const scripts = parsedTrace.Scripts.scripts.filter(script => {\n if (!context.navigation) {\n return false;\n }\n\n if (script.frame !== context.frameId) {\n return false;\n }\n\n return Helpers.Timing.timestampIsInBounds(context.bounds, script.ts);\n });\n\n const duplication = Extras.ScriptDuplication.computeScriptDuplication({scripts});\n const scriptsWithDuplication = [...duplication.values().flatMap(data => data.duplicates.map(d => d.script))];\n return finalize({\n duplication,\n scriptsWithDuplication: [...new Set(scriptsWithDuplication)],\n });\n}\n"]}
1
+ {"version":3,"file":"DuplicatedJavaScript.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/DuplicatedJavaScript.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2025 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as i18n from '../../../core/i18n/i18n.js';\nimport * as Extras from '../extras/extras.js';\nimport type * as Handlers from '../handlers/handlers.js';\nimport * as Helpers from '../helpers/helpers.js';\n\nimport {estimateCompressionRatioForScript, metricSavingsForWastedBytes} from './Common.js';\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 identifies multiple copies of the same JavaScript sources, and recommends removing the duplication.\n */\n title: 'Duplicated JavaScript',\n /**\n * @description Description of an insight that identifies multiple copies of the same JavaScript sources, and recommends removing the duplication.\n */\n description:\n 'Remove large, duplicate JavaScript modules from bundles to reduce unnecessary bytes consumed by network activity.',\n /** Label for a column in a data table; entries will be the locations of JavaScript or CSS code, e.g. the name of a Javascript package or module. */\n columnSource: 'Source',\n /** Label for a column in a data table; entries will be the number of wasted bytes due to duplication of a web resource. */\n columnDuplicatedBytes: 'Duplicated bytes',\n} as const;\n\nconst str_ = i18n.i18n.registerUIStrings('models/trace/insights/DuplicatedJavaScript.ts', UIStrings);\nexport const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);\n\nexport type DuplicatedJavaScriptInsightModel = InsightModel<typeof UIStrings, {\n duplication: Extras.ScriptDuplication.ScriptDuplication,\n duplicationGroupedByNodeModules: Extras.ScriptDuplication.ScriptDuplication,\n scriptsWithDuplication: Handlers.ModelHandlers.Scripts.Script[],\n scripts: Handlers.ModelHandlers.Scripts.Script[],\n mainDocumentUrl: string,\n}>;\n\nfunction finalize(partialModel: PartialInsightModel<DuplicatedJavaScriptInsightModel>):\n DuplicatedJavaScriptInsightModel {\n const requests = partialModel.scriptsWithDuplication.map(script => script.request).filter(e => !!e);\n\n return {\n insightKey: InsightKeys.DUPLICATE_JAVASCRIPT,\n strings: UIStrings,\n title: i18nString(UIStrings.title),\n description: i18nString(UIStrings.description),\n category: InsightCategory.LCP,\n state: Boolean(partialModel.duplication.values().next().value) ? 'fail' : 'pass',\n relatedEvents: [...new Set(requests)],\n ...partialModel,\n };\n}\n\nexport function generateInsight(\n parsedTrace: Handlers.Types.ParsedTrace, context: InsightSetContext): DuplicatedJavaScriptInsightModel {\n const scripts = parsedTrace.Scripts.scripts.filter(script => {\n if (!context.navigation) {\n return false;\n }\n\n if (script.frame !== context.frameId) {\n return false;\n }\n\n if (script.url?.startsWith('chrome-extension://')) {\n return false;\n }\n\n return Helpers.Timing.timestampIsInBounds(context.bounds, script.ts);\n });\n\n const {duplication, duplicationGroupedByNodeModules} = Extras.ScriptDuplication.computeScriptDuplication({scripts});\n const scriptsWithDuplication = [...duplication.values().flatMap(data => data.duplicates.map(d => d.script))];\n\n const wastedBytesByRequestId = new Map<string, number>();\n for (const {duplicates} of duplication.values()) {\n for (let i = 1; i < duplicates.length; i++) {\n const sourceData = duplicates[i];\n if (!sourceData.script.request) {\n continue;\n }\n\n const compressionRatio = estimateCompressionRatioForScript(sourceData.script);\n const transferSize = Math.round(sourceData.attributedSize * compressionRatio);\n const requestId = sourceData.script.request.args.data.requestId;\n wastedBytesByRequestId.set(requestId, (wastedBytesByRequestId.get(requestId) || 0) + transferSize);\n }\n }\n\n return finalize({\n duplication,\n duplicationGroupedByNodeModules,\n scriptsWithDuplication: [...new Set(scriptsWithDuplication)],\n scripts,\n mainDocumentUrl: context.navigation?.args.data?.url ?? parsedTrace.Meta.mainFrameURL,\n metricSavings: metricSavingsForWastedBytes(wastedBytesByRequestId, context),\n });\n}\n"]}
@@ -27,7 +27,11 @@ export declare const UIStrings: {
27
27
  /**
28
28
  * @description Text to describe CPU processor tasks that could not be attributed to any specific source code.
29
29
  */
30
- readonly unattributed: "Unattributed";
30
+ readonly unattributed: "[unattributed]";
31
+ /**
32
+ * @description Text for the name of anonymous functions
33
+ */
34
+ readonly anonymous: "(anonymous)";
31
35
  };
32
36
  export declare const i18nString: (id: string, values?: Record<string, string> | undefined) => {i18nId: string, values: Record<string, string|number>, formattedDefault: string};
33
37
  export type ForcedReflowInsightModel = InsightModel<typeof UIStrings, {
@@ -31,7 +31,11 @@ export const UIStrings = {
31
31
  /**
32
32
  * @description Text to describe CPU processor tasks that could not be attributed to any specific source code.
33
33
  */
34
- unattributed: 'Unattributed',
34
+ unattributed: '[unattributed]',
35
+ /**
36
+ * @description Text for the name of anonymous functions
37
+ */
38
+ anonymous: '(anonymous)',
35
39
  };
36
40
  // const str_ = i18n.i18n.registerUIStrings('models/trace/insights/ForcedReflow.ts', UIStrings);
37
41
  export const i18nString = (i18nId, values) => ({i18nId, values}); // i18n.i18n.getLocalizedString.bind(undefined, str_);
@@ -103,7 +107,7 @@ function finalize(partialModel) {
103
107
  }
104
108
  function getBottomCallFrameForEvent(event, traceParsedData) {
105
109
  const profileStackTrace = Extras.StackTraceForEvent.get(event, traceParsedData);
106
- const eventStackTrace = Helpers.Trace.getZeroIndexedStackTraceForEvent(event);
110
+ const eventStackTrace = Helpers.Trace.getZeroIndexedStackTraceInEventPayload(event);
107
111
  return profileStackTrace?.callFrames[0] ?? eventStackTrace?.[0] ?? null;
108
112
  }
109
113
  export function generateInsight(traceParsedData, context) {
@@ -1 +1 @@
1
- {"version":3,"file":"ForcedReflow.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/ForcedReflow.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,yEAAyE;AACzE,6BAA6B;AAE7B,OAAO,KAAK,IAAI,MAAM,4BAA4B,CAAC;AACnD,OAAO,KAAK,QAAQ,MAAM,oCAAoC,CAAC;AAE/D,OAAO,KAAK,MAAM,MAAM,qBAAqB,CAAC;AAE9C,OAAO,KAAK,OAAO,MAAM,uBAAuB,CAAC;AACjD,OAAO,KAAK,KAAK,MAAM,mBAAmB,CAAC;AAE3C,OAAO,EACL,eAAe,GAKhB,MAAM,YAAY,CAAC;AAEpB,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB;;OAEG;IACH,KAAK,EAAE,eAAe;IACtB;;OAEG;IACH,WAAW,EACP,8VAA8V;IAClW;;OAEG;IACH,iBAAiB,EAAE,aAAa;IAChC;;OAEG;IACH,4BAA4B,EAAE,mBAAmB;IACjD;;OAEG;IACH,eAAe,EAAE,mBAAmB;IACpC;;OAEG;IACH,YAAY,EAAE,cAAc;CACpB,CAAC;AAEX,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,uCAAuC,EAAE,SAAS,CAAC,CAAC;AAC7F,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;AAsB7E,SAAS,cAAc,CAAC,SAA4D;IAClF,OAAO,SAAS,CAAC,QAAQ,GAAG,GAAG,GAAG,SAAS,CAAC,UAAU,GAAG,GAAG,GAAG,SAAS,CAAC,YAAY,CAAC;AACxF,CAAC;AAED,SAAS,8BAA8B,CACnC,kBAAwC,EAAE,eAA2C;IAEvF,MAAM,cAAc,GAAG,eAAe,CAAC,QAAQ,CAAC,WAAW,CAAC;IAC5D,MAAM,sBAAsB,GAAG,IAAI,GAAG,EAAsC,CAAC;IAC7E,IAAI,kBAAkB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpC,OAAO;IACT,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,kBAAkB,EAAE,CAAC;QACvC,mDAAmD;QACnD,MAAM,SAAS,GAAG,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC5C,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,SAAS;QACX,CAAC;QAED,IAAI,IAAI,GAAG,SAAS,CAAC,MAAM,CAAC;QAC5B,IAAI,oBAAoB,CAAC;QACzB,IAAI,yBAAuD,CAAC;QAC5D,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC;YAC7B,IAAI,KAAK,CAAC,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC1C,oBAAoB,GAAG,SAAS,CAAC,SAAS,CAAC;gBAC3C,yBAAyB,GAAG,SAAS,CAAC;YACxC,CAAC;iBAAM,CAAC;gBACN,4CAA4C;gBAC5C,IAAI,KAAK,CAAC,MAAM,CAAC,cAAc,CAAC,SAAS,CAAC,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI;oBAC7D,KAAK,CAAC,MAAM,CAAC,iBAAiB,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;oBACxD,oBAAoB,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC;oBAC3C,yBAAyB,GAAG,SAAS,CAAC;gBACxC,CAAC;gBACD,MAAM;YACR,CAAC;YACD,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC;QACrB,CAAC;QAED,IAAI,CAAC,oBAAoB,IAAI,CAAC,yBAAyB,EAAE,CAAC;YACxD,SAAS;QACX,CAAC;QAED,MAAM,gBAAgB,GAAG,cAAc,CAAC,oBAAoB,CAAC,CAAC;QAC9D,MAAM,cAAc,GAChB,QAAQ,CAAC,YAAY,CAAC,cAAc,CAAC,sBAAsB,EAAE,gBAAgB,EAAE,GAAG,EAAE,CAAC,CAAC;YACL,oBAAoB;YACpB,eAAe,EAAE,CAAC;YAClB,0BAA0B,EAAE,EAAE;SAC/B,CAAC,CAAC,CAAC;QACvF,cAAc,CAAC,eAAe,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;QACnD,cAAc,CAAC,0BAA0B,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;IAC5E,CAAC;IAED,IAAI,oBAAoB,GAAyC,SAAS,CAAC;IAC3E,sBAAsB,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;QACpC,IAAI,CAAC,oBAAoB,IAAI,IAAI,CAAC,eAAe,GAAG,oBAAoB,CAAC,eAAe,EAAE,CAAC;YACzF,oBAAoB,GAAG,IAAI,CAAC;QAC9B,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,oBAAoB,CAAC;AAC9B,CAAC;AAED,SAAS,QAAQ,CAAC,YAA2D;IAC3E,OAAO;QACL,UAAU,gDAA2B;QACrC,OAAO,EAAE,SAAS;QAClB,KAAK,EAAE,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC;QAClC,WAAW,EAAE,UAAU,CAAC,SAAS,CAAC,WAAW,CAAC;QAC9C,QAAQ,EAAE,eAAe,CAAC,GAAG;QAC7B,KAAK,EAAE,YAAY,CAAC,sBAAsB,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM;QACzE,GAAG,YAAY;KAChB,CAAC;AACJ,CAAC;AAED,SAAS,0BAA0B,CAAC,KAAyB,EAAE,eAA2C;IAExG,MAAM,iBAAiB,GAAG,MAAM,CAAC,kBAAkB,CAAC,GAAG,CAAC,KAAK,EAAE,eAAe,CAAC,CAAC;IAChF,MAAM,eAAe,GAAG,OAAO,CAAC,KAAK,CAAC,gCAAgC,CAAC,KAAK,CAAC,CAAC;IAE9E,OAAO,iBAAiB,EAAE,UAAU,CAAC,CAAC,CAAC,IAAI,eAAe,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AAC1E,CAAC;AAED,MAAM,UAAU,eAAe,CAC3B,eAA2C,EAAE,OAA0B;IACzE,MAAM,eAAe,GAAG,CAAC,KAAyB,EAAW,EAAE;QAC7D,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QACrD,IAAI,OAAO,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC;YAChC,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/D,CAAC,CAAC;IAEF,MAAM,eAAe,GAAG,IAAI,GAAG,EAA6B,CAAC;IAC7D,MAAM,MAAM,GAAG,eAAe,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC;IACvG,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,eAAe,GAAG,0BAA0B,CAAC,KAAK,EAAE,eAAe,CAAC,CAAC;QAC3E,MAAM,YAAY,GAAG,eAAe,CAAC,CAAC,CAAC,cAAc,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC;QACxF,MAAM,YAAY,GACd,QAAQ,CAAC,YAAY,CAAC,cAAc,CAAC,eAAe,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC;YACL,YAAY,EAAE,eAAe;YAC7B,SAAS,EAAE,CAAC;YACZ,aAAa,EAAE,EAAE;SAClB,CAAC,CAAC,CAAC;QAC5E,YAAY,CAAC,SAAS,IAAI,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC;QACzC,YAAY,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACzC,CAAC;IAED,MAAM,wBAAwB,GAAG,8BAA8B,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAEzF,OAAO,QAAQ,CAAC;QACd,aAAa,EAAE,MAAM;QACrB,wBAAwB;QACxB,sBAAsB,EAAE,CAAC,GAAG,eAAe,CAAC,MAAM,EAAE,CAAC;KACtD,CAAC,CAAC;AACL,CAAC","sourcesContent":["// Copyright 2024 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as i18n from '../../../core/i18n/i18n.js';\nimport * as Platform from '../../../core/platform/platform.js';\nimport type * as Protocol from '../../../generated/protocol.js';\nimport * as Extras from '../extras/extras.js';\nimport type * 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 type PartialInsightModel,\n} from './types.js';\n\nexport const UIStrings = {\n /**\n *@description Title of an insight that provides details about Forced reflow.\n */\n title: 'Forced reflow',\n /**\n * @description Text to describe the forced reflow.\n */\n description:\n 'Many APIs, typically reading layout geometry, force the rendering engine to pause script execution in order to calculate the style and layout. Learn more about [forced reflow](https://developers.google.com/web/fundamentals/performance/rendering/avoid-large-complex-layouts-and-layout-thrashing#avoid-forced-synchronous-layouts) and its mitigations.',\n /**\n *@description Title of a list to provide related stack trace data\n */\n relatedStackTrace: 'Stack trace',\n /**\n *@description Text to describe the top time-consuming function call\n */\n topTimeConsumingFunctionCall: 'Top function call',\n /**\n * @description Text to describe the total reflow time\n */\n totalReflowTime: 'Total reflow time',\n /**\n * @description Text to describe CPU processor tasks that could not be attributed to any specific source code.\n */\n unattributed: 'Unattributed',\n} as const;\n\nconst str_ = i18n.i18n.registerUIStrings('models/trace/insights/ForcedReflow.ts', UIStrings);\nexport const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);\n\nexport type ForcedReflowInsightModel = InsightModel<typeof UIStrings, {\n topLevelFunctionCallData: ForcedReflowAggregatedData | undefined,\n aggregatedBottomUpData: BottomUpCallStack[],\n}>;\n\nexport interface BottomUpCallStack {\n /**\n * `null` indicates that this data is for unattributed force reflows.\n */\n bottomUpData: Types.Events.CallFrame|Protocol.Runtime.CallFrame|null;\n totalTime: number;\n relatedEvents: Types.Events.Event[];\n}\n\nexport interface ForcedReflowAggregatedData {\n topLevelFunctionCall: Types.Events.CallFrame|Protocol.Runtime.CallFrame;\n totalReflowTime: number;\n topLevelFunctionCallEvents: Types.Events.Event[];\n}\n\nfunction getCallFrameId(callFrame: Types.Events.CallFrame|Protocol.Runtime.CallFrame): string {\n return callFrame.scriptId + ':' + callFrame.lineNumber + ':' + callFrame.columnNumber;\n}\n\nfunction getLargestTopLevelFunctionData(\n forcedReflowEvents: Types.Events.Event[], traceParsedData: Handlers.Types.ParsedTrace): ForcedReflowAggregatedData|\n undefined {\n const entryToNodeMap = traceParsedData.Renderer.entryToNode;\n const dataByTopLevelFunction = new Map<string, ForcedReflowAggregatedData>();\n if (forcedReflowEvents.length === 0) {\n return;\n }\n\n for (const event of forcedReflowEvents) {\n // Gather the stack traces by searching in the tree\n const traceNode = entryToNodeMap.get(event);\n if (!traceNode) {\n continue;\n }\n\n let node = traceNode.parent;\n let topLevelFunctionCall;\n let topLevelFunctionCallEvent: Types.Events.Event|undefined;\n while (node) {\n const eventData = node.entry;\n if (Types.Events.isProfileCall(eventData)) {\n topLevelFunctionCall = eventData.callFrame;\n topLevelFunctionCallEvent = eventData;\n } else {\n // We have finished searching bottom up data\n if (Types.Events.isFunctionCall(eventData) && eventData.args.data &&\n Types.Events.objectIsCallFrame(eventData.args.data)) {\n topLevelFunctionCall = eventData.args.data;\n topLevelFunctionCallEvent = eventData;\n }\n break;\n }\n node = node.parent;\n }\n\n if (!topLevelFunctionCall || !topLevelFunctionCallEvent) {\n continue;\n }\n\n const aggregatedDataId = getCallFrameId(topLevelFunctionCall);\n const aggregatedData =\n Platform.MapUtilities.getWithDefault(dataByTopLevelFunction, aggregatedDataId, () => ({\n topLevelFunctionCall,\n totalReflowTime: 0,\n topLevelFunctionCallEvents: [],\n }));\n aggregatedData.totalReflowTime += (event.dur ?? 0);\n aggregatedData.topLevelFunctionCallEvents.push(topLevelFunctionCallEvent);\n }\n\n let topTimeConsumingData: ForcedReflowAggregatedData|undefined = undefined;\n dataByTopLevelFunction.forEach(data => {\n if (!topTimeConsumingData || data.totalReflowTime > topTimeConsumingData.totalReflowTime) {\n topTimeConsumingData = data;\n }\n });\n\n return topTimeConsumingData;\n}\n\nfunction finalize(partialModel: PartialInsightModel<ForcedReflowInsightModel>): ForcedReflowInsightModel {\n return {\n insightKey: InsightKeys.FORCED_REFLOW,\n strings: UIStrings,\n title: i18nString(UIStrings.title),\n description: i18nString(UIStrings.description),\n category: InsightCategory.ALL,\n state: partialModel.aggregatedBottomUpData.length !== 0 ? 'fail' : 'pass',\n ...partialModel,\n };\n}\n\nfunction getBottomCallFrameForEvent(event: Types.Events.Event, traceParsedData: Handlers.Types.ParsedTrace):\n Types.Events.CallFrame|Protocol.Runtime.CallFrame|null {\n const profileStackTrace = Extras.StackTraceForEvent.get(event, traceParsedData);\n const eventStackTrace = Helpers.Trace.getZeroIndexedStackTraceForEvent(event);\n\n return profileStackTrace?.callFrames[0] ?? eventStackTrace?.[0] ?? null;\n}\n\nexport function generateInsight(\n traceParsedData: Handlers.Types.ParsedTrace, context: InsightSetContext): ForcedReflowInsightModel {\n const isWithinContext = (event: Types.Events.Event): boolean => {\n const frameId = Helpers.Trace.frameIDForEvent(event);\n if (frameId !== context.frameId) {\n return false;\n }\n\n return Helpers.Timing.eventIsInBounds(event, context.bounds);\n };\n\n const bottomUpDataMap = new Map<string, BottomUpCallStack>();\n const events = traceParsedData.Warnings.perWarning.get('FORCED_REFLOW')?.filter(isWithinContext) ?? [];\n for (const event of events) {\n const bottomCallFrame = getBottomCallFrameForEvent(event, traceParsedData);\n const bottomCallId = bottomCallFrame ? getCallFrameId(bottomCallFrame) : 'UNATTRIBUTED';\n const bottomUpData =\n Platform.MapUtilities.getWithDefault(bottomUpDataMap, bottomCallId, () => ({\n bottomUpData: bottomCallFrame,\n totalTime: 0,\n relatedEvents: [],\n }));\n bottomUpData.totalTime += event.dur ?? 0;\n bottomUpData.relatedEvents.push(event);\n }\n\n const topLevelFunctionCallData = getLargestTopLevelFunctionData(events, traceParsedData);\n\n return finalize({\n relatedEvents: events,\n topLevelFunctionCallData,\n aggregatedBottomUpData: [...bottomUpDataMap.values()],\n });\n}\n"]}
1
+ {"version":3,"file":"ForcedReflow.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/ForcedReflow.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,yEAAyE;AACzE,6BAA6B;AAE7B,OAAO,KAAK,IAAI,MAAM,4BAA4B,CAAC;AACnD,OAAO,KAAK,QAAQ,MAAM,oCAAoC,CAAC;AAE/D,OAAO,KAAK,MAAM,MAAM,qBAAqB,CAAC;AAE9C,OAAO,KAAK,OAAO,MAAM,uBAAuB,CAAC;AACjD,OAAO,KAAK,KAAK,MAAM,mBAAmB,CAAC;AAE3C,OAAO,EACL,eAAe,GAKhB,MAAM,YAAY,CAAC;AAEpB,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB;;OAEG;IACH,KAAK,EAAE,eAAe;IACtB;;OAEG;IACH,WAAW,EACP,8VAA8V;IAClW;;OAEG;IACH,iBAAiB,EAAE,aAAa;IAChC;;OAEG;IACH,4BAA4B,EAAE,mBAAmB;IACjD;;OAEG;IACH,eAAe,EAAE,mBAAmB;IACpC;;OAEG;IACH,YAAY,EAAE,gBAAgB;IAC9B;;OAEG;IACH,SAAS,EAAE,aAAa;CAChB,CAAC;AAEX,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,uCAAuC,EAAE,SAAS,CAAC,CAAC;AAC7F,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;AAsB7E,SAAS,cAAc,CAAC,SAA4D;IAClF,OAAO,SAAS,CAAC,QAAQ,GAAG,GAAG,GAAG,SAAS,CAAC,UAAU,GAAG,GAAG,GAAG,SAAS,CAAC,YAAY,CAAC;AACxF,CAAC;AAED,SAAS,8BAA8B,CACnC,kBAAwC,EAAE,eAA2C;IAEvF,MAAM,cAAc,GAAG,eAAe,CAAC,QAAQ,CAAC,WAAW,CAAC;IAC5D,MAAM,sBAAsB,GAAG,IAAI,GAAG,EAAsC,CAAC;IAC7E,IAAI,kBAAkB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpC,OAAO;IACT,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,kBAAkB,EAAE,CAAC;QACvC,mDAAmD;QACnD,MAAM,SAAS,GAAG,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC5C,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,SAAS;QACX,CAAC;QAED,IAAI,IAAI,GAAG,SAAS,CAAC,MAAM,CAAC;QAC5B,IAAI,oBAAoB,CAAC;QACzB,IAAI,yBAAuD,CAAC;QAC5D,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC;YAC7B,IAAI,KAAK,CAAC,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC1C,oBAAoB,GAAG,SAAS,CAAC,SAAS,CAAC;gBAC3C,yBAAyB,GAAG,SAAS,CAAC;YACxC,CAAC;iBAAM,CAAC;gBACN,4CAA4C;gBAC5C,IAAI,KAAK,CAAC,MAAM,CAAC,cAAc,CAAC,SAAS,CAAC,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI;oBAC7D,KAAK,CAAC,MAAM,CAAC,iBAAiB,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;oBACxD,oBAAoB,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC;oBAC3C,yBAAyB,GAAG,SAAS,CAAC;gBACxC,CAAC;gBACD,MAAM;YACR,CAAC;YACD,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC;QACrB,CAAC;QAED,IAAI,CAAC,oBAAoB,IAAI,CAAC,yBAAyB,EAAE,CAAC;YACxD,SAAS;QACX,CAAC;QAED,MAAM,gBAAgB,GAAG,cAAc,CAAC,oBAAoB,CAAC,CAAC;QAC9D,MAAM,cAAc,GAChB,QAAQ,CAAC,YAAY,CAAC,cAAc,CAAC,sBAAsB,EAAE,gBAAgB,EAAE,GAAG,EAAE,CAAC,CAAC;YACL,oBAAoB;YACpB,eAAe,EAAE,CAAC;YAClB,0BAA0B,EAAE,EAAE;SAC/B,CAAC,CAAC,CAAC;QACvF,cAAc,CAAC,eAAe,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;QACnD,cAAc,CAAC,0BAA0B,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;IAC5E,CAAC;IAED,IAAI,oBAAoB,GAAyC,SAAS,CAAC;IAC3E,sBAAsB,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;QACpC,IAAI,CAAC,oBAAoB,IAAI,IAAI,CAAC,eAAe,GAAG,oBAAoB,CAAC,eAAe,EAAE,CAAC;YACzF,oBAAoB,GAAG,IAAI,CAAC;QAC9B,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,oBAAoB,CAAC;AAC9B,CAAC;AAED,SAAS,QAAQ,CAAC,YAA2D;IAC3E,OAAO;QACL,UAAU,gDAA2B;QACrC,OAAO,EAAE,SAAS;QAClB,KAAK,EAAE,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC;QAClC,WAAW,EAAE,UAAU,CAAC,SAAS,CAAC,WAAW,CAAC;QAC9C,QAAQ,EAAE,eAAe,CAAC,GAAG;QAC7B,KAAK,EAAE,YAAY,CAAC,sBAAsB,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM;QACzE,GAAG,YAAY;KAChB,CAAC;AACJ,CAAC;AAED,SAAS,0BAA0B,CAAC,KAAyB,EAAE,eAA2C;IAExG,MAAM,iBAAiB,GAAG,MAAM,CAAC,kBAAkB,CAAC,GAAG,CAAC,KAAK,EAAE,eAAe,CAAC,CAAC;IAChF,MAAM,eAAe,GAAG,OAAO,CAAC,KAAK,CAAC,sCAAsC,CAAC,KAAK,CAAC,CAAC;IAEpF,OAAO,iBAAiB,EAAE,UAAU,CAAC,CAAC,CAAC,IAAI,eAAe,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AAC1E,CAAC;AAED,MAAM,UAAU,eAAe,CAC3B,eAA2C,EAAE,OAA0B;IACzE,MAAM,eAAe,GAAG,CAAC,KAAyB,EAAW,EAAE;QAC7D,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QACrD,IAAI,OAAO,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC;YAChC,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/D,CAAC,CAAC;IAEF,MAAM,eAAe,GAAG,IAAI,GAAG,EAA6B,CAAC;IAC7D,MAAM,MAAM,GAAG,eAAe,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC;IACvG,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,eAAe,GAAG,0BAA0B,CAAC,KAAK,EAAE,eAAe,CAAC,CAAC;QAC3E,MAAM,YAAY,GAAG,eAAe,CAAC,CAAC,CAAC,cAAc,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC;QACxF,MAAM,YAAY,GACd,QAAQ,CAAC,YAAY,CAAC,cAAc,CAAC,eAAe,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC;YACL,YAAY,EAAE,eAAe;YAC7B,SAAS,EAAE,CAAC;YACZ,aAAa,EAAE,EAAE;SAClB,CAAC,CAAC,CAAC;QAC5E,YAAY,CAAC,SAAS,IAAI,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC;QACzC,YAAY,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACzC,CAAC;IAED,MAAM,wBAAwB,GAAG,8BAA8B,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAEzF,OAAO,QAAQ,CAAC;QACd,aAAa,EAAE,MAAM;QACrB,wBAAwB;QACxB,sBAAsB,EAAE,CAAC,GAAG,eAAe,CAAC,MAAM,EAAE,CAAC;KACtD,CAAC,CAAC;AACL,CAAC","sourcesContent":["// Copyright 2024 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as i18n from '../../../core/i18n/i18n.js';\nimport * as Platform from '../../../core/platform/platform.js';\nimport type * as Protocol from '../../../generated/protocol.js';\nimport * as Extras from '../extras/extras.js';\nimport type * 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 type PartialInsightModel,\n} from './types.js';\n\nexport const UIStrings = {\n /**\n *@description Title of an insight that provides details about Forced reflow.\n */\n title: 'Forced reflow',\n /**\n * @description Text to describe the forced reflow.\n */\n description:\n 'Many APIs, typically reading layout geometry, force the rendering engine to pause script execution in order to calculate the style and layout. Learn more about [forced reflow](https://developers.google.com/web/fundamentals/performance/rendering/avoid-large-complex-layouts-and-layout-thrashing#avoid-forced-synchronous-layouts) and its mitigations.',\n /**\n *@description Title of a list to provide related stack trace data\n */\n relatedStackTrace: 'Stack trace',\n /**\n *@description Text to describe the top time-consuming function call\n */\n topTimeConsumingFunctionCall: 'Top function call',\n /**\n * @description Text to describe the total reflow time\n */\n totalReflowTime: 'Total reflow time',\n /**\n * @description Text to describe CPU processor tasks that could not be attributed to any specific source code.\n */\n unattributed: '[unattributed]',\n /**\n * @description Text for the name of anonymous functions\n */\n anonymous: '(anonymous)',\n} as const;\n\nconst str_ = i18n.i18n.registerUIStrings('models/trace/insights/ForcedReflow.ts', UIStrings);\nexport const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);\n\nexport type ForcedReflowInsightModel = InsightModel<typeof UIStrings, {\n topLevelFunctionCallData: ForcedReflowAggregatedData | undefined,\n aggregatedBottomUpData: BottomUpCallStack[],\n}>;\n\nexport interface BottomUpCallStack {\n /**\n * `null` indicates that this data is for unattributed force reflows.\n */\n bottomUpData: Types.Events.CallFrame|Protocol.Runtime.CallFrame|null;\n totalTime: number;\n relatedEvents: Types.Events.Event[];\n}\n\nexport interface ForcedReflowAggregatedData {\n topLevelFunctionCall: Types.Events.CallFrame|Protocol.Runtime.CallFrame;\n totalReflowTime: number;\n topLevelFunctionCallEvents: Types.Events.Event[];\n}\n\nfunction getCallFrameId(callFrame: Types.Events.CallFrame|Protocol.Runtime.CallFrame): string {\n return callFrame.scriptId + ':' + callFrame.lineNumber + ':' + callFrame.columnNumber;\n}\n\nfunction getLargestTopLevelFunctionData(\n forcedReflowEvents: Types.Events.Event[], traceParsedData: Handlers.Types.ParsedTrace): ForcedReflowAggregatedData|\n undefined {\n const entryToNodeMap = traceParsedData.Renderer.entryToNode;\n const dataByTopLevelFunction = new Map<string, ForcedReflowAggregatedData>();\n if (forcedReflowEvents.length === 0) {\n return;\n }\n\n for (const event of forcedReflowEvents) {\n // Gather the stack traces by searching in the tree\n const traceNode = entryToNodeMap.get(event);\n if (!traceNode) {\n continue;\n }\n\n let node = traceNode.parent;\n let topLevelFunctionCall;\n let topLevelFunctionCallEvent: Types.Events.Event|undefined;\n while (node) {\n const eventData = node.entry;\n if (Types.Events.isProfileCall(eventData)) {\n topLevelFunctionCall = eventData.callFrame;\n topLevelFunctionCallEvent = eventData;\n } else {\n // We have finished searching bottom up data\n if (Types.Events.isFunctionCall(eventData) && eventData.args.data &&\n Types.Events.objectIsCallFrame(eventData.args.data)) {\n topLevelFunctionCall = eventData.args.data;\n topLevelFunctionCallEvent = eventData;\n }\n break;\n }\n node = node.parent;\n }\n\n if (!topLevelFunctionCall || !topLevelFunctionCallEvent) {\n continue;\n }\n\n const aggregatedDataId = getCallFrameId(topLevelFunctionCall);\n const aggregatedData =\n Platform.MapUtilities.getWithDefault(dataByTopLevelFunction, aggregatedDataId, () => ({\n topLevelFunctionCall,\n totalReflowTime: 0,\n topLevelFunctionCallEvents: [],\n }));\n aggregatedData.totalReflowTime += (event.dur ?? 0);\n aggregatedData.topLevelFunctionCallEvents.push(topLevelFunctionCallEvent);\n }\n\n let topTimeConsumingData: ForcedReflowAggregatedData|undefined = undefined;\n dataByTopLevelFunction.forEach(data => {\n if (!topTimeConsumingData || data.totalReflowTime > topTimeConsumingData.totalReflowTime) {\n topTimeConsumingData = data;\n }\n });\n\n return topTimeConsumingData;\n}\n\nfunction finalize(partialModel: PartialInsightModel<ForcedReflowInsightModel>): ForcedReflowInsightModel {\n return {\n insightKey: InsightKeys.FORCED_REFLOW,\n strings: UIStrings,\n title: i18nString(UIStrings.title),\n description: i18nString(UIStrings.description),\n category: InsightCategory.ALL,\n state: partialModel.aggregatedBottomUpData.length !== 0 ? 'fail' : 'pass',\n ...partialModel,\n };\n}\n\nfunction getBottomCallFrameForEvent(event: Types.Events.Event, traceParsedData: Handlers.Types.ParsedTrace):\n Types.Events.CallFrame|Protocol.Runtime.CallFrame|null {\n const profileStackTrace = Extras.StackTraceForEvent.get(event, traceParsedData);\n const eventStackTrace = Helpers.Trace.getZeroIndexedStackTraceInEventPayload(event);\n\n return profileStackTrace?.callFrames[0] ?? eventStackTrace?.[0] ?? null;\n}\n\nexport function generateInsight(\n traceParsedData: Handlers.Types.ParsedTrace, context: InsightSetContext): ForcedReflowInsightModel {\n const isWithinContext = (event: Types.Events.Event): boolean => {\n const frameId = Helpers.Trace.frameIDForEvent(event);\n if (frameId !== context.frameId) {\n return false;\n }\n\n return Helpers.Timing.eventIsInBounds(event, context.bounds);\n };\n\n const bottomUpDataMap = new Map<string, BottomUpCallStack>();\n const events = traceParsedData.Warnings.perWarning.get('FORCED_REFLOW')?.filter(isWithinContext) ?? [];\n for (const event of events) {\n const bottomCallFrame = getBottomCallFrameForEvent(event, traceParsedData);\n const bottomCallId = bottomCallFrame ? getCallFrameId(bottomCallFrame) : 'UNATTRIBUTED';\n const bottomUpData =\n Platform.MapUtilities.getWithDefault(bottomUpDataMap, bottomCallId, () => ({\n bottomUpData: bottomCallFrame,\n totalTime: 0,\n relatedEvents: [],\n }));\n bottomUpData.totalTime += event.dur ?? 0;\n bottomUpData.relatedEvents.push(event);\n }\n\n const topLevelFunctionCallData = getLargestTopLevelFunctionData(events, traceParsedData);\n\n return finalize({\n relatedEvents: events,\n topLevelFunctionCallData,\n aggregatedBottomUpData: [...bottomUpDataMap.values()],\n });\n}\n"]}
@@ -40,4 +40,5 @@ export type INPInsightModel = InsightModel<typeof UIStrings, {
40
40
  longestInteractionEvent?: SyntheticInteractionPair;
41
41
  highPercentileInteractionEvent?: SyntheticInteractionPair;
42
42
  }>;
43
+ export declare function isINP(insight: InsightModel): insight is INPInsightModel;
43
44
  export declare function generateInsight(parsedTrace: Handlers.Types.ParsedTrace, context: InsightSetContext): INPInsightModel;
@@ -41,6 +41,9 @@ export const UIStrings = {
41
41
  };
42
42
  // const str_ = i18n.i18n.registerUIStrings('models/trace/insights/InteractionToNextPaint.ts', UIStrings);
43
43
  export const i18nString = (i18nId, values) => ({i18nId, values}); // i18n.i18n.getLocalizedString.bind(undefined, str_);
44
+ export function isINP(insight) {
45
+ return insight.insightKey === "InteractionToNextPaint" /* InsightKeys.INTERACTION_TO_NEXT_PAINT */;
46
+ }
44
47
  function finalize(partialModel) {
45
48
  return {
46
49
  insightKey: "InteractionToNextPaint" /* InsightKeys.INTERACTION_TO_NEXT_PAINT */,
@@ -1 +1 @@
1
- {"version":3,"file":"InteractionToNextPaint.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/InteractionToNextPaint.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,yEAAyE;AACzE,6BAA6B;AAE7B,OAAO,KAAK,IAAI,MAAM,4BAA4B,CAAC;AAEnD,OAAO,KAAK,OAAO,MAAM,uBAAuB,CAAC;AAGjD,OAAO,EACL,eAAe,GAKhB,MAAM,YAAY,CAAC;AAEpB,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB;;OAEG;IACH,WAAW,EACP,8PAA8P;IAClQ;;OAEG;IACH,KAAK,EAAE,cAAc;IACrB;;OAEG;IACH,KAAK,EAAE,OAAO;IACd;;OAEG;IACH,QAAQ,EAAE,UAAU;IAEpB,oFAAoF;IACpF;;OAEG;IACH,UAAU,EAAE,aAAa;IACzB;;OAEG;IACH,kBAAkB,EAAE,qBAAqB;IACzC;;OAEG;IACH,iBAAiB,EAAE,oBAAoB;IACvC;;OAEG;IACH,cAAc,EAAE,0BAA0B;CAClC,CAAC;AAEX,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,iDAAiD,EAAE,SAAS,CAAC,CAAC;AACvG,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;AAO7E,SAAS,QAAQ,CAAC,YAAkD;IAClE,OAAO;QACL,UAAU,sEAAuC;QACjD,OAAO,EAAE,SAAS;QAClB,KAAK,EAAE,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC;QAClC,WAAW,EAAE,UAAU,CAAC,SAAS,CAAC,WAAW,CAAC;QAC9C,QAAQ,EAAE,eAAe,CAAC,GAAG;QAC7B,KAAK,EAAE,YAAY,CAAC,uBAAuB,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM;QACpE,GAAG,YAAY;KAChB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,WAAuC,EAAE,OAA0B;IACjG,MAAM,iBAAiB,GAAG,WAAW,CAAC,gBAAgB,CAAC,8BAA8B,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;QACnG,OAAO,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,iBAAiB,CAAC,MAAM,EAAE,CAAC;QAC9B,qDAAqD;QACrD,OAAO,QAAQ,CAAC,EAAE,CAAC,CAAC;IACtB,CAAC;IAED,MAAM,sBAAsB,GAAG,IAAI,GAAG,EAAoC,CAAC;IAC3E,KAAK,MAAM,KAAK,IAAI,iBAAiB,EAAE,CAAC;QACtC,MAAM,GAAG,GAAG,KAAK,CAAC,aAAa,CAAC;QAChC,MAAM,OAAO,GAAG,sBAAsB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAChD,IAAI,CAAC,OAAO,IAAI,KAAK,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;YACxC,sBAAsB,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;IACD,MAAM,2BAA2B,GAAG,CAAC,GAAG,sBAAsB,CAAC,MAAM,EAAE,CAAC,CAAC;IACzE,2BAA2B,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;IAE1D,6EAA6E;IAC7E,+EAA+E;IAC/E,6EAA6E;IAC7E,iMAAiM;IACjM,MAAM,mBAAmB,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,2BAA2B,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC;IAE7F,OAAO,QAAQ,CAAC;QACd,aAAa,EAAE,CAAC,2BAA2B,CAAC,CAAC,CAAC,CAAC;QAC/C,uBAAuB,EAAE,2BAA2B,CAAC,CAAC,CAAC;QACvD,8BAA8B,EAAE,2BAA2B,CAAC,mBAAmB,CAAC;KACjF,CAAC,CAAC;AACL,CAAC","sourcesContent":["// Copyright 2024 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as i18n from '../../../core/i18n/i18n.js';\nimport type * as Handlers from '../handlers/handlers.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport type {SyntheticInteractionPair} from '../types/TraceEvents.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 Text to tell the user about the longest user interaction.\n */\n description:\n 'Start investigating with the longest phase. [Delays can be minimized](https://web.dev/articles/optimize-inp#optimize_interactions). To reduce processing duration, [optimize the main-thread costs](https://web.dev/articles/optimize-long-tasks), often JS.',\n /**\n * @description Title for the performance insight \"INP by phase\", which shows a breakdown of INP by phases / sections.\n */\n title: 'INP by phase',\n /**\n *@description Label used for the phase/component/stage/section of a larger duration.\n */\n phase: 'Phase',\n /**\n *@description Label used for a time duration.\n */\n duration: 'Duration',\n\n // TODO: these are repeated in InteractionBreakdown. Add a place for common strings?\n /**\n *@description Text shown next to the interaction event's input delay time in the detail view.\n */\n inputDelay: 'Input delay',\n /**\n *@description Text shown next to the interaction event's thread processing duration in the detail view.\n */\n processingDuration: 'Processing duration',\n /**\n *@description Text shown next to the interaction event's presentation delay time in the detail view.\n */\n presentationDelay: 'Presentation delay',\n /**\n * @description Text status indicating that no user interactions were detected.\n */\n noInteractions: 'No interactions detected',\n} as const;\n\nconst str_ = i18n.i18n.registerUIStrings('models/trace/insights/InteractionToNextPaint.ts', UIStrings);\nexport const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);\n\nexport type INPInsightModel = InsightModel<typeof UIStrings, {\n longestInteractionEvent?: SyntheticInteractionPair,\n highPercentileInteractionEvent?: SyntheticInteractionPair,\n}>;\n\nfunction finalize(partialModel: PartialInsightModel<INPInsightModel>): INPInsightModel {\n return {\n insightKey: InsightKeys.INTERACTION_TO_NEXT_PAINT,\n strings: UIStrings,\n title: i18nString(UIStrings.title),\n description: i18nString(UIStrings.description),\n category: InsightCategory.INP,\n state: partialModel.longestInteractionEvent ? 'informative' : 'pass',\n ...partialModel,\n };\n}\n\nexport function generateInsight(parsedTrace: Handlers.Types.ParsedTrace, context: InsightSetContext): INPInsightModel {\n const interactionEvents = parsedTrace.UserInteractions.interactionEventsWithNoNesting.filter(event => {\n return Helpers.Timing.eventIsInBounds(event, context.bounds);\n });\n\n if (!interactionEvents.length) {\n // A valid result, when there is no user interaction.\n return finalize({});\n }\n\n const longestByInteractionId = new Map<number, SyntheticInteractionPair>();\n for (const event of interactionEvents) {\n const key = event.interactionId;\n const longest = longestByInteractionId.get(key);\n if (!longest || event.dur > longest.dur) {\n longestByInteractionId.set(key, event);\n }\n }\n const normalizedInteractionEvents = [...longestByInteractionId.values()];\n normalizedInteractionEvents.sort((a, b) => b.dur - a.dur);\n\n // INP is the \"nearest-rank\"/inverted_cdf 98th percentile, except Chrome only\n // keeps the 10 worst events around, so it can never be more than the 10th from\n // last array element. To keep things simpler, sort desc and pick from front.\n // See https://source.chromium.org/chromium/chromium/src/+/main:components/page_load_metrics/browser/responsiveness_metrics_normalization.cc;l=45-59;drc=cb0f9c8b559d9c7c3cb4ca94fc1118cc015d38ad\n const highPercentileIndex = Math.min(9, Math.floor(normalizedInteractionEvents.length / 50));\n\n return finalize({\n relatedEvents: [normalizedInteractionEvents[0]],\n longestInteractionEvent: normalizedInteractionEvents[0],\n highPercentileInteractionEvent: normalizedInteractionEvents[highPercentileIndex],\n });\n}\n"]}
1
+ {"version":3,"file":"InteractionToNextPaint.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/InteractionToNextPaint.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as i18n from '../../../core/i18n/i18n.js';\nimport type * as Handlers from '../handlers/handlers.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport type {SyntheticInteractionPair} from '../types/TraceEvents.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 Text to tell the user about the longest user interaction.\n */\n description:\n 'Start investigating with the longest phase. [Delays can be minimized](https://web.dev/articles/optimize-inp#optimize_interactions). To reduce processing duration, [optimize the main-thread costs](https://web.dev/articles/optimize-long-tasks), often JS.',\n /**\n * @description Title for the performance insight \"INP by phase\", which shows a breakdown of INP by phases / sections.\n */\n title: 'INP by phase',\n /**\n *@description Label used for the phase/component/stage/section of a larger duration.\n */\n phase: 'Phase',\n /**\n *@description Label used for a time duration.\n */\n duration: 'Duration',\n\n // TODO: these are repeated in InteractionBreakdown. Add a place for common strings?\n /**\n *@description Text shown next to the interaction event's input delay time in the detail view.\n */\n inputDelay: 'Input delay',\n /**\n *@description Text shown next to the interaction event's thread processing duration in the detail view.\n */\n processingDuration: 'Processing duration',\n /**\n *@description Text shown next to the interaction event's presentation delay time in the detail view.\n */\n presentationDelay: 'Presentation delay',\n /**\n * @description Text status indicating that no user interactions were detected.\n */\n noInteractions: 'No interactions detected',\n} as const;\n\nconst str_ = i18n.i18n.registerUIStrings('models/trace/insights/InteractionToNextPaint.ts', UIStrings);\nexport const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);\n\nexport type INPInsightModel = InsightModel<typeof UIStrings, {\n longestInteractionEvent?: SyntheticInteractionPair,\n highPercentileInteractionEvent?: SyntheticInteractionPair,\n}>;\n\nexport function isINP(insight: InsightModel): insight is INPInsightModel {\n return insight.insightKey === InsightKeys.INTERACTION_TO_NEXT_PAINT;\n}\n\nfunction finalize(partialModel: PartialInsightModel<INPInsightModel>): INPInsightModel {\n return {\n insightKey: InsightKeys.INTERACTION_TO_NEXT_PAINT,\n strings: UIStrings,\n title: i18nString(UIStrings.title),\n description: i18nString(UIStrings.description),\n category: InsightCategory.INP,\n state: partialModel.longestInteractionEvent ? 'informative' : 'pass',\n ...partialModel,\n };\n}\n\nexport function generateInsight(parsedTrace: Handlers.Types.ParsedTrace, context: InsightSetContext): INPInsightModel {\n const interactionEvents = parsedTrace.UserInteractions.interactionEventsWithNoNesting.filter(event => {\n return Helpers.Timing.eventIsInBounds(event, context.bounds);\n });\n\n if (!interactionEvents.length) {\n // A valid result, when there is no user interaction.\n return finalize({});\n }\n\n const longestByInteractionId = new Map<number, SyntheticInteractionPair>();\n for (const event of interactionEvents) {\n const key = event.interactionId;\n const longest = longestByInteractionId.get(key);\n if (!longest || event.dur > longest.dur) {\n longestByInteractionId.set(key, event);\n }\n }\n const normalizedInteractionEvents = [...longestByInteractionId.values()];\n normalizedInteractionEvents.sort((a, b) => b.dur - a.dur);\n\n // INP is the \"nearest-rank\"/inverted_cdf 98th percentile, except Chrome only\n // keeps the 10 worst events around, so it can never be more than the 10th from\n // last array element. To keep things simpler, sort desc and pick from front.\n // See https://source.chromium.org/chromium/chromium/src/+/main:components/page_load_metrics/browser/responsiveness_metrics_normalization.cc;l=45-59;drc=cb0f9c8b559d9c7c3cb4ca94fc1118cc015d38ad\n const highPercentileIndex = Math.min(9, Math.floor(normalizedInteractionEvents.length / 50));\n\n return finalize({\n relatedEvents: [normalizedInteractionEvents[0]],\n longestInteractionEvent: normalizedInteractionEvents[0],\n highPercentileInteractionEvent: normalizedInteractionEvents[highPercentileIndex],\n });\n}\n"]}
@@ -0,0 +1,32 @@
1
+ import type * as Handlers from '../handlers/handlers.js';
2
+ import { type InsightModel, type InsightSetContext } from './types.js';
3
+ export declare const UIStrings: {
4
+ /**
5
+ * @description Title of an insight that identifies polyfills for modern JavaScript features, and recommends their removal.
6
+ */
7
+ readonly title: "Legacy JavaScript";
8
+ /**
9
+ * @description Description of an insight that identifies polyfills for modern JavaScript features, and recommends their removal.
10
+ */
11
+ readonly description: "Polyfills and transforms enable legacy browsers to use new JavaScript features. However, many aren't necessary for modern browsers. Consider modifying your JavaScript build process to not transpile [Baseline](https://web.dev/articles/baseline-and-polyfills) features, unless you know you must support legacy browsers. [Learn why most sites can deploy ES6+ code without transpiling](https://philipwalton.com/articles/the-state-of-es5-on-the-web/)";
12
+ /** Label for a column in a data table; entries will be the individual JavaScript scripts. */
13
+ readonly columnScript: "Script";
14
+ /** Label for a column in a data table; entries will be the number of wasted bytes (aka the estimated savings in terms of bytes). */
15
+ readonly columnWastedBytes: "Wasted bytes";
16
+ };
17
+ export declare const i18nString: (id: string, values?: Record<string, string> | undefined) => Record<string, string>;
18
+ export interface PatternMatchResult {
19
+ name: string;
20
+ line: number;
21
+ column: number;
22
+ }
23
+ interface LegacyJavaScriptResult {
24
+ matches: PatternMatchResult[];
25
+ estimatedByteSavings: number;
26
+ }
27
+ type LegacyJavaScriptResults = Map<Handlers.ModelHandlers.Scripts.Script, LegacyJavaScriptResult>;
28
+ export type LegacyJavaScriptInsightModel = InsightModel<typeof UIStrings, {
29
+ legacyJavaScriptResults: LegacyJavaScriptResults;
30
+ }>;
31
+ export declare function generateInsight(parsedTrace: Handlers.Types.ParsedTrace, context: InsightSetContext): LegacyJavaScriptInsightModel;
32
+ export {};
@@ -0,0 +1,77 @@
1
+ // Copyright 2025 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+ // import * as i18n from '../../../core/i18n/i18n.js';
5
+ import * as LegacyJavaScriptLib from '../../../third_party/legacy-javascript/legacy-javascript.js';
6
+ import * as Helpers from '../helpers/helpers.js';
7
+ import { estimateCompressionRatioForScript, metricSavingsForWastedBytes } from './Common.js';
8
+ import { InsightCategory, } from './types.js';
9
+ const { detectLegacyJavaScript } = LegacyJavaScriptLib.LegacyJavaScript;
10
+ export const UIStrings = {
11
+ /**
12
+ * @description Title of an insight that identifies polyfills for modern JavaScript features, and recommends their removal.
13
+ */
14
+ title: 'Legacy JavaScript',
15
+ /**
16
+ * @description Description of an insight that identifies polyfills for modern JavaScript features, and recommends their removal.
17
+ */
18
+ description: 'Polyfills and transforms enable legacy browsers to use new JavaScript features. However, many aren\'t necessary for modern browsers. Consider modifying your JavaScript build process to not transpile [Baseline](https://web.dev/articles/baseline-and-polyfills) features, unless you know you must support legacy browsers. [Learn why most sites can deploy ES6+ code without transpiling](https://philipwalton.com/articles/the-state-of-es5-on-the-web/)',
19
+ /** Label for a column in a data table; entries will be the individual JavaScript scripts. */
20
+ columnScript: 'Script',
21
+ /** Label for a column in a data table; entries will be the number of wasted bytes (aka the estimated savings in terms of bytes). */
22
+ columnWastedBytes: 'Wasted bytes',
23
+ };
24
+ // const str_ = i18n.i18n.registerUIStrings('models/trace/insights/LegacyJavaScript.ts', UIStrings);
25
+ export const i18nString = (i18nId, values) => ({i18nId, values}); // i18n.i18n.getLocalizedString.bind(undefined, str_);
26
+ const BYTE_THRESHOLD = 5000;
27
+ function finalize(partialModel) {
28
+ const requests = [...partialModel.legacyJavaScriptResults.keys()].map(script => script.request).filter(e => !!e);
29
+ return {
30
+ insightKey: "LegacyJavaScript" /* InsightKeys.LEGACY_JAVASCRIPT */,
31
+ strings: UIStrings,
32
+ title: i18nString(UIStrings.title),
33
+ description: i18nString(UIStrings.description),
34
+ category: InsightCategory.ALL,
35
+ state: requests.length ? 'fail' : 'pass',
36
+ relatedEvents: [...new Set(requests)],
37
+ ...partialModel,
38
+ };
39
+ }
40
+ export function generateInsight(parsedTrace, context) {
41
+ const scripts = parsedTrace.Scripts.scripts.filter(script => {
42
+ if (!context.navigation) {
43
+ return false;
44
+ }
45
+ if (script.frame !== context.frameId) {
46
+ return false;
47
+ }
48
+ if (script.url?.startsWith('chrome-extension://')) {
49
+ return false;
50
+ }
51
+ return Helpers.Timing.timestampIsInBounds(context.bounds, script.ts);
52
+ });
53
+ const legacyJavaScriptResults = new Map();
54
+ const wastedBytesByRequestId = new Map();
55
+ for (const script of scripts) {
56
+ if (!script.content || script.content.length < BYTE_THRESHOLD) {
57
+ continue;
58
+ }
59
+ const result = detectLegacyJavaScript(script.content, script.sourceMap);
60
+ if (result.estimatedByteSavings < BYTE_THRESHOLD) {
61
+ continue;
62
+ }
63
+ legacyJavaScriptResults.set(script, result);
64
+ if (script.request) {
65
+ const compressionRatio = estimateCompressionRatioForScript(script);
66
+ const transferSize = Math.round(result.estimatedByteSavings * compressionRatio);
67
+ const requestId = script.request.args.data.requestId;
68
+ wastedBytesByRequestId.set(requestId, transferSize);
69
+ }
70
+ }
71
+ const sorted = new Map([...legacyJavaScriptResults].sort((a, b) => b[1].estimatedByteSavings - a[1].estimatedByteSavings));
72
+ return finalize({
73
+ legacyJavaScriptResults: sorted,
74
+ metricSavings: metricSavingsForWastedBytes(wastedBytesByRequestId, context),
75
+ });
76
+ }
77
+ //# sourceMappingURL=LegacyJavaScript.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LegacyJavaScript.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/LegacyJavaScript.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,yEAAyE;AACzE,6BAA6B;AAE7B,OAAO,KAAK,IAAI,MAAM,4BAA4B,CAAC;AACnD,OAAO,KAAK,mBAAmB,MAAM,6DAA6D,CAAC;AAEnG,OAAO,KAAK,OAAO,MAAM,uBAAuB,CAAC;AAEjD,OAAO,EAAC,iCAAiC,EAAE,2BAA2B,EAAC,MAAM,aAAa,CAAC;AAC3F,OAAO,EACL,eAAe,GAKhB,MAAM,YAAY,CAAC;AAEpB,MAAM,EAAC,sBAAsB,EAAC,GAAG,mBAAmB,CAAC,gBAAgB,CAAC;AAEtE,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB;;OAEG;IACH,KAAK,EAAE,mBAAmB;IAC1B;;OAEG;IACH,WAAW,EACP,gcAAgc;IACpc,6FAA6F;IAC7F,YAAY,EAAE,QAAQ;IACtB,oIAAoI;IACpI,iBAAiB,EAAE,cAAc;CACzB,CAAC;AAEX,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,2CAA2C,EAAE,SAAS,CAAC,CAAC;AACjG,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;AAmB7E,MAAM,cAAc,GAAG,IAAI,CAAC;AAE5B,SAAS,QAAQ,CAAC,YAA+D;IAC/E,MAAM,QAAQ,GAAG,CAAC,GAAG,YAAY,CAAC,uBAAuB,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAEjH,OAAO;QACL,UAAU,wDAA+B;QACzC,OAAO,EAAE,SAAS;QAClB,KAAK,EAAE,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC;QAClC,WAAW,EAAE,UAAU,CAAC,SAAS,CAAC,WAAW,CAAC;QAC9C,QAAQ,EAAE,eAAe,CAAC,GAAG;QAC7B,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM;QACxC,aAAa,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;QACrC,GAAG,YAAY;KAChB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAC3B,WAAuC,EAAE,OAA0B;IACrE,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE;QAC1D,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;YACxB,OAAO,KAAK,CAAC;QACf,CAAC;QAED,IAAI,MAAM,CAAC,KAAK,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC;YACrC,OAAO,KAAK,CAAC;QACf,CAAC;QAED,IAAI,MAAM,CAAC,GAAG,EAAE,UAAU,CAAC,qBAAqB,CAAC,EAAE,CAAC;YAClD,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,OAAO,CAAC,MAAM,CAAC,mBAAmB,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;IAEH,MAAM,uBAAuB,GAA4B,IAAI,GAAG,EAAE,CAAC;IACnE,MAAM,sBAAsB,GAAG,IAAI,GAAG,EAAkB,CAAC;IAEzD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,cAAc,EAAE,CAAC;YAC9D,SAAS;QACX,CAAC;QAED,MAAM,MAAM,GAAG,sBAAsB,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;QACxE,IAAI,MAAM,CAAC,oBAAoB,GAAG,cAAc,EAAE,CAAC;YACjD,SAAS;QACX,CAAC;QAED,uBAAuB,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAE5C,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,MAAM,gBAAgB,GAAG,iCAAiC,CAAC,MAAM,CAAC,CAAC;YACnE,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,oBAAoB,GAAG,gBAAgB,CAAC,CAAC;YAChF,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC;YACrD,sBAAsB,CAAC,GAAG,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;QACtD,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GACR,IAAI,GAAG,CAAC,CAAC,GAAG,uBAAuB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,oBAAoB,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC;IAEhH,OAAO,QAAQ,CAAC;QACd,uBAAuB,EAAE,MAAM;QAC/B,aAAa,EAAE,2BAA2B,CAAC,sBAAsB,EAAE,OAAO,CAAC;KAC5E,CAAC,CAAC;AACL,CAAC","sourcesContent":["// Copyright 2025 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as i18n from '../../../core/i18n/i18n.js';\nimport * as LegacyJavaScriptLib from '../../../third_party/legacy-javascript/legacy-javascript.js';\nimport type * as Handlers from '../handlers/handlers.js';\nimport * as Helpers from '../helpers/helpers.js';\n\nimport {estimateCompressionRatioForScript, metricSavingsForWastedBytes} from './Common.js';\nimport {\n InsightCategory,\n InsightKeys,\n type InsightModel,\n type InsightSetContext,\n type PartialInsightModel,\n} from './types.js';\n\nconst {detectLegacyJavaScript} = LegacyJavaScriptLib.LegacyJavaScript;\n\nexport const UIStrings = {\n /**\n * @description Title of an insight that identifies polyfills for modern JavaScript features, and recommends their removal.\n */\n title: 'Legacy JavaScript',\n /**\n * @description Description of an insight that identifies polyfills for modern JavaScript features, and recommends their removal.\n */\n description:\n 'Polyfills and transforms enable legacy browsers to use new JavaScript features. However, many aren\\'t necessary for modern browsers. Consider modifying your JavaScript build process to not transpile [Baseline](https://web.dev/articles/baseline-and-polyfills) features, unless you know you must support legacy browsers. [Learn why most sites can deploy ES6+ code without transpiling](https://philipwalton.com/articles/the-state-of-es5-on-the-web/)',\n /** Label for a column in a data table; entries will be the individual JavaScript scripts. */\n columnScript: 'Script',\n /** Label for a column in a data table; entries will be the number of wasted bytes (aka the estimated savings in terms of bytes). */\n columnWastedBytes: 'Wasted bytes',\n} as const;\n\nconst str_ = i18n.i18n.registerUIStrings('models/trace/insights/LegacyJavaScript.ts', UIStrings);\nexport const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);\n\nexport interface PatternMatchResult {\n name: string;\n line: number;\n column: number;\n}\n\ninterface LegacyJavaScriptResult {\n matches: PatternMatchResult[];\n estimatedByteSavings: number;\n}\n\ntype LegacyJavaScriptResults = Map<Handlers.ModelHandlers.Scripts.Script, LegacyJavaScriptResult>;\n\nexport type LegacyJavaScriptInsightModel = InsightModel<typeof UIStrings, {\n legacyJavaScriptResults: LegacyJavaScriptResults,\n}>;\n\nconst BYTE_THRESHOLD = 5000;\n\nfunction finalize(partialModel: PartialInsightModel<LegacyJavaScriptInsightModel>): LegacyJavaScriptInsightModel {\n const requests = [...partialModel.legacyJavaScriptResults.keys()].map(script => script.request).filter(e => !!e);\n\n return {\n insightKey: InsightKeys.LEGACY_JAVASCRIPT,\n strings: UIStrings,\n title: i18nString(UIStrings.title),\n description: i18nString(UIStrings.description),\n category: InsightCategory.ALL,\n state: requests.length ? 'fail' : 'pass',\n relatedEvents: [...new Set(requests)],\n ...partialModel,\n };\n}\n\nexport function generateInsight(\n parsedTrace: Handlers.Types.ParsedTrace, context: InsightSetContext): LegacyJavaScriptInsightModel {\n const scripts = parsedTrace.Scripts.scripts.filter(script => {\n if (!context.navigation) {\n return false;\n }\n\n if (script.frame !== context.frameId) {\n return false;\n }\n\n if (script.url?.startsWith('chrome-extension://')) {\n return false;\n }\n\n return Helpers.Timing.timestampIsInBounds(context.bounds, script.ts);\n });\n\n const legacyJavaScriptResults: LegacyJavaScriptResults = new Map();\n const wastedBytesByRequestId = new Map<string, number>();\n\n for (const script of scripts) {\n if (!script.content || script.content.length < BYTE_THRESHOLD) {\n continue;\n }\n\n const result = detectLegacyJavaScript(script.content, script.sourceMap);\n if (result.estimatedByteSavings < BYTE_THRESHOLD) {\n continue;\n }\n\n legacyJavaScriptResults.set(script, result);\n\n if (script.request) {\n const compressionRatio = estimateCompressionRatioForScript(script);\n const transferSize = Math.round(result.estimatedByteSavings * compressionRatio);\n const requestId = script.request.args.data.requestId;\n wastedBytesByRequestId.set(requestId, transferSize);\n }\n }\n\n const sorted =\n new Map([...legacyJavaScriptResults].sort((a, b) => b[1].estimatedByteSavings - a[1].estimatedByteSavings));\n\n return finalize({\n legacyJavaScriptResults: sorted,\n metricSavings: metricSavingsForWastedBytes(wastedBytesByRequestId, context),\n });\n}\n"]}
@@ -1,3 +1,4 @@
1
+ export * as Cache from './Cache.js';
1
2
  export * as CLSCulprits from './CLSCulprits.js';
2
3
  export * as DocumentLatency from './DocumentLatency.js';
3
4
  export * as DOMSize from './DOMSize.js';
@@ -8,9 +9,10 @@ export * as ImageDelivery from './ImageDelivery.js';
8
9
  export * as InteractionToNextPaint from './InteractionToNextPaint.js';
9
10
  export * as LCPDiscovery from './LCPDiscovery.js';
10
11
  export * as LCPPhases from './LCPPhases.js';
12
+ export * as LegacyJavaScript from './LegacyJavaScript.js';
13
+ export * as ModernHTTP from './ModernHTTP.js';
11
14
  export * as NetworkDependencyTree from './NetworkDependencyTree.js';
12
15
  export * as RenderBlocking from './RenderBlocking.js';
13
16
  export * as SlowCSSSelector from './SlowCSSSelector.js';
14
17
  export * as ThirdParties from './ThirdParties.js';
15
- export * as UseCache from './UseCache.js';
16
18
  export * as Viewport from './Viewport.js';
@@ -1,6 +1,7 @@
1
1
  // Copyright 2024 The Chromium Authors. All rights reserved.
2
2
  // Use of this source code is governed by a BSD-style license that can be
3
3
  // found in the LICENSE file.
4
+ export * as Cache from './Cache.js';
4
5
  export * as CLSCulprits from './CLSCulprits.js';
5
6
  export * as DocumentLatency from './DocumentLatency.js';
6
7
  export * as DOMSize from './DOMSize.js';
@@ -11,10 +12,11 @@ export * as ImageDelivery from './ImageDelivery.js';
11
12
  export * as InteractionToNextPaint from './InteractionToNextPaint.js';
12
13
  export * as LCPDiscovery from './LCPDiscovery.js';
13
14
  export * as LCPPhases from './LCPPhases.js';
15
+ export * as LegacyJavaScript from './LegacyJavaScript.js';
16
+ export * as ModernHTTP from './ModernHTTP.js';
14
17
  export * as NetworkDependencyTree from './NetworkDependencyTree.js';
15
18
  export * as RenderBlocking from './RenderBlocking.js';
16
19
  export * as SlowCSSSelector from './SlowCSSSelector.js';
17
20
  export * as ThirdParties from './ThirdParties.js';
18
- export * as UseCache from './UseCache.js';
19
21
  export * as Viewport from './Viewport.js';
20
22
  //# sourceMappingURL=Models.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Models.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/Models.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,yEAAyE;AACzE,6BAA6B;AAE7B,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAC;AAChD,OAAO,KAAK,eAAe,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AACxC,OAAO,KAAK,oBAAoB,MAAM,2BAA2B,CAAC;AAClE,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAC;AAChD,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,aAAa,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,sBAAsB,MAAM,6BAA6B,CAAC;AACtE,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAC;AAC5C,OAAO,KAAK,qBAAqB,MAAM,4BAA4B,CAAC;AACpE,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,eAAe,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAC1C,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC","sourcesContent":["// Copyright 2024 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nexport * as CLSCulprits from './CLSCulprits.js';\nexport * as DocumentLatency from './DocumentLatency.js';\nexport * as DOMSize from './DOMSize.js';\nexport * as DuplicatedJavaScript from './DuplicatedJavaScript.js';\nexport * as FontDisplay from './FontDisplay.js';\nexport * as ForcedReflow from './ForcedReflow.js';\nexport * as ImageDelivery from './ImageDelivery.js';\nexport * as InteractionToNextPaint from './InteractionToNextPaint.js';\nexport * as LCPDiscovery from './LCPDiscovery.js';\nexport * as LCPPhases from './LCPPhases.js';\nexport * as NetworkDependencyTree from './NetworkDependencyTree.js';\nexport * as RenderBlocking from './RenderBlocking.js';\nexport * as SlowCSSSelector from './SlowCSSSelector.js';\nexport * as ThirdParties from './ThirdParties.js';\nexport * as UseCache from './UseCache.js';\nexport * as Viewport from './Viewport.js';\n"]}
1
+ {"version":3,"file":"Models.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/Models.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,yEAAyE;AACzE,6BAA6B;AAE7B,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AACpC,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAC;AAChD,OAAO,KAAK,eAAe,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AACxC,OAAO,KAAK,oBAAoB,MAAM,2BAA2B,CAAC;AAClE,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAC;AAChD,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,aAAa,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,sBAAsB,MAAM,6BAA6B,CAAC;AACtE,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAC;AAC5C,OAAO,KAAK,gBAAgB,MAAM,uBAAuB,CAAC;AAC1D,OAAO,KAAK,UAAU,MAAM,iBAAiB,CAAC;AAC9C,OAAO,KAAK,qBAAqB,MAAM,4BAA4B,CAAC;AACpE,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,eAAe,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC","sourcesContent":["// Copyright 2024 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nexport * as Cache from './Cache.js';\nexport * as CLSCulprits from './CLSCulprits.js';\nexport * as DocumentLatency from './DocumentLatency.js';\nexport * as DOMSize from './DOMSize.js';\nexport * as DuplicatedJavaScript from './DuplicatedJavaScript.js';\nexport * as FontDisplay from './FontDisplay.js';\nexport * as ForcedReflow from './ForcedReflow.js';\nexport * as ImageDelivery from './ImageDelivery.js';\nexport * as InteractionToNextPaint from './InteractionToNextPaint.js';\nexport * as LCPDiscovery from './LCPDiscovery.js';\nexport * as LCPPhases from './LCPPhases.js';\nexport * as LegacyJavaScript from './LegacyJavaScript.js';\nexport * as ModernHTTP from './ModernHTTP.js';\nexport * as NetworkDependencyTree from './NetworkDependencyTree.js';\nexport * as RenderBlocking from './RenderBlocking.js';\nexport * as SlowCSSSelector from './SlowCSSSelector.js';\nexport * as ThirdParties from './ThirdParties.js';\nexport * as Viewport from './Viewport.js';\n"]}
@@ -0,0 +1,51 @@
1
+ import * as Platform from '../../../core/platform/platform.js';
2
+ import * as Handlers from '../handlers/handlers.js';
3
+ import type * as Types from '../types/types.js';
4
+ import { type InsightModel, type InsightSetContext } from './types.js';
5
+ export declare const UIStrings: {
6
+ /**
7
+ * @description Title of an insight that recommends using HTTP/2 over HTTP/1.1 because of the performance benefits. "HTTP" should not be translated.
8
+ */
9
+ readonly title: "Modern HTTP";
10
+ /**
11
+ * @description Description of an insight that recommends recommends using HTTP/2 over HTTP/1.1 because of the performance benefits. "HTTP" should not be translated.
12
+ */
13
+ readonly description: "HTTP/2 and HTTP/3 offer many benefits over HTTP/1.1, such as multiplexing. [Learn more about using modern HTTP](https://developer.chrome.com/docs/lighthouse/best-practices/uses-http2/).";
14
+ /**
15
+ * @description Column header for a table where each cell represents a network request.
16
+ */
17
+ readonly request: "Request";
18
+ /**
19
+ * @description Column header for a table where each cell represents the protocol of a network request.
20
+ */
21
+ readonly protocol: "Protocol";
22
+ /**
23
+ * @description Text explaining that there were not requests that were slowed down by using HTTP/1.1. "HTTP/1.1" should not be translated.
24
+ */
25
+ readonly noOldProtocolRequests: "No requests used HTTP/1.1";
26
+ };
27
+ export declare const i18nString: (id: string, values?: Record<string, string> | undefined) => {i18nId: string, values: Record<string, string|number>, formattedDefault: string};
28
+ export type UseModernHTTPInsightModel = InsightModel<typeof UIStrings, {
29
+ requests: Types.Events.SyntheticNetworkRequest[];
30
+ }>;
31
+ /**
32
+ * Determine the set of resources that aren't HTTP/2 but should be.
33
+ * We're a little conservative about what we surface for a few reasons:
34
+ *
35
+ * - The simulator approximation of HTTP/2 is a little more generous than reality.
36
+ * - There's a bit of debate surrounding HTTP/2 due to its worse performance in environments with high packet loss. [1][2][3]
37
+ * - It's something that you'd have absolutely zero control over with a third-party (can't defer to fix it for example).
38
+ *
39
+ * Therefore, we only surface requests that were...
40
+ *
41
+ * - Served over HTTP/1.1 or earlier
42
+ * - Served over an origin that serves at least 6 static asset requests
43
+ * (if there aren't more requests than browser's max/host, multiplexing isn't as big a deal)
44
+ * - Not served on localhost (h2 is a pain to deal with locally & and CI)
45
+ *
46
+ * [1] https://news.ycombinator.com/item?id=19086639
47
+ * [2] https://www.twilio.com/blog/2017/10/http2-issues.html
48
+ * [3] https://www.cachefly.com/http-2-is-not-a-magic-bullet/
49
+ */
50
+ export declare function determineNonHttp2Resources(requests: Types.Events.SyntheticNetworkRequest[], entityMappings: Handlers.Helpers.EntityMappings, firstPartyEntity: Handlers.Helpers.Entity | null): Types.Events.SyntheticNetworkRequest[];
51
+ export declare function generateInsight(parsedTrace: Handlers.Types.ParsedTrace, context: InsightSetContext): UseModernHTTPInsightModel;