chrome-devtools-frontend 1.0.1672388 → 1.0.1674545

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 (232) hide show
  1. package/eslint.config.mjs +3 -3
  2. package/front_end/core/common/SettingRegistration.ts +1 -26
  3. package/front_end/core/common/Settings.ts +4 -53
  4. package/front_end/core/host/UserMetrics.ts +127 -117
  5. package/front_end/core/protocol_client/PuppeteerDevToolsConnection.ts +42 -9
  6. package/front_end/core/root/Runtime.ts +7 -2
  7. package/front_end/core/sdk/NetworkManager.ts +0 -35
  8. package/front_end/core/sdk/SourceMap.ts +1 -19
  9. package/front_end/core/sdk/SourceMapManager.ts +75 -48
  10. package/front_end/core/sdk/SourceMapScopesInfo.ts +0 -62
  11. package/front_end/devtools_compatibility.js +1 -1
  12. package/front_end/generated/InspectorBackendCommands.ts +4 -3
  13. package/front_end/generated/{SupportedCSSProperties.js → SupportedCSSProperties.ts} +32 -1
  14. package/front_end/generated/protocol-mapping.d.ts +8 -0
  15. package/front_end/generated/protocol-proxy-api.d.ts +6 -0
  16. package/front_end/generated/protocol.ts +16 -2
  17. package/front_end/models/ai_assistance/AiSetting.ts +66 -3
  18. package/front_end/models/ai_assistance/agents/PerformanceAgent.snapshot.txt +1 -1
  19. package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +4 -3
  20. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +1 -1
  21. package/front_end/models/bindings/CompilerScriptMapping.ts +1 -1
  22. package/front_end/models/emulation/DeviceModeModel.ts +25 -34
  23. package/front_end/models/emulation/EmulatedDevices.ts +1 -1
  24. package/front_end/models/javascript_metadata/NativeFunctions.js +4 -4
  25. package/front_end/models/trace/ModelImpl.ts +5 -0
  26. package/front_end/models/trace/Processor.ts +47 -10
  27. package/front_end/models/trace/handlers/LayoutShiftsHandler.ts +18 -19
  28. package/front_end/models/trace/handlers/MetaHandler.ts +46 -9
  29. package/front_end/models/trace/handlers/PageLoadMetricsHandler.ts +11 -0
  30. package/front_end/models/trace/insights/CLSCulprits.ts +1 -2
  31. package/front_end/models/trace/insights/CharacterSet.ts +1 -1
  32. package/front_end/models/trace/insights/Common.ts +21 -2
  33. package/front_end/models/trace/insights/DocumentLatency.ts +1 -1
  34. package/front_end/models/trace/insights/LCPBreakdown.ts +7 -6
  35. package/front_end/models/trace/insights/LCPDiscovery.ts +1 -1
  36. package/front_end/models/trace/insights/ModernHTTP.ts +7 -3
  37. package/front_end/models/trace/insights/NetworkDependencyTree.ts +1 -1
  38. package/front_end/models/trace/insights/RenderBlocking.ts +1 -1
  39. package/front_end/models/trace/insights/ThirdParties.ts +5 -2
  40. package/front_end/models/trace/insights/types.ts +11 -6
  41. package/front_end/models/trace/types/Configuration.ts +5 -0
  42. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +11 -10
  43. package/front_end/panels/ai_assistance/ai_assistance-meta.ts +3 -45
  44. package/front_end/panels/application/BackgroundServiceView.ts +42 -40
  45. package/front_end/panels/application/KeyValueStorageItemsView.ts +1 -0
  46. package/front_end/panels/common/ExtensionServer.ts +7 -1
  47. package/front_end/panels/common/common.ts +0 -1
  48. package/front_end/panels/console/ConsoleInsightTeaser.ts +7 -6
  49. package/front_end/panels/console/ConsoleViewMessage.ts +1 -1
  50. package/front_end/panels/elements/ClassesPaneWidget.ts +2 -2
  51. package/front_end/panels/elements/ElementsTreeElement.ts +56 -5
  52. package/front_end/panels/elements/StylesSidebarPane.ts +1 -1
  53. package/front_end/panels/elements/components/AdornerManager.ts +1 -0
  54. package/front_end/panels/emulation/AdvancedApp.ts +3 -3
  55. package/front_end/panels/emulation/DeviceModeToolbar.ts +2 -11
  56. package/front_end/panels/emulation/DeviceModeView.ts +234 -75
  57. package/front_end/panels/emulation/InspectedPagePlaceholder.ts +1 -1
  58. package/front_end/panels/emulation/deviceModeView.css +4 -21
  59. package/front_end/panels/emulation/emulation-meta.ts +4 -30
  60. package/front_end/panels/emulation/emulation.ts +0 -3
  61. package/front_end/panels/explain/components/ConsoleInsight.ts +11 -7
  62. package/front_end/panels/layers/LayersPanel.ts +2 -2
  63. package/front_end/panels/layers/layers-meta.ts +2 -2
  64. package/front_end/panels/lighthouse/LighthouseController.ts +3 -7
  65. package/front_end/panels/mobile_throttling/CPUThrottlingSelector.ts +313 -0
  66. package/front_end/panels/mobile_throttling/NetworkPanelIndicator.ts +0 -10
  67. package/front_end/panels/mobile_throttling/NetworkThrottlingSelector.ts +23 -10
  68. package/front_end/panels/mobile_throttling/mobile_throttling.ts +3 -0
  69. package/front_end/panels/network/NetworkConfigView.ts +1 -71
  70. package/front_end/panels/network/networkConfigView.css +1 -2
  71. package/front_end/panels/profiler/HeapDetachedElementsDataGrid.ts +3 -3
  72. package/front_end/panels/profiler/HeapDetachedElementsView.ts +5 -5
  73. package/front_end/panels/profiler/HeapProfileView.ts +32 -32
  74. package/front_end/panels/profiler/HeapProfilerPanel.ts +2 -2
  75. package/front_end/panels/profiler/HeapSnapshotDataGrids.ts +33 -37
  76. package/front_end/panels/profiler/HeapSnapshotGridNodes.ts +26 -27
  77. package/front_end/panels/profiler/HeapSnapshotView.ts +48 -48
  78. package/front_end/panels/profiler/IsolateSelector.ts +10 -10
  79. package/front_end/panels/profiler/ModuleUIStrings.ts +25 -25
  80. package/front_end/panels/profiler/ProfileLauncherView.ts +6 -6
  81. package/front_end/panels/profiler/ProfilesPanel.ts +6 -6
  82. package/front_end/panels/profiler/WritableProfileHeader.ts +6 -6
  83. package/front_end/panels/profiler/profiler-meta.ts +7 -7
  84. package/front_end/panels/recorder/RecorderPanel.ts +1 -1
  85. package/front_end/panels/settings/AISettingsTab.ts +27 -23
  86. package/front_end/panels/settings/emulation/DevicesSettingsTab.ts +463 -13
  87. package/front_end/panels/timeline/TimelineFlameChartNetworkDataProvider.ts +12 -17
  88. package/front_end/panels/timeline/TimelinePanel.ts +22 -35
  89. package/front_end/panels/timeline/components/CWVMetrics.ts +16 -3
  90. package/front_end/panels/timeline/components/LiveMetricsView.ts +27 -6
  91. package/front_end/panels/timeline/components/NetworkTrackWidget.ts +1 -1
  92. package/front_end/panels/timeline/components/components.ts +0 -4
  93. package/front_end/panels/timeline/components/cwvMetrics.css +4 -0
  94. package/front_end/panels/timeline/components/liveMetricsView.css +7 -17
  95. package/front_end/panels/timeline/components/metricValueStyles.css +17 -0
  96. package/front_end/third_party/chromium/README.chromium +1 -1
  97. package/front_end/third_party/puppeteer/README.chromium +2 -2
  98. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.d.ts +64 -15
  99. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +65 -16
  100. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Page.d.ts +50 -7
  101. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Page.d.ts.map +1 -1
  102. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Page.js.map +1 -1
  103. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/BidiOverCdp.d.ts +2 -1
  104. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/BidiOverCdp.d.ts.map +1 -1
  105. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/BidiOverCdp.js +5 -5
  106. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/BidiOverCdp.js.map +1 -1
  107. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/Connection.d.ts +2 -1
  108. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/Connection.d.ts.map +1 -1
  109. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/Connection.js +8 -6
  110. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/Connection.js.map +1 -1
  111. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/Dialog.d.ts.map +1 -1
  112. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/Dialog.js +3 -0
  113. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/Dialog.js.map +1 -1
  114. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Browser.d.ts.map +1 -1
  115. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Browser.js +16 -1
  116. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Browser.js.map +1 -1
  117. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Connection.d.ts +5 -1
  118. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Connection.d.ts.map +1 -1
  119. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Connection.js +11 -6
  120. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Connection.js.map +1 -1
  121. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Dialog.d.ts.map +1 -1
  122. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Dialog.js +5 -0
  123. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Dialog.js.map +1 -1
  124. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/NetworkManager.d.ts.map +1 -1
  125. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/NetworkManager.js +10 -0
  126. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/NetworkManager.js.map +1 -1
  127. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/BrowserConnector.js +4 -3
  128. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/BrowserConnector.js.map +1 -1
  129. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/Debug.d.ts +27 -2
  130. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/Debug.d.ts.map +1 -1
  131. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/Debug.js +12 -1
  132. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/Debug.js.map +1 -1
  133. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/util.d.ts +2 -2
  134. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/util.d.ts.map +1 -1
  135. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/util.js +2 -2
  136. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/util.js.map +1 -1
  137. package/front_end/third_party/puppeteer/package/lib/puppeteer/node/ChromeLauncher.d.ts.map +1 -1
  138. package/front_end/third_party/puppeteer/package/lib/puppeteer/node/ChromeLauncher.js +2 -0
  139. package/front_end/third_party/puppeteer/package/lib/puppeteer/node/ChromeLauncher.js.map +1 -1
  140. package/front_end/third_party/puppeteer/package/lib/puppeteer/node/ScreenRecorder.d.ts +2 -1
  141. package/front_end/third_party/puppeteer/package/lib/puppeteer/node/ScreenRecorder.d.ts.map +1 -1
  142. package/front_end/third_party/puppeteer/package/lib/puppeteer/node/ScreenRecorder.js +5 -4
  143. package/front_end/third_party/puppeteer/package/lib/puppeteer/node/ScreenRecorder.js.map +1 -1
  144. package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.d.ts +3 -3
  145. package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.js +3 -3
  146. package/front_end/third_party/puppeteer/package/lib/puppeteer/util/version.d.ts +1 -1
  147. package/front_end/third_party/puppeteer/package/lib/puppeteer/util/version.js +1 -1
  148. package/front_end/third_party/puppeteer/package/lib/types.d.ts +64 -15
  149. package/front_end/third_party/puppeteer/package/package.json +2 -2
  150. package/front_end/third_party/puppeteer/package/src/api/Page.ts +50 -7
  151. package/front_end/third_party/puppeteer/package/src/bidi/BidiOverCdp.ts +9 -7
  152. package/front_end/third_party/puppeteer/package/src/bidi/Connection.ts +9 -6
  153. package/front_end/third_party/puppeteer/package/src/bidi/Dialog.ts +4 -0
  154. package/front_end/third_party/puppeteer/package/src/cdp/Browser.ts +24 -1
  155. package/front_end/third_party/puppeteer/package/src/cdp/Connection.ts +11 -6
  156. package/front_end/third_party/puppeteer/package/src/cdp/Dialog.ts +7 -0
  157. package/front_end/third_party/puppeteer/package/src/cdp/NetworkManager.ts +11 -0
  158. package/front_end/third_party/puppeteer/package/src/common/BrowserConnector.ts +7 -3
  159. package/front_end/third_party/puppeteer/package/src/common/Debug.ts +30 -5
  160. package/front_end/third_party/puppeteer/package/src/common/util.ts +2 -2
  161. package/front_end/third_party/puppeteer/package/src/node/ChromeLauncher.ts +2 -0
  162. package/front_end/third_party/puppeteer/package/src/node/ScreenRecorder.ts +6 -4
  163. package/front_end/third_party/puppeteer/package/src/revisions.ts +3 -3
  164. package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
  165. package/front_end/third_party/source-map-scopes-codec/package/CONTRIBUTING.md +0 -0
  166. package/front_end/third_party/source-map-scopes-codec/package/LICENSE +0 -0
  167. package/front_end/third_party/source-map-scopes-codec/package/README.md +0 -0
  168. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/builder.d.ts +0 -0
  169. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/builder.d.ts.map +1 -1
  170. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/safe_builder.d.ts +0 -0
  171. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/safe_builder.d.ts.map +0 -0
  172. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/decode/decode.d.ts +0 -0
  173. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/decode/decode.d.ts.map +0 -0
  174. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/encode/encode.d.ts +0 -0
  175. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/encode/encode.d.ts.map +0 -0
  176. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/mod.d.ts +0 -0
  177. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/mod.d.ts.map +0 -0
  178. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/scopes.d.ts +0 -0
  179. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/scopes.d.ts.map +0 -0
  180. package/front_end/third_party/source-map-scopes-codec/package/deno.json +1 -1
  181. package/front_end/third_party/source-map-scopes-codec/package/package.json +1 -1
  182. package/front_end/third_party/source-map-scopes-codec/package/src/builder/builder.js +2 -0
  183. package/front_end/third_party/source-map-scopes-codec/package/src/builder/builder.js.map +1 -1
  184. package/front_end/third_party/source-map-scopes-codec/package/src/builder/builder.ts +2 -0
  185. package/front_end/third_party/source-map-scopes-codec/package/src/builder/safe_builder.js +0 -0
  186. package/front_end/third_party/source-map-scopes-codec/package/src/builder/safe_builder.js.map +0 -0
  187. package/front_end/third_party/source-map-scopes-codec/package/src/builder/safe_builder.ts +0 -0
  188. package/front_end/third_party/source-map-scopes-codec/package/src/codec.js +0 -0
  189. package/front_end/third_party/source-map-scopes-codec/package/src/codec.js.map +0 -0
  190. package/front_end/third_party/source-map-scopes-codec/package/src/codec.ts +0 -0
  191. package/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.js +0 -0
  192. package/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.js.map +0 -0
  193. package/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.ts +0 -0
  194. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encode.js +0 -0
  195. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encode.js.map +0 -0
  196. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encode.ts +0 -0
  197. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.js +0 -0
  198. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.js.map +0 -0
  199. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.ts +0 -0
  200. package/front_end/third_party/source-map-scopes-codec/package/src/mod.js +0 -0
  201. package/front_end/third_party/source-map-scopes-codec/package/src/mod.js.map +0 -0
  202. package/front_end/third_party/source-map-scopes-codec/package/src/mod.ts +0 -0
  203. package/front_end/third_party/source-map-scopes-codec/package/src/scopes.js +0 -0
  204. package/front_end/third_party/source-map-scopes-codec/package/src/scopes.js.map +0 -0
  205. package/front_end/third_party/source-map-scopes-codec/package/src/scopes.ts +0 -0
  206. package/front_end/third_party/source-map-scopes-codec/package/src/util.js +0 -0
  207. package/front_end/third_party/source-map-scopes-codec/package/src/util.js.map +0 -0
  208. package/front_end/third_party/source-map-scopes-codec/package/src/util.ts +0 -0
  209. package/front_end/third_party/source-map-scopes-codec/package/src/vlq.js +0 -0
  210. package/front_end/third_party/source-map-scopes-codec/package/src/vlq.js.map +0 -0
  211. package/front_end/third_party/source-map-scopes-codec/package/src/vlq.ts +0 -0
  212. package/front_end/ui/components/dialogs/ShortcutDialog.ts +2 -0
  213. package/front_end/ui/components/settings/SettingCheckbox.ts +4 -12
  214. package/front_end/ui/components/settings/settingCheckbox.css +0 -7
  215. package/front_end/ui/legacy/Treeoutline.ts +14 -14
  216. package/front_end/ui/legacy/UIUtils.ts +2 -47
  217. package/front_end/ui/legacy/Widget.ts +10 -2
  218. package/front_end/ui/legacy/components/settings_ui/SettingsUI.ts +1 -1
  219. package/front_end/ui/lit/Directives.ts +80 -0
  220. package/front_end/ui/lit/lit.ts +1 -0
  221. package/front_end/ui/lit/render.ts +8 -0
  222. package/front_end/ui/visual_logging/KnownContextValues.ts +18 -0
  223. package/mcp/mcp.ts +1 -0
  224. package/package.json +1 -1
  225. package/front_end/panels/common/ThrottlingUtils.ts +0 -51
  226. package/front_end/panels/emulation/DeviceModeWrapper.ts +0 -248
  227. package/front_end/panels/timeline/components/CPUThrottlingSelector.ts +0 -235
  228. package/front_end/panels/timeline/components/NetworkThrottlingSelector.ts +0 -245
  229. package/front_end/panels/timeline/components/cpuThrottlingSelector.css +0 -30
  230. package/front_end/panels/timeline/components/networkThrottlingSelector.css +0 -24
  231. /package/front_end/core/host/{UserMetricsEnums.d.ts → UserMetricsEnums.ts} +0 -0
  232. /package/front_end/generated/{ARIAProperties.js → ARIAProperties.ts} +0 -0
@@ -33,6 +33,7 @@ export class AiSetting<ValueT> extends Common.ObjectWrapper.ObjectWrapper<EventT
33
33
  readonly #settings: Common.Settings.Settings;
34
34
  readonly #boundOnSettingChanged = this.#onSettingChanged.bind(this);
35
35
  readonly #boundOnAidaAvailabilityChanged = this.#onAidaAvailabilityChanged.bind(this);
36
+ #isSubscribed = false;
36
37
 
37
38
  constructor(
38
39
  descriptor: Common.Settings.ConditionalSettingDescriptor<ValueT, DisabledReason[]>,
@@ -44,11 +45,56 @@ export class AiSetting<ValueT> extends Common.ObjectWrapper.ObjectWrapper<EventT
44
45
  this.#hostConfigTracker = hostConfigTracker;
45
46
  this.#settings = settings;
46
47
 
48
+ this.#tryResolveSetting();
49
+ }
50
+
51
+ override addEventListener<T extends keyof EventTypes>(
52
+ eventType: T,
53
+ listener: Common.EventTarget.EventListener<EventTypes, T>,
54
+ thisObject?: Object,
55
+ ): Common.EventTarget.EventDescriptor<EventTypes, T> {
56
+ const isFirst = !this.hasEventListeners(eventType);
57
+ const descriptor = super.addEventListener(eventType, listener, thisObject);
58
+ if (isFirst) {
59
+ this.#subscribe();
60
+ }
61
+ return descriptor;
62
+ }
63
+
64
+ override removeEventListener<T extends keyof EventTypes>(
65
+ eventType: T,
66
+ listener: Common.EventTarget.EventListener<EventTypes, T>,
67
+ thisObject?: Object,
68
+ ): void {
69
+ super.removeEventListener(eventType, listener, thisObject);
70
+ if (!this.hasEventListeners(eventType)) {
71
+ this.#unsubscribe();
72
+ }
73
+ }
74
+
75
+ #subscribe(): void {
76
+ if (this.#isSubscribed) {
77
+ return;
78
+ }
79
+ this.#tryResolveSetting();
80
+ this.#isSubscribed = true;
47
81
  this.#hostConfigTracker.addEventListener(
48
82
  Host.AidaClient.Events.AIDA_AVAILABILITY_CHANGED,
49
83
  this.#boundOnAidaAvailabilityChanged,
50
84
  );
51
- this.#tryResolveSetting();
85
+ this.#setting?.addChangeListener(this.#boundOnSettingChanged);
86
+ }
87
+
88
+ #unsubscribe(): void {
89
+ if (!this.#isSubscribed) {
90
+ return;
91
+ }
92
+ this.#isSubscribed = false;
93
+ this.#hostConfigTracker.removeEventListener(
94
+ Host.AidaClient.Events.AIDA_AVAILABILITY_CHANGED,
95
+ this.#boundOnAidaAvailabilityChanged,
96
+ );
97
+ this.#setting?.removeChangeListener(this.#boundOnSettingChanged);
52
98
  }
53
99
 
54
100
  #tryResolveSetting(): void {
@@ -56,12 +102,19 @@ export class AiSetting<ValueT> extends Common.ObjectWrapper.ObjectWrapper<EventT
56
102
  Common.Settings.ConditionalSettingDescriptor<unknown, DisabledReason[]>);
57
103
  if ('setting' in result) {
58
104
  if (this.#setting !== result.setting) {
59
- if (this.#setting) {
105
+ if (this.#setting && this.#isSubscribed) {
60
106
  this.#setting.removeChangeListener(this.#boundOnSettingChanged);
61
107
  }
62
108
  this.#setting = result.setting as Common.Settings.Setting<ValueT>;
63
- this.#setting.addChangeListener(this.#boundOnSettingChanged);
109
+ if (this.#isSubscribed) {
110
+ this.#setting.addChangeListener(this.#boundOnSettingChanged);
111
+ }
64
112
  }
113
+ } else if (this.#setting) {
114
+ if (this.#isSubscribed) {
115
+ this.#setting.removeChangeListener(this.#boundOnSettingChanged);
116
+ }
117
+ this.#setting = undefined;
65
118
  }
66
119
  }
67
120
 
@@ -87,6 +140,7 @@ export class AiSetting<ValueT> extends Common.ObjectWrapper.ObjectWrapper<EventT
87
140
  if (this.disabled || this.unavailable) {
88
141
  return undefined;
89
142
  }
143
+ this.#tryResolveSetting();
90
144
  return this.#setting?.get();
91
145
  }
92
146
 
@@ -94,9 +148,18 @@ export class AiSetting<ValueT> extends Common.ObjectWrapper.ObjectWrapper<EventT
94
148
  if (this.disabled || this.unavailable) {
95
149
  return;
96
150
  }
151
+ this.#tryResolveSetting();
97
152
  this.#setting?.set(value);
98
153
  }
99
154
 
155
+ get(): ValueT|undefined {
156
+ return this.getIfNotDisabled();
157
+ }
158
+
159
+ set(value: ValueT): void {
160
+ this.setIfNotDisabled(value);
161
+ }
162
+
100
163
  #onSettingChanged(): void {
101
164
  this.dispatchEventToListeners(Events.CHANGED);
102
165
  }
@@ -6,7 +6,7 @@ Content:
6
6
  "details": [
7
7
  {
8
8
  "title": "Trace details",
9
- "text": "Trace summary:\nURL: https://web.dev/\nTrace bounds: {min: 465455241690µs, max: 465460435979µs}\nCPU throttling: 1x\nNetwork throttling: No throttling\n\n# Available insight sets\n\nThe following is a list of insight sets. An insight set covers a specific part of the trace, split by navigations. The insights within each insight set are specific to that part of the trace. Be sure to consider the insight set id and bounds when calling functions. If no specific insight set or navigation is mentioned, assume the user is referring to the first one.\n\n## insight set id: NO_NAVIGATION\n\nURL: https://web.dev/\nBounds: {min: 465455241690µs, max: 465456489730µs}\nMetrics (lab / observed):\n - CLS: 0.00\nMetrics (field / real users): n/a – no data for this page in CrUX\nAvailable insights:\n - insight name: ThirdParties\n description: 3rd party code can significantly impact load performance. [Reduce and defer loading of 3rd party code](https://developer.chrome.com/docs/performance/insights/third-parties) to prioritize your page’s content.\n relevant trace bounds: {min: 465456492168µs, max: 465460052616µs}\n example question: Which third parties are having the largest impact on my page performance?\n\n## insight set id: NAVIGATION_1\n\nURL: https://web.dev/\nBounds: {min: 465456489730µs, max: 465460435979µs}\nMetrics (lab / observed):\n - LCP: 676 ms, event: (eventKey: r-21246, ts: 465457166052), nodeId: 1680\n - LCP breakdown:\n - TTFB: 553 ms, bounds: {min: 465456489730µs, max: 465457042737µs}\n - Render delay: 123 ms, bounds: {min: 465457042737µs, max: 465457166052µs}\n - CLS: 0.02, event: (eventKey: s-14250, ts: 465457121239)\nMetrics (field / real users): n/a – no data for this page in CrUX\nAvailable insights:\n - insight name: RenderBlocking\n description: Requests are blocking the page’s initial render, which may delay LCP. [Deferring or inlining](https://developer.chrome.com/docs/performance/insights/render-blocking) can move these network requests out of the critical path.\n relevant trace bounds: {min: 465457046567µs, max: 465457086893µs}\n estimated metric savings: FCP 118 ms, LCP 118 ms\n example question: Show me the most impactful render-blocking requests that I should focus on\n example question: How can I reduce the number of render-blocking requests?\n - insight name: LCPBreakdown\n description: Each [subpart has specific improvement strategies](https://developer.chrome.com/docs/performance/insights/lcp-breakdown). Ideally, most of the LCP time should be spent on loading the resources, not within delays.\n relevant trace bounds: {min: 465456489730µs, max: 465457166052µs}\n example question: Help me optimize my LCP score\n example question: Which LCP subpart was most problematic?\n example question: What can I do to reduce the LCP time for this page load?\n - insight name: CLSCulprits\n description: Layout shifts occur when elements move absent any user interaction. [Investigate the causes of layout shifts](https://developer.chrome.com/docs/performance/insights/cls-culprit), such as elements being added, removed, or their fonts changing as the page loads.\n relevant trace bounds: {min: 465457121239µs, max: 465459012394µs}\n example question: Help me optimize my CLS score\n example question: How can I prevent layout shifts on this page?\n - insight name: NetworkDependencyTree\n description: [Avoid chaining critical requests](https://developer.chrome.com/docs/performance/insights/network-dependency-tree) by reducing the length of chains, reducing the download size of resources, or deferring the download of unnecessary resources to improve page load.\n relevant trace bounds: {min: 465456490723µs, max: 465458472724µs}\n example question: How do I optimize my network dependency tree?\n - insight name: DOMSize\n description: A large DOM can increase the duration of style calculations and layout reflows, impacting page responsiveness. A large DOM will also increase memory usage. [Learn how to avoid an excessive DOM size](https://developer.chrome.com/docs/performance/insights/dom-size).\n relevant trace bounds: {min: 465458287196µs, max: 465458340745µs}\n example question: How can I reduce the size of my DOM?\n - insight name: ThirdParties\n description: 3rd party code can significantly impact load performance. [Reduce and defer loading of 3rd party code](https://developer.chrome.com/docs/performance/insights/third-parties) to prioritize your page’s content.\n relevant trace bounds: {min: 465456492168µs, max: 465460052616µs}\n example question: Which third parties are having the largest impact on my page performance?\n - insight name: ForcedReflow\n description: A forced reflow occurs when JavaScript queries geometric properties (such as offsetWidth) after styles have been invalidated by a change to the DOM state. This can result in poor performance. Learn more about [forced reflows](https://developer.chrome.com/docs/performance/insights/forced-reflow) and possible mitigations.\n relevant trace bounds: {min: 465456489730µs, max: 465460435979µs}\n example question: How can I avoid forced reflows and layout thrashing?\n example question: What is forced reflow and why is it problematic?\n - insight name: Cache\n description: A long cache lifetime can speed up repeat visits to your page. [Learn more about caching](https://developer.chrome.com/docs/performance/insights/cache).\n relevant trace bounds: {min: 465457179567µs, max: 465459110674µs}\n estimated metric savings: FCP 0 ms, LCP 0 ms\n estimated wasted bytes: 16 kB\n example question: What caching strategies can I apply to improve my page performance?\n# Critical network requests\n\n## insight set id: NO_NAVIGATION\n\nnone\n\n## insight set id: NAVIGATION_1\n\n\nNetwork requests data:\n\n\n\nallUrls = [0: https://web.dev/, 1: https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmEU9fCxc4AMP6lbBP.woff2, 2: https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmEU9fBxc4AMP6lbBP.woff2, 3: https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmEU9fABc4AMP6lbBP.woff2, 4: https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmEU9fChc4AMP6lbBP.woff2, 5: https://fonts.gstatic.com/s/materialicons/v142/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.woff2, 6: https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmEU9fBBc4AMP6lQ.woff2, 7: https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu4mxKKTU1Kg.woff2, 8: https://web.dev/_pwa/web/manifest.json, 9: https://fonts.googleapis.com/css?family=Google+Sans:400,500|Roboto:400,400italic,500,500italic,700,700italic|Roboto+Mono:400,500,700&display=swap, 10: https://fonts.gstatic.com/s/googlesans/v59/4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPjIUvbQoi-E.woff2, 11: https://fonts.googleapis.com/css2?family=Material+Icons&family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&display=block, 12: https://www.gstatic.com/devrel-devsite/prod/vafe2e13ca17bb026e70df42a2ead1c8192750e86a12923a88eda839025dabf95/web/css/app.css, 13: https://web.dev/extras.css]\n\n0;s-7302;1 ms;2 ms;568 ms;569 ms;568 ms;15 ms;0.5 ms;200;text/html;VeryHigh;VeryHigh;VeryHigh;f;unknown;t;;[];[content-security-policy: base-uri 'self'; object-src 'none'; script-src 'strict-dynamic' 'unsafe-inline' https: http: 'nonce-pLl1WHuNABXXiQLLmUesvDyvzBJZdE' 'unsafe-eval'; report-uri https://csp.withgoogle.com/csp/devsite/v2|content-encoding: gzip|x-content-type-options: nosniff|date: Mon, 29 Apr 2024 11:01:15 GMT|strict-transport-security: max-age=63072000; includeSubdomains; preload|alt-svc: h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000|content-length: <redacted>|x-xss-protection: 0|pragma: no-cache|last-modified: Fri, 26 Apr 2024 16:43:17 GMT|server: Google Frontend|vary: Cookie, Accept-Encoding|x-frame-options: SAMEORIGIN|content-type: text/html; charset=utf-8|x-cloud-trace-context: <redacted>|cache-control: no-cache, must-revalidate|expires: 0]\n1;s-49309;1,395 ms;1,402 ms;1,415 ms;1,423 ms;28 ms;94 μs;9 ms;200;font/woff2;VeryHigh;VeryHigh;VeryHigh;f;unknown;t;;[];[date: Wed, 24 Apr 2024 15:02:33 GMT|x-content-type-options: nosniff|age: 417214|content-security-policy-report-only: <redacted>|cross-origin-resource-policy: <redacted>|alt-svc: h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000|content-length: <redacted>|x-xss-protection: 0|last-modified: Wed, 11 May 2022 19:24:58 GMT|server: sffe|cross-origin-opener-policy: <redacted>|report-to: {\"group\":\"apps-themes\",\"max_age\":2592000,\"endpoints\":[{\"url\":\"https://csp.withgoogle.com/csp/report-to/apps-themes\"}]}|content-type: font/woff2|access-control-allow-origin: *|cache-control: public, max-age=31536000|accept-ranges: bytes|timing-allow-origin: *|expires: Thu, 24 Apr 2025 15:02:33 GMT]\n2;s-46519;1,348 ms;1,355 ms;1,361 ms;1,423 ms;75 ms;73 μs;62 ms;200;font/woff2;VeryHigh;VeryHigh;VeryHigh;f;unknown;t;;[];[date: Mon, 29 Apr 2024 03:50:51 GMT|x-content-type-options: nosniff|age: 25516|content-security-policy-report-only: <redacted>|cross-origin-resource-policy: <redacted>|alt-svc: h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000|content-length: <redacted>|x-xss-protection: 0|last-modified: Wed, 11 May 2022 19:24:41 GMT|server: sffe|cross-origin-opener-policy: <redacted>|report-to: {\"group\":\"apps-themes\",\"max_age\":2592000,\"endpoints\":[{\"url\":\"https://csp.withgoogle.com/csp/report-to/apps-themes\"}]}|content-type: font/woff2|access-control-allow-origin: *|cache-control: public, max-age=31536000|accept-ranges: bytes|timing-allow-origin: *|expires: Tue, 29 Apr 2025 03:50:51 GMT]\n3;s-46196;1,331 ms;1,339 ms;1,355 ms;1,420 ms;89 ms;0.1 ms;65 ms;200;font/woff2;VeryHigh;VeryHigh;VeryHigh;f;unknown;t;;[];[date: Fri, 26 Apr 2024 20:29:46 GMT|x-content-type-options: nosniff|age: 224781|content-security-policy-report-only: <redacted>|cross-origin-resource-policy: <redacted>|alt-svc: h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000|content-length: <redacted>|x-xss-protection: 0|last-modified: Wed, 11 May 2022 19:24:39 GMT|server: sffe|cross-origin-opener-policy: <redacted>|report-to: {\"group\":\"apps-themes\",\"max_age\":2592000,\"endpoints\":[{\"url\":\"https://csp.withgoogle.com/csp/report-to/apps-themes\"}]}|content-type: font/woff2|access-control-allow-origin: *|cache-control: public, max-age=31536000|accept-ranges: bytes|timing-allow-origin: *|expires: Sat, 26 Apr 2025 20:29:46 GMT]\n4;s-45814;1,326 ms;1,331 ms;1,348 ms;1,419 ms;93 ms;77 μs;71 ms;200;font/woff2;VeryHigh;VeryHigh;VeryHigh;f;unknown;t;;[];[date: Thu, 25 Apr 2024 13:27:47 GMT|x-content-type-options: nosniff|age: 336500|content-security-policy-report-only: <redacted>|cross-origin-resource-policy: <redacted>|alt-svc: h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000|content-length: <redacted>|x-xss-protection: 0|last-modified: Wed, 11 May 2022 19:24:56 GMT|server: sffe|cross-origin-opener-policy: <redacted>|report-to: {\"group\":\"apps-themes\",\"max_age\":2592000,\"endpoints\":[{\"url\":\"https://csp.withgoogle.com/csp/report-to/apps-themes\"}]}|content-type: font/woff2|access-control-allow-origin: *|cache-control: public, max-age=31536000|accept-ranges: bytes|timing-allow-origin: *|expires: Fri, 25 Apr 2025 13:27:47 GMT]\n5;s-44751;1,286 ms;1,307 ms;1,343 ms;1,416 ms;130 ms;1 ms;73 ms;200;font/woff2;VeryHigh;VeryHigh;VeryHigh;f;unknown;t;;[];[date: Fri, 26 Apr 2024 09:49:05 GMT|x-content-type-options: nosniff|age: 263222|content-security-policy-report-only: <redacted>|cross-origin-resource-policy: <redacted>|alt-svc: h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000|content-length: <redacted>|x-xss-protection: 0|last-modified: Mon, 08 Apr 2024 19:04:51 GMT|server: sffe|cross-origin-opener-policy: <redacted>|report-to: {\"group\":\"apps-themes\",\"max_age\":2592000,\"endpoints\":[{\"url\":\"https://csp.withgoogle.com/csp/report-to/apps-themes\"}]}|content-type: font/woff2|access-control-allow-origin: *|cache-control: public, max-age=31536000|accept-ranges: bytes|timing-allow-origin: *|expires: Sat, 26 Apr 2025 09:49:05 GMT]\n6;s-44728;1,285 ms;1,307 ms;1,343 ms;1,406 ms;120 ms;1 ms;62 ms;200;font/woff2;VeryHigh;VeryHigh;VeryHigh;f;unknown;t;;[];[date: Sun, 28 Apr 2024 21:44:44 GMT|x-content-type-options: nosniff|age: 47483|content-security-policy-report-only: <redacted>|cross-origin-resource-policy: <redacted>|alt-svc: h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000|content-length: <redacted>|x-xss-protection: 0|last-modified: Wed, 11 May 2022 19:24:53 GMT|server: sffe|cross-origin-opener-policy: <redacted>|report-to: {\"group\":\"apps-themes\",\"max_age\":2592000,\"endpoints\":[{\"url\":\"https://csp.withgoogle.com/csp/report-to/apps-themes\"}]}|content-type: font/woff2|access-control-allow-origin: *|cache-control: public, max-age=31536000|accept-ranges: bytes|timing-allow-origin: *|expires: Mon, 28 Apr 2025 21:44:44 GMT]\n7;s-44701;1,284 ms;1,300 ms;1,339 ms;1,405 ms;120 ms;0.2 ms;65 ms;200;font/woff2;VeryHigh;VeryHigh;VeryHigh;f;unknown;t;;[];[date: Thu, 25 Apr 2024 09:35:28 GMT|x-content-type-options: nosniff|age: 350439|content-security-policy-report-only: <redacted>|cross-origin-resource-policy: <redacted>|alt-svc: h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000|content-length: <redacted>|x-xss-protection: 0|last-modified: Wed, 11 May 2022 19:24:50 GMT|server: sffe|cross-origin-opener-policy: <redacted>|report-to: {\"group\":\"apps-themes\",\"max_age\":2592000,\"endpoints\":[{\"url\":\"https://csp.withgoogle.com/csp/report-to/apps-themes\"}]}|content-type: font/woff2|access-control-allow-origin: *|cache-control: public, max-age=31536000|accept-ranges: bytes|timing-allow-origin: *|expires: Fri, 25 Apr 2025 09:35:28 GMT]\n8;s-43119;1,751 ms;1,751 ms;1,771 ms;1,771 ms;20 ms;27 μs;0.2 ms;200;application/json;Medium;Medium;Medium;f;unknown;t;0;[];[date: Sun, 28 Apr 2024 14:07:49 GMT|last-modified: Wed, 24 Apr 2024 11:02:59 GMT|server: Google Frontend|age: 75208|content-type: application/json|x-cloud-trace-context: <redacted>|cache-control: public, max-age=86400|alt-svc: h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000|content-length: <redacted>]\n9;s-7695;557 ms;557 ms;597 ms;597 ms;40 ms;3 ms;0.6 ms;200;text/css;VeryHigh;VeryHigh;VeryHigh;t;unknown;t;0;[];[date: Mon, 29 Apr 2024 11:01:15 GMT|content-encoding: gzip|x-content-type-options: nosniff|strict-transport-security: max-age=31536000|cross-origin-resource-policy: <redacted>|alt-svc: h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000|x-xss-protection: 0|last-modified: Mon, 29 Apr 2024 10:51:49 GMT|server: ESF|cross-origin-opener-policy: <redacted>|x-frame-options: SAMEORIGIN|content-type: text/css; charset=utf-8|access-control-allow-origin: *|cache-control: private, max-age=86400, stale-while-revalidate=604800|timing-allow-origin: *|link: <https://fonts.gstatic.com>; rel=preconnect; crossorigin|expires: Mon, 29 Apr 2024 11:01:15 GMT]\n7;s-34909;770 ms;770 ms;771 ms;776 ms;6 ms;40 μs;5 ms;200;font/woff2;VeryHigh;VeryHigh;VeryHigh;f;unknown;t;;[];[x-google-security-signals: <redacted>|x-google-gfe-service-trace: <redacted>|content-security-policy-report-only: <redacted>|x-google-scs-row-timestamp: <redacted>|x-google-gfe-response-code-details-trace: <redacted>|cross-origin-resource-policy: <redacted>|x-google-scs-row-key: <redacted>|content-type: font/woff2|access-control-allow-origin: *|x-google-data-version: <redacted>|cache-control: public, max-age=31536000|x-google-gfe-backend-request-info: <redacted>|x-google-dos-service-trace: <redacted>|x-google-backends: <redacted>|date: Thu, 26 Oct 2023 10:46:00 GMT|x-content-type-options: nosniff|expires: Fri, 25 Oct 2024 10:46:00 GMT|x-google-gfe-version: <redacted>|x-google-netmon-label: <redacted>|alt-svc: h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000|content-length: <redacted>|x-google-service: <redacted>|x-xss-protection: 0|x-google-gfe-handshake-trace: <redacted>|x-google-shellfish-status: <redacted>|last-modified: Wed, 11 May 2022 19:24:50 GMT|server: sffe|cross-origin-opener-policy: <redacted>|report-to: {\"group\":\"apps-themes\",\"max_age\":2592000,\"endpoints\":[{\"url\":\"https://csp.withgoogle.com/csp/report-to/apps-themes\"}]}|x-google-gfe-request-trace: <redacted>|accept-ranges: bytes|timing-allow-origin: *|x-google-scs-repo: <redacted>]\n10;s-11121;602 ms;602 ms;603 ms;611 ms;9 ms;27 μs;8 ms;200;font/woff2;VeryHigh;VeryHigh;VeryHigh;f;unknown;t;;[];[date: Thu, 25 Apr 2024 15:44:03 GMT|x-content-type-options: nosniff|age: 328319|content-security-policy-report-only: <redacted>|cross-origin-resource-policy: <redacted>|alt-svc: h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000|content-length: <redacted>|x-xss-protection: 0|last-modified: Wed, 24 Apr 2024 23:37:14 GMT|server: sffe|cross-origin-opener-policy: <redacted>|report-to: {\"group\":\"apps-themes\",\"max_age\":2592000,\"endpoints\":[{\"url\":\"https://csp.withgoogle.com/csp/report-to/apps-themes\"}]}|content-type: font/woff2|access-control-allow-origin: *|cache-control: public, max-age=31536000|accept-ranges: bytes|timing-allow-origin: *|expires: Fri, 25 Apr 2025 15:44:03 GMT]\n11;s-7703;557 ms;557 ms;597 ms;597 ms;40 ms;90 μs;0.1 ms;200;text/css;VeryHigh;VeryHigh;VeryHigh;t;unknown;t;0;[];[date: Mon, 29 Apr 2024 11:01:15 GMT|content-encoding: gzip|x-content-type-options: nosniff|strict-transport-security: max-age=31536000|cross-origin-resource-policy: <redacted>|alt-svc: h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000|x-xss-protection: 0|last-modified: Mon, 29 Apr 2024 11:01:15 GMT|server: ESF|cross-origin-opener-policy: <redacted>|x-frame-options: SAMEORIGIN|content-type: text/css; charset=utf-8|access-control-allow-origin: *|cache-control: private, max-age=86400, stale-while-revalidate=604800|timing-allow-origin: *|link: <https://fonts.gstatic.com>; rel=preconnect; crossorigin|expires: Mon, 29 Apr 2024 11:01:15 GMT]\n5;s-11334;606 ms;606 ms;607 ms;615 ms;9 ms;30 μs;8 ms;200;font/woff2;VeryHigh;VeryHigh;VeryHigh;f;unknown;t;11;[];[date: Fri, 26 Apr 2024 09:49:05 GMT|x-content-type-options: nosniff|age: 263217|content-security-policy-report-only: <redacted>|cross-origin-resource-policy: <redacted>|alt-svc: h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000|content-length: <redacted>|x-xss-protection: 0|last-modified: Mon, 08 Apr 2024 19:04:51 GMT|server: sffe|cross-origin-opener-policy: <redacted>|report-to: {\"group\":\"apps-themes\",\"max_age\":2592000,\"endpoints\":[{\"url\":\"https://csp.withgoogle.com/csp/report-to/apps-themes\"}]}|content-type: font/woff2|access-control-allow-origin: *|cache-control: public, max-age=31536000|accept-ranges: bytes|timing-allow-origin: *|expires: Sat, 26 Apr 2025 09:49:05 GMT]\n12;s-7722;557 ms;557 ms;562 ms;568 ms;11 ms;0.5 ms;6 ms;200;text/css;VeryHigh;VeryHigh;VeryHigh;t;unknown;t;0;[];[date: Mon, 29 Apr 2024 10:56:02 GMT|content-encoding: gzip|x-content-type-options: nosniff|age: 256|content-security-policy-report-only: <redacted>|cross-origin-resource-policy: <redacted>|alt-svc: h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000|content-length: <redacted>|x-xss-protection: 0|last-modified: Thu, 25 Apr 2024 19:58:26 GMT|server: sffe|cross-origin-opener-policy: <redacted>|vary: Accept-Encoding|report-to: {\"group\":\"devrel-devsite\",\"max_age\":2592000,\"endpoints\":[{\"url\":\"https://csp.withgoogle.com/csp/report-to/devrel-devsite\"}]}|content-type: text/css|access-control-allow-origin: *|cache-control: public, max-age=31536000|accept-ranges: bytes|expires: Tue, 29 Apr 2025 10:56:02 GMT]\n13;s-7737;557 ms;557 ms;561 ms;561 ms;4 ms;0.4 ms;0.2 ms;200;text/css;VeryHigh;VeryHigh;VeryHigh;t;unknown;t;0;[];[content-security-policy: base-uri 'self'; object-src 'none'; script-src 'strict-dynamic' 'unsafe-inline' https: http: 'nonce-laTwEoovJjOKcMoBUjSFaYO6rrF8dU' 'unsafe-eval'; report-uri https://csp.withgoogle.com/csp/devsite/v2|content-encoding: gzip|x-content-type-options: nosniff|date: Mon, 29 Apr 2024 11:00:18 GMT|strict-transport-security: max-age=63072000; includeSubdomains; preload|alt-svc: h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000|content-length: <redacted>|x-xss-protection: 0|pragma: no-cache|last-modified: Tue, 19 Mar 2024 18:37:07 GMT|server: Google Frontend|vary: Cookie, Accept-Encoding|x-frame-options: SAMEORIGIN|content-type: text/css|x-cloud-trace-context: <redacted>|cache-control: no-cache, must-revalidate|expires: 0]\n\n# Main thread bottom-up summary\n\nThis is the bottom-up summary for the entire trace. Only the top 10 activities (sorted by self time) are shown. An activity is all the aggregated time spent on the same type of work. For example, it can be all the time spent in a specific JavaScript function, or all the time spent in a specific browser rendering stage (like layout, v8 compile, parsing html). \"Self time\" represents the aggregated time spent directly in an activity, across all occurrences. \"Total time\" represents the aggregated time spent in an activity or any of its children.\n\n## insight set id: NO_NAVIGATION\n\n- self: 12 ms, total: 12 ms, source: Profiling overhead\n- self: 4 ms, total: 28 ms, source: Task\n- self: 3 ms, total: 4 ms, source: Recalculate style (url: https://www.gstatic.com/devrel-devsite/prod/vafe2e13ca17bb026e70df42a2ead1c8192750e86a12923a88eda839025dabf95/js/devsite_app_module.js, line: 98, column: 12)\n- self: 2 ms, total: 2 ms, source: Commit\n- self: 0.9 ms, total: 2 ms, source: Function call (url: https://www.gstatic.com/devrel-devsite/prod/vafe2e13ca17bb026e70df42a2ead1c8192750e86a12923a88eda839025dabf95/js/devsite_app_module.js, line: 102, column: 35)\n- self: 0.8 ms, total: 13 ms, source: Evaluate script\n- self: 0.7 ms, total: 3 ms, source: Event: pointerover\n- self: 0.1 ms, total: 1 ms, source: Xh (url: https://www.gstatic.com/devrel-devsite/prod/vafe2e13ca17bb026e70df42a2ead1c8192750e86a12923a88eda839025dabf95/js/devsite_app_module.js, line: 104, column: 61)\n\n## insight set id: NAVIGATION_1\n\n- self: 46 ms, total: 49 ms, source: Recalculate style\n- self: 37 ms, total: 211 ms, source: Task\n- self: 21 ms, total: 22 ms, source: Layout\n- self: 17 ms, total: 19 ms, source: Compile code\n- self: 7 ms, total: 7 ms, source: Cache script code\n- self: 6 ms, total: 26 ms, source: Function call (url: https://www.gstatic.com/devrel-devsite/prod/vafe2e13ca17bb026e70df42a2ead1c8192750e86a12923a88eda839025dabf95/js/devsite_app_module.js, line: 288, column: 146)\n- self: 5 ms, total: 5 ms, source: Parse stylesheet\n- self: 5 ms, total: 5 ms, source: Pre-paint\n- self: 5 ms, total: 5 ms, source: Commit\n- self: 5 ms, total: 10 ms, source: appendChild\n\n# 3rd party summary\n\n## insight set id: NO_NAVIGATION\n\n- name: Google CDN, main thread time: 1 ms, network transfer size: 0 B\n\n## insight set id: NAVIGATION_1\n\n- name: Google CDN, main thread time: 38 ms, network transfer size: 990 B\n- name: web.dev, main thread time: 3 ms, network transfer size: 84.3 kB\n- name: Google Analytics, main thread time: 0.6 ms, network transfer size: 52.9 kB\n- name: Google Fonts, main thread time: 0 ms, network transfer size: 42.2 kB\n\n# Longest tasks\n\n## insight set id: NO_NAVIGATION\n\n- total time: 13 ms, event: (eventKey: r-96, ts: 465455241964)\n- total time: 2 ms, event: (eventKey: r-934, ts: 465455475572)\n- total time: 1 ms, event: (eventKey: r-2310, ts: 465455879141)\n\n## insight set id: NAVIGATION_1\n\n- total time: 18 ms, event: (eventKey: r-20182, ts: 465457150438)\n- total time: 14 ms, event: (eventKey: r-12184, ts: 465457104625)\n- total time: 12 ms, event: (eventKey: r-10779, ts: 465457087373)\n\nUser selected the following call tree:\n\n\n\n# Call tree:\n\n1;r-10779;Task;3;;;2;;\n2;r-11902;Layout;3;3;;;;;S\n\n\n# User query\n\ntest"
9
+ "text": "Trace summary:\nURL: https://web.dev/\nTrace bounds: {min: 465455241690µs, max: 465460435979µs}\nCPU throttling: 1x\nNetwork throttling: No throttling\n\n# Available insight sets\n\nThe following is a list of insight sets. An insight set covers a specific part of the trace, split by navigations. The insights within each insight set are specific to that part of the trace. Be sure to consider the insight set id and bounds when calling functions. If no specific insight set or navigation is mentioned, assume the user is referring to the first one.\n\n## insight set id: NO_NAVIGATION\n\nURL: https://web.dev/\nBounds: {min: 465455241690µs, max: 465456489729µs}\nMetrics (lab / observed):\n - CLS: 0.00\nMetrics (field / real users): n/a – no data for this page in CrUX\nAvailable insights:\n - insight name: ThirdParties\n description: 3rd party code can significantly impact load performance. [Reduce and defer loading of 3rd party code](https://developer.chrome.com/docs/performance/insights/third-parties) to prioritize your page’s content.\n relevant trace bounds: {min: 465456492168µs, max: 465460052616µs}\n example question: Which third parties are having the largest impact on my page performance?\n\n## insight set id: NAVIGATION_1\n\nURL: https://web.dev/\nBounds: {min: 465456489730µs, max: 465460435979µs}\nMetrics (lab / observed):\n - LCP: 676 ms, event: (eventKey: r-21246, ts: 465457166052), nodeId: 1680\n - LCP breakdown:\n - TTFB: 553 ms, bounds: {min: 465456489730µs, max: 465457042737µs}\n - Render delay: 123 ms, bounds: {min: 465457042737µs, max: 465457166052µs}\n - CLS: 0.02, event: (eventKey: s-14250, ts: 465457121239)\nMetrics (field / real users): n/a – no data for this page in CrUX\nAvailable insights:\n - insight name: RenderBlocking\n description: Requests are blocking the page’s initial render, which may delay LCP. [Deferring or inlining](https://developer.chrome.com/docs/performance/insights/render-blocking) can move these network requests out of the critical path.\n relevant trace bounds: {min: 465457046567µs, max: 465457086893µs}\n estimated metric savings: FCP 118 ms, LCP 118 ms\n example question: Show me the most impactful render-blocking requests that I should focus on\n example question: How can I reduce the number of render-blocking requests?\n - insight name: LCPBreakdown\n description: Each [subpart has specific improvement strategies](https://developer.chrome.com/docs/performance/insights/lcp-breakdown). Ideally, most of the LCP time should be spent on loading the resources, not within delays.\n relevant trace bounds: {min: 465456489730µs, max: 465457166052µs}\n example question: Help me optimize my LCP score\n example question: Which LCP subpart was most problematic?\n example question: What can I do to reduce the LCP time for this page load?\n - insight name: CLSCulprits\n description: Layout shifts occur when elements move absent any user interaction. [Investigate the causes of layout shifts](https://developer.chrome.com/docs/performance/insights/cls-culprit), such as elements being added, removed, or their fonts changing as the page loads.\n relevant trace bounds: {min: 465457121239µs, max: 465459012394µs}\n example question: Help me optimize my CLS score\n example question: How can I prevent layout shifts on this page?\n - insight name: NetworkDependencyTree\n description: [Avoid chaining critical requests](https://developer.chrome.com/docs/performance/insights/network-dependency-tree) by reducing the length of chains, reducing the download size of resources, or deferring the download of unnecessary resources to improve page load.\n relevant trace bounds: {min: 465456490723µs, max: 465458472724µs}\n example question: How do I optimize my network dependency tree?\n - insight name: DOMSize\n description: A large DOM can increase the duration of style calculations and layout reflows, impacting page responsiveness. A large DOM will also increase memory usage. [Learn how to avoid an excessive DOM size](https://developer.chrome.com/docs/performance/insights/dom-size).\n relevant trace bounds: {min: 465458287196µs, max: 465458340745µs}\n example question: How can I reduce the size of my DOM?\n - insight name: ThirdParties\n description: 3rd party code can significantly impact load performance. [Reduce and defer loading of 3rd party code](https://developer.chrome.com/docs/performance/insights/third-parties) to prioritize your page’s content.\n relevant trace bounds: {min: 465456492168µs, max: 465460052616µs}\n example question: Which third parties are having the largest impact on my page performance?\n - insight name: ForcedReflow\n description: A forced reflow occurs when JavaScript queries geometric properties (such as offsetWidth) after styles have been invalidated by a change to the DOM state. This can result in poor performance. Learn more about [forced reflows](https://developer.chrome.com/docs/performance/insights/forced-reflow) and possible mitigations.\n relevant trace bounds: {min: 465456489730µs, max: 465460435979µs}\n example question: How can I avoid forced reflows and layout thrashing?\n example question: What is forced reflow and why is it problematic?\n - insight name: Cache\n description: A long cache lifetime can speed up repeat visits to your page. [Learn more about caching](https://developer.chrome.com/docs/performance/insights/cache).\n relevant trace bounds: {min: 465457179567µs, max: 465459110674µs}\n estimated metric savings: FCP 0 ms, LCP 0 ms\n estimated wasted bytes: 16 kB\n example question: What caching strategies can I apply to improve my page performance?\n# Critical network requests\n\n## insight set id: NO_NAVIGATION\n\nnone\n\n## insight set id: NAVIGATION_1\n\n\nNetwork requests data:\n\n\n\nallUrls = [0: https://web.dev/, 1: https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmEU9fCxc4AMP6lbBP.woff2, 2: https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmEU9fBxc4AMP6lbBP.woff2, 3: https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmEU9fABc4AMP6lbBP.woff2, 4: https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmEU9fChc4AMP6lbBP.woff2, 5: https://fonts.gstatic.com/s/materialicons/v142/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.woff2, 6: https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmEU9fBBc4AMP6lQ.woff2, 7: https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu4mxKKTU1Kg.woff2, 8: https://web.dev/_pwa/web/manifest.json, 9: https://fonts.googleapis.com/css?family=Google+Sans:400,500|Roboto:400,400italic,500,500italic,700,700italic|Roboto+Mono:400,500,700&display=swap, 10: https://fonts.gstatic.com/s/googlesans/v59/4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPjIUvbQoi-E.woff2, 11: https://fonts.googleapis.com/css2?family=Material+Icons&family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&display=block, 12: https://www.gstatic.com/devrel-devsite/prod/vafe2e13ca17bb026e70df42a2ead1c8192750e86a12923a88eda839025dabf95/web/css/app.css, 13: https://web.dev/extras.css]\n\n0;s-7302;1 ms;2 ms;568 ms;569 ms;568 ms;15 ms;0.5 ms;200;text/html;VeryHigh;VeryHigh;VeryHigh;f;unknown;t;;[];[content-security-policy: base-uri 'self'; object-src 'none'; script-src 'strict-dynamic' 'unsafe-inline' https: http: 'nonce-pLl1WHuNABXXiQLLmUesvDyvzBJZdE' 'unsafe-eval'; report-uri https://csp.withgoogle.com/csp/devsite/v2|content-encoding: gzip|x-content-type-options: nosniff|date: Mon, 29 Apr 2024 11:01:15 GMT|strict-transport-security: max-age=63072000; includeSubdomains; preload|alt-svc: h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000|content-length: <redacted>|x-xss-protection: 0|pragma: no-cache|last-modified: Fri, 26 Apr 2024 16:43:17 GMT|server: Google Frontend|vary: Cookie, Accept-Encoding|x-frame-options: SAMEORIGIN|content-type: text/html; charset=utf-8|x-cloud-trace-context: <redacted>|cache-control: no-cache, must-revalidate|expires: 0]\n1;s-49309;1,395 ms;1,402 ms;1,415 ms;1,423 ms;28 ms;94 μs;9 ms;200;font/woff2;VeryHigh;VeryHigh;VeryHigh;f;unknown;t;;[];[date: Wed, 24 Apr 2024 15:02:33 GMT|x-content-type-options: nosniff|age: 417214|content-security-policy-report-only: <redacted>|cross-origin-resource-policy: <redacted>|alt-svc: h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000|content-length: <redacted>|x-xss-protection: 0|last-modified: Wed, 11 May 2022 19:24:58 GMT|server: sffe|cross-origin-opener-policy: <redacted>|report-to: {\"group\":\"apps-themes\",\"max_age\":2592000,\"endpoints\":[{\"url\":\"https://csp.withgoogle.com/csp/report-to/apps-themes\"}]}|content-type: font/woff2|access-control-allow-origin: *|cache-control: public, max-age=31536000|accept-ranges: bytes|timing-allow-origin: *|expires: Thu, 24 Apr 2025 15:02:33 GMT]\n2;s-46519;1,348 ms;1,355 ms;1,361 ms;1,423 ms;75 ms;73 μs;62 ms;200;font/woff2;VeryHigh;VeryHigh;VeryHigh;f;unknown;t;;[];[date: Mon, 29 Apr 2024 03:50:51 GMT|x-content-type-options: nosniff|age: 25516|content-security-policy-report-only: <redacted>|cross-origin-resource-policy: <redacted>|alt-svc: h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000|content-length: <redacted>|x-xss-protection: 0|last-modified: Wed, 11 May 2022 19:24:41 GMT|server: sffe|cross-origin-opener-policy: <redacted>|report-to: {\"group\":\"apps-themes\",\"max_age\":2592000,\"endpoints\":[{\"url\":\"https://csp.withgoogle.com/csp/report-to/apps-themes\"}]}|content-type: font/woff2|access-control-allow-origin: *|cache-control: public, max-age=31536000|accept-ranges: bytes|timing-allow-origin: *|expires: Tue, 29 Apr 2025 03:50:51 GMT]\n3;s-46196;1,331 ms;1,339 ms;1,355 ms;1,420 ms;89 ms;0.1 ms;65 ms;200;font/woff2;VeryHigh;VeryHigh;VeryHigh;f;unknown;t;;[];[date: Fri, 26 Apr 2024 20:29:46 GMT|x-content-type-options: nosniff|age: 224781|content-security-policy-report-only: <redacted>|cross-origin-resource-policy: <redacted>|alt-svc: h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000|content-length: <redacted>|x-xss-protection: 0|last-modified: Wed, 11 May 2022 19:24:39 GMT|server: sffe|cross-origin-opener-policy: <redacted>|report-to: {\"group\":\"apps-themes\",\"max_age\":2592000,\"endpoints\":[{\"url\":\"https://csp.withgoogle.com/csp/report-to/apps-themes\"}]}|content-type: font/woff2|access-control-allow-origin: *|cache-control: public, max-age=31536000|accept-ranges: bytes|timing-allow-origin: *|expires: Sat, 26 Apr 2025 20:29:46 GMT]\n4;s-45814;1,326 ms;1,331 ms;1,348 ms;1,419 ms;93 ms;77 μs;71 ms;200;font/woff2;VeryHigh;VeryHigh;VeryHigh;f;unknown;t;;[];[date: Thu, 25 Apr 2024 13:27:47 GMT|x-content-type-options: nosniff|age: 336500|content-security-policy-report-only: <redacted>|cross-origin-resource-policy: <redacted>|alt-svc: h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000|content-length: <redacted>|x-xss-protection: 0|last-modified: Wed, 11 May 2022 19:24:56 GMT|server: sffe|cross-origin-opener-policy: <redacted>|report-to: {\"group\":\"apps-themes\",\"max_age\":2592000,\"endpoints\":[{\"url\":\"https://csp.withgoogle.com/csp/report-to/apps-themes\"}]}|content-type: font/woff2|access-control-allow-origin: *|cache-control: public, max-age=31536000|accept-ranges: bytes|timing-allow-origin: *|expires: Fri, 25 Apr 2025 13:27:47 GMT]\n5;s-44751;1,286 ms;1,307 ms;1,343 ms;1,416 ms;130 ms;1 ms;73 ms;200;font/woff2;VeryHigh;VeryHigh;VeryHigh;f;unknown;t;;[];[date: Fri, 26 Apr 2024 09:49:05 GMT|x-content-type-options: nosniff|age: 263222|content-security-policy-report-only: <redacted>|cross-origin-resource-policy: <redacted>|alt-svc: h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000|content-length: <redacted>|x-xss-protection: 0|last-modified: Mon, 08 Apr 2024 19:04:51 GMT|server: sffe|cross-origin-opener-policy: <redacted>|report-to: {\"group\":\"apps-themes\",\"max_age\":2592000,\"endpoints\":[{\"url\":\"https://csp.withgoogle.com/csp/report-to/apps-themes\"}]}|content-type: font/woff2|access-control-allow-origin: *|cache-control: public, max-age=31536000|accept-ranges: bytes|timing-allow-origin: *|expires: Sat, 26 Apr 2025 09:49:05 GMT]\n6;s-44728;1,285 ms;1,307 ms;1,343 ms;1,406 ms;120 ms;1 ms;62 ms;200;font/woff2;VeryHigh;VeryHigh;VeryHigh;f;unknown;t;;[];[date: Sun, 28 Apr 2024 21:44:44 GMT|x-content-type-options: nosniff|age: 47483|content-security-policy-report-only: <redacted>|cross-origin-resource-policy: <redacted>|alt-svc: h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000|content-length: <redacted>|x-xss-protection: 0|last-modified: Wed, 11 May 2022 19:24:53 GMT|server: sffe|cross-origin-opener-policy: <redacted>|report-to: {\"group\":\"apps-themes\",\"max_age\":2592000,\"endpoints\":[{\"url\":\"https://csp.withgoogle.com/csp/report-to/apps-themes\"}]}|content-type: font/woff2|access-control-allow-origin: *|cache-control: public, max-age=31536000|accept-ranges: bytes|timing-allow-origin: *|expires: Mon, 28 Apr 2025 21:44:44 GMT]\n7;s-44701;1,284 ms;1,300 ms;1,339 ms;1,405 ms;120 ms;0.2 ms;65 ms;200;font/woff2;VeryHigh;VeryHigh;VeryHigh;f;unknown;t;;[];[date: Thu, 25 Apr 2024 09:35:28 GMT|x-content-type-options: nosniff|age: 350439|content-security-policy-report-only: <redacted>|cross-origin-resource-policy: <redacted>|alt-svc: h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000|content-length: <redacted>|x-xss-protection: 0|last-modified: Wed, 11 May 2022 19:24:50 GMT|server: sffe|cross-origin-opener-policy: <redacted>|report-to: {\"group\":\"apps-themes\",\"max_age\":2592000,\"endpoints\":[{\"url\":\"https://csp.withgoogle.com/csp/report-to/apps-themes\"}]}|content-type: font/woff2|access-control-allow-origin: *|cache-control: public, max-age=31536000|accept-ranges: bytes|timing-allow-origin: *|expires: Fri, 25 Apr 2025 09:35:28 GMT]\n8;s-43119;1,751 ms;1,751 ms;1,771 ms;1,771 ms;20 ms;27 μs;0.2 ms;200;application/json;Medium;Medium;Medium;f;unknown;t;0;[];[date: Sun, 28 Apr 2024 14:07:49 GMT|last-modified: Wed, 24 Apr 2024 11:02:59 GMT|server: Google Frontend|age: 75208|content-type: application/json|x-cloud-trace-context: <redacted>|cache-control: public, max-age=86400|alt-svc: h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000|content-length: <redacted>]\n9;s-7695;557 ms;557 ms;597 ms;597 ms;40 ms;3 ms;0.6 ms;200;text/css;VeryHigh;VeryHigh;VeryHigh;t;unknown;t;0;[];[date: Mon, 29 Apr 2024 11:01:15 GMT|content-encoding: gzip|x-content-type-options: nosniff|strict-transport-security: max-age=31536000|cross-origin-resource-policy: <redacted>|alt-svc: h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000|x-xss-protection: 0|last-modified: Mon, 29 Apr 2024 10:51:49 GMT|server: ESF|cross-origin-opener-policy: <redacted>|x-frame-options: SAMEORIGIN|content-type: text/css; charset=utf-8|access-control-allow-origin: *|cache-control: private, max-age=86400, stale-while-revalidate=604800|timing-allow-origin: *|link: <https://fonts.gstatic.com>; rel=preconnect; crossorigin|expires: Mon, 29 Apr 2024 11:01:15 GMT]\n7;s-34909;770 ms;770 ms;771 ms;776 ms;6 ms;40 μs;5 ms;200;font/woff2;VeryHigh;VeryHigh;VeryHigh;f;unknown;t;;[];[x-google-security-signals: <redacted>|x-google-gfe-service-trace: <redacted>|content-security-policy-report-only: <redacted>|x-google-scs-row-timestamp: <redacted>|x-google-gfe-response-code-details-trace: <redacted>|cross-origin-resource-policy: <redacted>|x-google-scs-row-key: <redacted>|content-type: font/woff2|access-control-allow-origin: *|x-google-data-version: <redacted>|cache-control: public, max-age=31536000|x-google-gfe-backend-request-info: <redacted>|x-google-dos-service-trace: <redacted>|x-google-backends: <redacted>|date: Thu, 26 Oct 2023 10:46:00 GMT|x-content-type-options: nosniff|expires: Fri, 25 Oct 2024 10:46:00 GMT|x-google-gfe-version: <redacted>|x-google-netmon-label: <redacted>|alt-svc: h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000|content-length: <redacted>|x-google-service: <redacted>|x-xss-protection: 0|x-google-gfe-handshake-trace: <redacted>|x-google-shellfish-status: <redacted>|last-modified: Wed, 11 May 2022 19:24:50 GMT|server: sffe|cross-origin-opener-policy: <redacted>|report-to: {\"group\":\"apps-themes\",\"max_age\":2592000,\"endpoints\":[{\"url\":\"https://csp.withgoogle.com/csp/report-to/apps-themes\"}]}|x-google-gfe-request-trace: <redacted>|accept-ranges: bytes|timing-allow-origin: *|x-google-scs-repo: <redacted>]\n10;s-11121;602 ms;602 ms;603 ms;611 ms;9 ms;27 μs;8 ms;200;font/woff2;VeryHigh;VeryHigh;VeryHigh;f;unknown;t;;[];[date: Thu, 25 Apr 2024 15:44:03 GMT|x-content-type-options: nosniff|age: 328319|content-security-policy-report-only: <redacted>|cross-origin-resource-policy: <redacted>|alt-svc: h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000|content-length: <redacted>|x-xss-protection: 0|last-modified: Wed, 24 Apr 2024 23:37:14 GMT|server: sffe|cross-origin-opener-policy: <redacted>|report-to: {\"group\":\"apps-themes\",\"max_age\":2592000,\"endpoints\":[{\"url\":\"https://csp.withgoogle.com/csp/report-to/apps-themes\"}]}|content-type: font/woff2|access-control-allow-origin: *|cache-control: public, max-age=31536000|accept-ranges: bytes|timing-allow-origin: *|expires: Fri, 25 Apr 2025 15:44:03 GMT]\n11;s-7703;557 ms;557 ms;597 ms;597 ms;40 ms;90 μs;0.1 ms;200;text/css;VeryHigh;VeryHigh;VeryHigh;t;unknown;t;0;[];[date: Mon, 29 Apr 2024 11:01:15 GMT|content-encoding: gzip|x-content-type-options: nosniff|strict-transport-security: max-age=31536000|cross-origin-resource-policy: <redacted>|alt-svc: h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000|x-xss-protection: 0|last-modified: Mon, 29 Apr 2024 11:01:15 GMT|server: ESF|cross-origin-opener-policy: <redacted>|x-frame-options: SAMEORIGIN|content-type: text/css; charset=utf-8|access-control-allow-origin: *|cache-control: private, max-age=86400, stale-while-revalidate=604800|timing-allow-origin: *|link: <https://fonts.gstatic.com>; rel=preconnect; crossorigin|expires: Mon, 29 Apr 2024 11:01:15 GMT]\n5;s-11334;606 ms;606 ms;607 ms;615 ms;9 ms;30 μs;8 ms;200;font/woff2;VeryHigh;VeryHigh;VeryHigh;f;unknown;t;11;[];[date: Fri, 26 Apr 2024 09:49:05 GMT|x-content-type-options: nosniff|age: 263217|content-security-policy-report-only: <redacted>|cross-origin-resource-policy: <redacted>|alt-svc: h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000|content-length: <redacted>|x-xss-protection: 0|last-modified: Mon, 08 Apr 2024 19:04:51 GMT|server: sffe|cross-origin-opener-policy: <redacted>|report-to: {\"group\":\"apps-themes\",\"max_age\":2592000,\"endpoints\":[{\"url\":\"https://csp.withgoogle.com/csp/report-to/apps-themes\"}]}|content-type: font/woff2|access-control-allow-origin: *|cache-control: public, max-age=31536000|accept-ranges: bytes|timing-allow-origin: *|expires: Sat, 26 Apr 2025 09:49:05 GMT]\n12;s-7722;557 ms;557 ms;562 ms;568 ms;11 ms;0.5 ms;6 ms;200;text/css;VeryHigh;VeryHigh;VeryHigh;t;unknown;t;0;[];[date: Mon, 29 Apr 2024 10:56:02 GMT|content-encoding: gzip|x-content-type-options: nosniff|age: 256|content-security-policy-report-only: <redacted>|cross-origin-resource-policy: <redacted>|alt-svc: h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000|content-length: <redacted>|x-xss-protection: 0|last-modified: Thu, 25 Apr 2024 19:58:26 GMT|server: sffe|cross-origin-opener-policy: <redacted>|vary: Accept-Encoding|report-to: {\"group\":\"devrel-devsite\",\"max_age\":2592000,\"endpoints\":[{\"url\":\"https://csp.withgoogle.com/csp/report-to/devrel-devsite\"}]}|content-type: text/css|access-control-allow-origin: *|cache-control: public, max-age=31536000|accept-ranges: bytes|expires: Tue, 29 Apr 2025 10:56:02 GMT]\n13;s-7737;557 ms;557 ms;561 ms;561 ms;4 ms;0.4 ms;0.2 ms;200;text/css;VeryHigh;VeryHigh;VeryHigh;t;unknown;t;0;[];[content-security-policy: base-uri 'self'; object-src 'none'; script-src 'strict-dynamic' 'unsafe-inline' https: http: 'nonce-laTwEoovJjOKcMoBUjSFaYO6rrF8dU' 'unsafe-eval'; report-uri https://csp.withgoogle.com/csp/devsite/v2|content-encoding: gzip|x-content-type-options: nosniff|date: Mon, 29 Apr 2024 11:00:18 GMT|strict-transport-security: max-age=63072000; includeSubdomains; preload|alt-svc: h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000|content-length: <redacted>|x-xss-protection: 0|pragma: no-cache|last-modified: Tue, 19 Mar 2024 18:37:07 GMT|server: Google Frontend|vary: Cookie, Accept-Encoding|x-frame-options: SAMEORIGIN|content-type: text/css|x-cloud-trace-context: <redacted>|cache-control: no-cache, must-revalidate|expires: 0]\n\n# Main thread bottom-up summary\n\nThis is the bottom-up summary for the entire trace. Only the top 10 activities (sorted by self time) are shown. An activity is all the aggregated time spent on the same type of work. For example, it can be all the time spent in a specific JavaScript function, or all the time spent in a specific browser rendering stage (like layout, v8 compile, parsing html). \"Self time\" represents the aggregated time spent directly in an activity, across all occurrences. \"Total time\" represents the aggregated time spent in an activity or any of its children.\n\n## insight set id: NO_NAVIGATION\n\n- self: 12 ms, total: 12 ms, source: Profiling overhead\n- self: 4 ms, total: 28 ms, source: Task\n- self: 3 ms, total: 4 ms, source: Recalculate style (url: https://www.gstatic.com/devrel-devsite/prod/vafe2e13ca17bb026e70df42a2ead1c8192750e86a12923a88eda839025dabf95/js/devsite_app_module.js, line: 98, column: 12)\n- self: 2 ms, total: 2 ms, source: Commit\n- self: 0.9 ms, total: 2 ms, source: Function call (url: https://www.gstatic.com/devrel-devsite/prod/vafe2e13ca17bb026e70df42a2ead1c8192750e86a12923a88eda839025dabf95/js/devsite_app_module.js, line: 102, column: 35)\n- self: 0.8 ms, total: 13 ms, source: Evaluate script\n- self: 0.7 ms, total: 3 ms, source: Event: pointerover\n- self: 0.1 ms, total: 1 ms, source: Xh (url: https://www.gstatic.com/devrel-devsite/prod/vafe2e13ca17bb026e70df42a2ead1c8192750e86a12923a88eda839025dabf95/js/devsite_app_module.js, line: 104, column: 61)\n\n## insight set id: NAVIGATION_1\n\n- self: 46 ms, total: 49 ms, source: Recalculate style\n- self: 37 ms, total: 211 ms, source: Task\n- self: 21 ms, total: 22 ms, source: Layout\n- self: 17 ms, total: 19 ms, source: Compile code\n- self: 7 ms, total: 7 ms, source: Cache script code\n- self: 6 ms, total: 26 ms, source: Function call (url: https://www.gstatic.com/devrel-devsite/prod/vafe2e13ca17bb026e70df42a2ead1c8192750e86a12923a88eda839025dabf95/js/devsite_app_module.js, line: 288, column: 146)\n- self: 5 ms, total: 5 ms, source: Parse stylesheet\n- self: 5 ms, total: 5 ms, source: Pre-paint\n- self: 5 ms, total: 5 ms, source: Commit\n- self: 5 ms, total: 10 ms, source: appendChild\n\n# 3rd party summary\n\n## insight set id: NO_NAVIGATION\n\n- name: Google CDN, main thread time: 1 ms, network transfer size: 0 B\n\n## insight set id: NAVIGATION_1\n\n- name: Google CDN, main thread time: 38 ms, network transfer size: 990 B\n- name: web.dev, main thread time: 3 ms, network transfer size: 84.3 kB\n- name: Google Analytics, main thread time: 0.6 ms, network transfer size: 52.9 kB\n- name: Google Fonts, main thread time: 0 ms, network transfer size: 42.2 kB\n\n# Longest tasks\n\n## insight set id: NO_NAVIGATION\n\n- total time: 13 ms, event: (eventKey: r-96, ts: 465455241964)\n- total time: 2 ms, event: (eventKey: r-934, ts: 465455475572)\n- total time: 1 ms, event: (eventKey: r-2310, ts: 465455879141)\n\n## insight set id: NAVIGATION_1\n\n- total time: 18 ms, event: (eventKey: r-20182, ts: 465457150438)\n- total time: 14 ms, event: (eventKey: r-12184, ts: 465457104625)\n- total time: 12 ms, event: (eventKey: r-10779, ts: 465457087373)\n\nUser selected the following call tree:\n\n\n\n# Call tree:\n\n1;r-10779;Task;3;;;2;;\n2;r-11902;Layout;3;3;;;;;S\n\n\n# User query\n\ntest"
10
10
  }
11
11
  ],
12
12
  "widgets": [
@@ -14,8 +14,8 @@ import {bytes, millis} from './UnitFormatters.js';
14
14
  /**
15
15
  * For a given frame ID and navigation ID, returns the LCP Event and the LCP Request, if the resource was an image.
16
16
  */
17
- function getLCPData(
18
- parsedTrace: Trace.TraceModel.ParsedTrace, frameId: string, navigation: Trace.Types.Events.NavigationStart): {
17
+ function getLCPData(parsedTrace: Trace.TraceModel.ParsedTrace, frameId: string,
18
+ navigation: Trace.Types.Events.NavigationStart|Trace.Types.Events.SoftNavigationStart): {
19
19
  lcpEvent: Trace.Types.Events.LargestContentfulPaintCandidate,
20
20
  metricScore: Trace.Handlers.ModelHandlers.PageLoadMetrics.LCPMetricScore,
21
21
  lcpRequest?: Trace.Types.Events.SyntheticNetworkRequest,
@@ -34,7 +34,8 @@ function getLCPData(
34
34
  return null;
35
35
  }
36
36
 
37
- const navigationId = navigation.args.data?.navigationId;
37
+ const navigationId =
38
+ Trace.Types.Events.isSoftNavigationStart(navigation) ? undefined : navigation.args.data?.navigationId;
38
39
 
39
40
  return {
40
41
  lcpEvent,
@@ -574,7 +574,7 @@ The following is a list of insight sets. An insight set covers a specific part o
574
574
  ## insight set id: NAVIGATION_0
575
575
 
576
576
  URL: http://localhost:8080/render-blocking
577
- Bounds: {min: 171607579779µs, max: 171613750571µs}
577
+ Bounds: {min: 171607579779µs, max: 171613750570µs}
578
578
  Metrics (lab / observed):
579
579
  - LCP: 1317 ms, event: (eventKey: r-6686, ts: 171608897210), nodeId: 10
580
580
  - LCP breakdown:
@@ -193,7 +193,7 @@ export class CompilerScriptMapping implements DebuggerSourceMapping {
193
193
  return null;
194
194
  }
195
195
 
196
- const entry = sourceMap.findEntry(lineNumber, columnNumber, rawLocation.inlineFrameIndex);
196
+ const entry = sourceMap.findEntry(lineNumber, columnNumber);
197
197
  if (!entry?.sourceURL) {
198
198
  return null;
199
199
  }
@@ -104,6 +104,7 @@ export class DeviceModeModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
104
104
  #availableSize: Geometry.Size;
105
105
  #preferredSize: Geometry.Size;
106
106
  #initialized: boolean;
107
+ #autoFitScaleOnInitialize: boolean;
107
108
  #appliedDeviceSize: Geometry.Size;
108
109
  #appliedDeviceScaleFactor: number;
109
110
  #appliedUserAgentType: UA;
@@ -113,7 +114,7 @@ export class DeviceModeModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
113
114
  #heightSetting: Common.Settings.Setting<number>;
114
115
  #uaSetting: Common.Settings.Setting<UA>;
115
116
  readonly #deviceScaleFactorSetting: Common.Settings.Setting<number>;
116
- readonly #deviceOutlineSetting: Common.Settings.Setting<boolean>;
117
+
117
118
  readonly #toolbarControlsEnabledSetting: Common.Settings.Setting<boolean>;
118
119
  #type: Type;
119
120
  #device: EmulatedDevice|null;
@@ -143,6 +144,7 @@ export class DeviceModeModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
143
144
  this.#availableSize = new Geometry.Size(1, 1);
144
145
  this.#preferredSize = new Geometry.Size(1, 1);
145
146
  this.#initialized = false;
147
+ this.#autoFitScaleOnInitialize = false;
146
148
  this.#appliedDeviceSize = new Geometry.Size(1, 1);
147
149
  this.#appliedDeviceScaleFactor = globalThis.devicePixelRatio;
148
150
  this.#appliedUserAgentType = UA.DESKTOP;
@@ -178,9 +180,6 @@ export class DeviceModeModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
178
180
  this.#deviceScaleFactorSetting = this.#settings.createSetting('emulation.device-scale-factor', 0);
179
181
  this.#deviceScaleFactorSetting.addChangeListener(this.deviceScaleFactorSettingChanged, this);
180
182
 
181
- this.#deviceOutlineSetting = this.#settings.moduleSetting('emulation.show-device-outline');
182
- this.#deviceOutlineSetting.addChangeListener(this.deviceOutlineSettingChanged, this);
183
-
184
183
  this.#toolbarControlsEnabledSetting = this.#settings.createSetting('emulation.toolbar-controls-enabled', true,
185
184
  Common.Settings.SettingStorageType.SESSION);
186
185
 
@@ -311,10 +310,22 @@ export class DeviceModeModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
311
310
  return this.#scaleSetting;
312
311
  }
313
312
 
313
+ #updateFitScale(): void {
314
+ if (this.#type === Type.Device && this.#device && this.#mode) {
315
+ const orientation = this.#device.orientationByName(this.#mode.orientation);
316
+ this.#scaleSetting.set(
317
+ this.calculateFitScale(orientation.width, orientation.height, this.currentOutline(), this.currentInsets()));
318
+ }
319
+ }
320
+
314
321
  setAvailableSize(availableSize: Geometry.Size, preferredSize: Geometry.Size): void {
315
322
  this.#availableSize = availableSize;
316
323
  this.#preferredSize = preferredSize;
317
324
  this.#initialized = true;
325
+ if (this.#autoFitScaleOnInitialize) {
326
+ this.#autoFitScaleOnInitialize = false;
327
+ this.#updateFitScale();
328
+ }
318
329
  this.calculateAndEmulate(false);
319
330
  }
320
331
 
@@ -326,15 +337,19 @@ export class DeviceModeModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
326
337
  console.assert(Boolean(device) && Boolean(mode), 'Must pass device and mode for device emulation');
327
338
  this.#mode = mode;
328
339
  this.#device = device;
329
- if (this.#initialized) {
330
- const orientation = device.orientationByName(mode.orientation);
331
- this.#scaleSetting.set(
332
- scale ||
333
- this.calculateFitScale(orientation.width, orientation.height, this.currentOutline(), this.currentInsets()));
340
+ if (scale !== undefined) {
341
+ this.#autoFitScaleOnInitialize = false;
342
+ this.#scaleSetting.set(scale);
343
+ } else if (this.#initialized) {
344
+ this.#autoFitScaleOnInitialize = false;
345
+ this.#updateFitScale();
346
+ } else {
347
+ this.#autoFitScaleOnInitialize = true;
334
348
  }
335
349
  } else {
336
350
  this.#device = null;
337
351
  this.#mode = null;
352
+ this.#autoFitScaleOnInitialize = false;
338
353
  }
339
354
 
340
355
  if (type !== Type.None) {
@@ -390,11 +405,6 @@ export class DeviceModeModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
390
405
  return (this.#device && this.#mode) ? this.#device.modeImage(this.#mode) : '';
391
406
  }
392
407
 
393
- outlineImage(): string {
394
- return (this.#device && this.#mode && this.#deviceOutlineSetting.get()) ? this.#device.outlineImage(this.#mode) :
395
- '';
396
- }
397
-
398
408
  canShowDeviceFrame(): boolean {
399
409
  return Boolean(this.#device && this.#mode && this.#device.outlineImage(this.#mode));
400
410
  }
@@ -471,10 +481,6 @@ export class DeviceModeModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
471
481
  return this.#deviceScaleFactorSetting;
472
482
  }
473
483
 
474
- deviceOutlineSetting(): Common.Settings.Setting<boolean> {
475
- return this.#deviceOutlineSetting;
476
- }
477
-
478
484
  toolbarControlsEnabledSetting(): Common.Settings.Setting<boolean> {
479
485
  return this.#toolbarControlsEnabledSetting;
480
486
  }
@@ -590,10 +596,6 @@ export class DeviceModeModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
590
596
  this.calculateAndEmulate(false);
591
597
  }
592
598
 
593
- private deviceOutlineSettingChanged(): void {
594
- this.calculateAndEmulate(false);
595
- }
596
-
597
599
  private preferredScaledWidth(): number {
598
600
  return Math.floor(this.#preferredSize.width / (this.#scaleSetting.get() || 1));
599
601
  }
@@ -603,15 +605,7 @@ export class DeviceModeModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
603
605
  }
604
606
 
605
607
  private currentOutline(): Insets {
606
- let outline: Insets = new Insets(0, 0, 0, 0);
607
- if (this.#type !== Type.Device || !this.#device || !this.#mode) {
608
- return outline;
609
- }
610
- const orientation = this.#device.orientationByName(this.#mode.orientation);
611
- if (this.#deviceOutlineSetting.get()) {
612
- outline = orientation.outlineInsets || outline;
613
- }
614
- return outline;
608
+ return new Insets(0, 0, 0, 0);
615
609
  }
616
610
 
617
611
  private currentInsets(): Insets {
@@ -924,9 +918,6 @@ export class DeviceModeModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
924
918
  }
925
919
  ctx.imageSmoothingEnabled = false;
926
920
 
927
- if (this.outlineImage()) {
928
- await this.paintImage(ctx, this.outlineImage(), outlineRect.relativeTo(outlineRect));
929
- }
930
921
  if (this.screenImage()) {
931
922
  await this.paintImage(ctx, this.screenImage(), screenRect.relativeTo(outlineRect));
932
923
  }
@@ -1803,7 +1803,7 @@ const emulatedDevices = [
1803
1803
  {
1804
1804
  'order': 42,
1805
1805
  'show-by-default': true,
1806
- 'title': 'iPad Pro 13"',
1806
+ 'title': 'iPad Pro 13',
1807
1807
  'screen': {
1808
1808
  'horizontal': {
1809
1809
  'width': 1376,
@@ -7810,6 +7810,10 @@ export const NativeFunctions = [
7810
7810
  name: "MediaStreamTrackEvent",
7811
7811
  signatures: [["type","eventInitDict"]]
7812
7812
  },
7813
+ {
7814
+ name: "setConstraints",
7815
+ signatures: [["?constraints"]]
7816
+ },
7813
7817
  {
7814
7818
  name: "webkitGetUserMedia",
7815
7819
  signatures: [["constraints","successCallback","errorCallback"]]
@@ -7818,10 +7822,6 @@ export const NativeFunctions = [
7818
7822
  name: "OverconstrainedError",
7819
7823
  signatures: [["constraint","?message"]]
7820
7824
  },
7821
- {
7822
- name: "setConstraints",
7823
- signatures: [["?constraints"]]
7824
- },
7825
7825
  {
7826
7826
  name: "appendEncodedChunks",
7827
7827
  signatures: [["chunks"]]
@@ -51,6 +51,11 @@ export class Model extends EventTarget {
51
51
  this.#processor = new TraceProcessor(handlers, this.#config);
52
52
  }
53
53
 
54
+ updateConfiguration(config: Types.Configuration.Configuration): void {
55
+ this.#config = config;
56
+ this.#processor.updateConfiguration(config);
57
+ }
58
+
54
59
  /**
55
60
  * Parses an array of trace events into a structured object containing all the
56
61
  * information parsed by the trace handlers.
@@ -94,6 +94,11 @@ export class TraceProcessor extends EventTarget {
94
94
  }
95
95
  }
96
96
 
97
+ updateConfiguration(config: Types.Configuration.Configuration): void {
98
+ this.#modelConfiguration = config;
99
+ this.#passConfigToHandlers();
100
+ }
101
+
97
102
  /**
98
103
  * When the user passes in a set of handlers, we want to ensure that we have all
99
104
  * the required handlers. Handlers can depend on other handlers, so if the user
@@ -440,7 +445,12 @@ export class TraceProcessor extends EventTarget {
440
445
  let id, urlString, navigation;
441
446
  if (context.navigation) {
442
447
  id = `NAVIGATION_${this.#insights.size}`;
443
- urlString = data.Meta.finalDisplayUrlByNavigationId.get(context.navigationId) ?? data.Meta.mainFrameURL;
448
+ if (Types.Events.isSoftNavigationStart(context.navigation)) {
449
+ urlString = context.navigation.args.context.URL;
450
+ } else {
451
+ urlString = data.Meta.finalDisplayUrlByNavigationId.get(context.navigation.args.data?.navigationId ?? '') ??
452
+ data.Meta.mainFrameURL;
453
+ }
444
454
  navigation = context.navigation;
445
455
  } else {
446
456
  id = Types.Events.NO_NAVIGATION;
@@ -523,17 +533,28 @@ export class TraceProcessor extends EventTarget {
523
533
 
524
534
  // Filter main frame navigations to those that have the necessary data (frameId and navigationId).
525
535
  // TODO(cjamcl): Does this filtering makes the "use the next nav as the end time" logic potentially broken? Are navs without nav id or frame even real?
526
- const navigations = data.Meta.mainFrameNavigations.filter(
527
- navigation => navigation.args.frame && navigation.args.data?.navigationId);
536
+ const hardNavigations = data.Meta.mainFrameNavigations.filter(navigation => navigation.args.frame &&
537
+ navigation.args.data?.navigationId);
538
+
539
+ const softNavigations =
540
+ this.#modelConfiguration.enableSoftNavigation ? Array.from(data.Meta.softNavigationsById.values()) : [];
541
+ const navigations = [...hardNavigations, ...softNavigations].sort((a, b) => a.ts - b.ts);
528
542
 
529
543
  this.#computeInsightsForInitialTracePeriod(data, navigations, options);
530
544
 
531
545
  for (const [index, navigation] of navigations.entries()) {
532
546
  const min = navigation.ts;
533
- // Use trace end for the last navigation, otherwise use the start of the next navigation.
534
- const max = index + 1 < navigations.length ? navigations[index + 1].ts : data.Meta.traceBounds.max;
547
+ // Use trace end for the last navigation, otherwise use the start of the next navigation (minus 1 to avoid overlap).
548
+ let max = index + 1 < navigations.length ? navigations[index + 1].ts : data.Meta.traceBounds.max;
549
+ if (index + 1 < navigations.length) {
550
+ max = Types.Timing.Micro(max - 1);
551
+ }
535
552
  const bounds = Helpers.Timing.traceWindowFromMicroSeconds(min, max);
536
- this.#computeInsightsForNavigation(navigation, bounds, data, traceEvents, options);
553
+ if (Types.Events.isSoftNavigationStart(navigation)) {
554
+ this.#computeInsightsForSoftNavigation(navigation, bounds, data, options);
555
+ } else {
556
+ this.#computeInsightsForNavigation(navigation, bounds, data, traceEvents, options);
557
+ }
537
558
  }
538
559
  }
539
560
 
@@ -541,12 +562,13 @@ export class TraceProcessor extends EventTarget {
541
562
  * Computes insights for the period before the first navigation, or for the entire trace if no navigations exist.
542
563
  */
543
564
  #computeInsightsForInitialTracePeriod(
544
- data: Handlers.Types.HandlerData, navigations: readonly Types.Events.NavigationStart[],
565
+ data: Handlers.Types.HandlerData,
566
+ navigations: ReadonlyArray<Types.Events.NavigationStart|Types.Events.SoftNavigationStart>,
545
567
  options: Types.Configuration.ParseOptions): void {
546
568
  // Determine bounds: Use the period before the first navigation if navigations exist, otherwise use the entire trace bounds.
547
- const bounds = navigations.length > 0 ?
548
- Helpers.Timing.traceWindowFromMicroSeconds(data.Meta.traceBounds.min, navigations[0].ts) :
549
- data.Meta.traceBounds;
569
+ const bounds = navigations.length > 0 ? Helpers.Timing.traceWindowFromMicroSeconds(
570
+ data.Meta.traceBounds.min, Types.Timing.Micro(navigations[0].ts - 1)) :
571
+ data.Meta.traceBounds;
550
572
 
551
573
  const context: Insights.Types.InsightSetContext = {
552
574
  options,
@@ -609,6 +631,21 @@ export class TraceProcessor extends EventTarget {
609
631
  };
610
632
  this.#computeInsightSet(data, context);
611
633
  }
634
+
635
+ /**
636
+ * Computes insights for a specific soft navigation event.
637
+ */
638
+ #computeInsightsForSoftNavigation(navigation: Types.Events.SoftNavigationStart, bounds: Types.Timing.TraceWindowMicro,
639
+ data: Handlers.Types.HandlerData, options: Types.Configuration.ParseOptions): void {
640
+ const frameId = navigation.args.frame;
641
+ const context: Insights.Types.InsightSetContextWithSoftNavigation = {
642
+ options,
643
+ bounds,
644
+ frameId,
645
+ navigation,
646
+ };
647
+ this.#computeInsightSet(data, context);
648
+ }
612
649
  }
613
650
 
614
651
  /**
@@ -39,7 +39,6 @@ import type {HandlerName} from './types.js';
39
39
 
40
40
  interface LayoutShiftsData {
41
41
  clusters: readonly Types.Events.SyntheticLayoutShiftCluster[];
42
- clustersByNavigationId: Map<Types.Events.NavigationId, Types.Events.SyntheticLayoutShiftCluster[]>;
43
42
  sessionMaxScore: number;
44
43
  // The session window which contains the SessionMaxScore
45
44
  clsWindowID: number;
@@ -110,7 +109,6 @@ let sessionMaxScore = 0;
110
109
  let clsWindowID = -1;
111
110
 
112
111
  let clusters: Types.Events.SyntheticLayoutShiftCluster[] = [];
113
- let clustersByNavigationId = new Map<Types.Events.NavigationId, Types.Events.SyntheticLayoutShiftCluster[]>();
114
112
 
115
113
  /**
116
114
  * Represents a point in time in which a LS score change
@@ -141,7 +139,11 @@ export function reset(): void {
141
139
  sessionMaxScore = 0;
142
140
  scoreRecords = [];
143
141
  clsWindowID = -1;
144
- clustersByNavigationId = new Map();
142
+ }
143
+
144
+ let enableSoftNavigation = true;
145
+ export function handleUserConfig(userConfig: Types.Configuration.Configuration): void {
146
+ enableSoftNavigation = userConfig.enableSoftNavigation;
145
147
  }
146
148
 
147
149
  export function handleEvent(event: Types.Events.Event): void {
@@ -292,8 +294,10 @@ export async function finalize(): Promise<void> {
292
294
  }
293
295
 
294
296
  async function buildLayoutShiftsClusters(): Promise<void> {
295
- const {navigationsByFrameId, mainFrameId, traceBounds} = metaHandlerData();
296
- const navigations = navigationsByFrameId.get(mainFrameId) || [];
297
+ const {navigationsByFrameId, mainFrameId, traceBounds, softNavigationsById} = metaHandlerData();
298
+ const softNavigations = enableSoftNavigation ? Array.from(softNavigationsById.values()) : [];
299
+ const navigations: Types.Events.Event[] =
300
+ [...(navigationsByFrameId.get(mainFrameId) || []), ...softNavigations].sort((a, b) => a.ts - b.ts);
297
301
  if (layoutShiftEvents.length === 0) {
298
302
  return;
299
303
  }
@@ -348,13 +352,15 @@ async function buildLayoutShiftsClusters(): Promise<void> {
348
352
  // If this cluster happened after a navigation, set the navigationId to
349
353
  // the current navigation. This lets us easily group clusters by
350
354
  // navigation.
351
- const navigationId = currentShiftNavigation === null ?
352
- Types.Events.NO_NAVIGATION :
353
- navigations[currentShiftNavigation].args.data?.navigationId;
354
- // TODO: `navigationId` is `string | undefined`, but the undefined portion
355
- // comes from `data.navigationId`. I don't think that is possible for this
356
- // event type. Can we make this typing stronger? In the meantime, we allow
357
- // `navigationId` to include undefined values.
355
+ let navigationId: string|undefined = undefined;
356
+ if (currentShiftNavigation !== null) {
357
+ const nav = navigations[currentShiftNavigation];
358
+ if (Types.Events.isNavigationStart(nav)) {
359
+ navigationId = nav.args.data?.navigationId;
360
+ }
361
+ } else {
362
+ navigationId = Types.Events.NO_NAVIGATION;
363
+ }
358
364
 
359
365
  clusters.push(Helpers.SyntheticEvents.SyntheticEventsManager
360
366
  .registerSyntheticEvent<Types.Events.SyntheticLayoutShiftCluster>({
@@ -519,12 +525,6 @@ async function buildLayoutShiftsClusters(): Promise<void> {
519
525
  sessionMaxScore = weightedScore;
520
526
  }
521
527
 
522
- if (cluster.navigationId) {
523
- const clustersForId = Platform.MapUtilities.getWithDefault(clustersByNavigationId, cluster.navigationId, () => {
524
- return [];
525
- });
526
- clustersForId.push(cluster);
527
- }
528
528
  }
529
529
  }
530
530
 
@@ -543,7 +543,6 @@ export function data(): LayoutShiftsData {
543
543
  remoteFonts,
544
544
  scoreRecords,
545
545
  backendNodeIds,
546
- clustersByNavigationId,
547
546
  paintImageEvents,
548
547
  };
549
548
  }