chrome-devtools-frontend 1.0.1558690 → 1.0.1561080

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 (167) hide show
  1. package/front_end/Images/src/container.svg +4 -0
  2. package/front_end/core/common/Gzip.ts +15 -0
  3. package/front_end/core/host/InspectorFrontendHostStub.ts +0 -3
  4. package/front_end/core/platform/ArrayUtilities.ts +13 -0
  5. package/front_end/core/root/Runtime.ts +0 -5
  6. package/front_end/core/sdk/CSSMetadata.ts +6 -6
  7. package/front_end/core/sdk/CSSModel.ts +2 -2
  8. package/front_end/core/sdk/DOMModel.ts +15 -3
  9. package/front_end/core/sdk/NetworkManager.ts +4 -0
  10. package/front_end/core/sdk/NetworkRequest.ts +9 -0
  11. package/front_end/core/sdk/OverlayModel.ts +20 -9
  12. package/front_end/entrypoints/main/MainImpl.ts +2 -1
  13. package/front_end/generated/InspectorBackendCommands.ts +6 -3
  14. package/front_end/generated/SupportedCSSProperties.js +64 -32
  15. package/front_end/generated/protocol-mapping.d.ts +16 -0
  16. package/front_end/generated/protocol-proxy-api.d.ts +12 -0
  17. package/front_end/generated/protocol.ts +38 -1
  18. package/front_end/models/ai_assistance/agents/StylingAgent.ts +1 -1
  19. package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +11 -7
  20. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +23 -22
  21. package/front_end/models/badges/UserBadges.ts +48 -16
  22. package/front_end/models/greendev/Prototypes.ts +6 -1
  23. package/front_end/models/trace/LanternComputationData.ts +4 -3
  24. package/front_end/models/trace/Processor.ts +6 -5
  25. package/front_end/models/trace/Styles.ts +10 -1
  26. package/front_end/models/trace/extras/TraceTree.ts +1 -1
  27. package/front_end/models/trace/handlers/LargestImagePaintHandler.ts +2 -2
  28. package/front_end/models/trace/handlers/MetaHandler.ts +14 -0
  29. package/front_end/models/trace/handlers/PageLoadMetricsHandler.ts +59 -34
  30. package/front_end/models/trace/helpers/Timing.ts +8 -1
  31. package/front_end/models/trace/insights/Common.ts +1 -1
  32. package/front_end/models/trace/insights/LCPBreakdown.ts +4 -4
  33. package/front_end/models/trace/insights/LCPDiscovery.ts +3 -3
  34. package/front_end/models/trace/insights/RenderBlocking.ts +1 -1
  35. package/front_end/models/trace/insights/types.ts +1 -1
  36. package/front_end/models/trace/types/TraceEvents.ts +62 -10
  37. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +11 -142
  38. package/front_end/panels/ai_assistance/PatchWidget.ts +90 -72
  39. package/front_end/panels/ai_assistance/ai_assistance.ts +1 -0
  40. package/front_end/panels/ai_assistance/components/ChatInput.ts +701 -0
  41. package/front_end/panels/ai_assistance/components/ChatView.ts +71 -1268
  42. package/front_end/panels/ai_assistance/components/UserActionRow.ts +514 -31
  43. package/front_end/panels/ai_assistance/components/chatInput.css +387 -0
  44. package/front_end/panels/ai_assistance/components/chatView.css +38 -599
  45. package/front_end/panels/ai_assistance/components/userActionRow.css +230 -0
  46. package/front_end/panels/autofill/AutofillView.ts +2 -2
  47. package/front_end/panels/changes/ChangesView.ts +15 -1
  48. package/front_end/panels/changes/changesView.css +6 -0
  49. package/front_end/panels/common/AiCodeGenerationTeaser.ts +48 -12
  50. package/front_end/panels/common/BadgeNotification.ts +44 -58
  51. package/front_end/panels/common/CopyChangesToPrompt.ts +233 -0
  52. package/front_end/panels/common/aiCodeGenerationTeaser.css +14 -0
  53. package/front_end/panels/common/common.ts +2 -1
  54. package/front_end/panels/console/consoleView.css +1 -1
  55. package/front_end/panels/elements/CSSRuleValidator.ts +38 -0
  56. package/front_end/panels/elements/ElementsTreeElement.ts +222 -377
  57. package/front_end/panels/elements/ElementsTreeOutline.ts +0 -23
  58. package/front_end/panels/elements/ShortcutTreeElement.ts +57 -50
  59. package/front_end/panels/elements/StylePropertiesSection.ts +1 -3
  60. package/front_end/panels/elements/StylesSidebarPane.ts +15 -4
  61. package/front_end/panels/elements/components/AdornerManager.ts +5 -149
  62. package/front_end/panels/issues/HiddenIssuesRow.ts +1 -2
  63. package/front_end/panels/issues/IssueKindView.ts +2 -4
  64. package/front_end/panels/issues/IssueView.ts +2 -4
  65. package/front_end/panels/network/NetworkDataGridNode.ts +65 -1
  66. package/front_end/panels/network/NetworkLogView.ts +2 -4
  67. package/front_end/panels/network/NetworkLogViewColumns.ts +9 -0
  68. package/front_end/panels/screencast/ScreencastApp.ts +1 -0
  69. package/front_end/panels/settings/SettingsScreen.ts +3 -2
  70. package/front_end/panels/timeline/CompatibilityTracksAppender.ts +14 -1
  71. package/front_end/panels/timeline/StatusDialog.ts +4 -3
  72. package/front_end/panels/timeline/ThirdPartyTreeView.ts +1 -4
  73. package/front_end/panels/timeline/TimelineController.ts +185 -3
  74. package/front_end/panels/timeline/TimelineFlameChartDataProvider.ts +52 -25
  75. package/front_end/panels/timeline/TimelineFlameChartNetworkDataProvider.ts +3 -16
  76. package/front_end/panels/timeline/TimelineFlameChartView.ts +65 -21
  77. package/front_end/panels/timeline/TimelinePanel.ts +86 -126
  78. package/front_end/panels/timeline/TimelineTreeView.ts +1 -0
  79. package/front_end/panels/timeline/TimelineUIUtils.ts +28 -2
  80. package/front_end/panels/timeline/TimingsTrackAppender.ts +3 -1
  81. package/front_end/panels/timeline/components/SidebarSingleInsightSet.ts +1 -1
  82. package/front_end/panels/timeline/components/insights/BaseInsightComponent.ts +2 -2
  83. package/front_end/panels/timeline/components/insights/RenderBlocking.ts +6 -4
  84. package/front_end/panels/timeline/components/insights/Table.ts +3 -3
  85. package/front_end/panels/timeline/overlays/OverlaysImpl.ts +4 -0
  86. package/front_end/panels/timeline/timelinePanel.css +8 -1
  87. package/front_end/panels/timeline/utils/EntryNodes.ts +2 -1
  88. package/front_end/panels/whats_new/ReleaseNoteText.ts +15 -9
  89. package/front_end/panels/whats_new/resources/WNDT.md +6 -6
  90. package/front_end/third_party/chromium/README.chromium +1 -1
  91. package/front_end/third_party/codemirror.next/rebuild.sh +1 -1
  92. package/front_end/third_party/lit/rebuild.sh +1 -1
  93. package/front_end/third_party/puppeteer/README.chromium +2 -2
  94. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.d.ts +2 -3
  95. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.d.ts.map +1 -1
  96. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.js.map +1 -1
  97. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/HTTPRequest.d.ts.map +1 -1
  98. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/HTTPRequest.js +9 -0
  99. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/HTTPRequest.js.map +1 -1
  100. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/HTTPResponse.d.ts +3 -0
  101. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/HTTPResponse.d.ts.map +1 -1
  102. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/HTTPResponse.js +9 -0
  103. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/HTTPResponse.js.map +1 -1
  104. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Request.d.ts +3 -0
  105. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Request.d.ts.map +1 -1
  106. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Request.js +10 -0
  107. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Request.js.map +1 -1
  108. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.d.ts.map +1 -1
  109. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.js +8 -4
  110. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.js.map +1 -1
  111. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/injected.d.ts +1 -1
  112. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/injected.d.ts.map +1 -1
  113. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/injected.js +1 -1
  114. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/injected.js.map +1 -1
  115. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/injected/injected.d.ts +1 -1
  116. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.d.ts +3 -3
  117. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js +3 -3
  118. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js.map +1 -1
  119. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Mutex.d.ts +2 -2
  120. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.d.ts +1 -1
  121. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.js +1 -1
  122. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.d.ts +10 -1
  123. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +13 -7
  124. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.d.ts +2 -3
  125. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.d.ts.map +1 -1
  126. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.js.map +1 -1
  127. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/HTTPRequest.d.ts.map +1 -1
  128. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/HTTPRequest.js +9 -0
  129. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/HTTPRequest.js.map +1 -1
  130. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/HTTPResponse.d.ts +3 -0
  131. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/HTTPResponse.d.ts.map +1 -1
  132. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/HTTPResponse.js +9 -0
  133. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/HTTPResponse.js.map +1 -1
  134. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/Request.d.ts +3 -0
  135. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/Request.d.ts.map +1 -1
  136. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/Request.js +10 -0
  137. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/Request.js.map +1 -1
  138. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.d.ts.map +1 -1
  139. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.js +8 -4
  140. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.js.map +1 -1
  141. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/injected.d.ts +1 -1
  142. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/injected.d.ts.map +1 -1
  143. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/injected.js +1 -1
  144. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/injected.js.map +1 -1
  145. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.d.ts +3 -3
  146. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js +3 -3
  147. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js.map +1 -1
  148. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.d.ts +1 -1
  149. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.js +1 -1
  150. package/front_end/third_party/puppeteer/package/lib/types.d.ts +10 -1
  151. package/front_end/third_party/puppeteer/package/package.json +3 -3
  152. package/front_end/third_party/puppeteer/package/src/api/Page.ts +2 -3
  153. package/front_end/third_party/puppeteer/package/src/bidi/HTTPRequest.ts +13 -0
  154. package/front_end/third_party/puppeteer/package/src/bidi/HTTPResponse.ts +10 -0
  155. package/front_end/third_party/puppeteer/package/src/bidi/core/Request.ts +15 -0
  156. package/front_end/third_party/puppeteer/package/src/cdp/Browser.ts +9 -4
  157. package/front_end/third_party/puppeteer/package/src/generated/injected.ts +1 -1
  158. package/front_end/third_party/puppeteer/package/src/revisions.ts +3 -3
  159. package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
  160. package/front_end/ui/components/adorners/Adorner.ts +8 -68
  161. package/front_end/ui/components/text_editor/AiCodeGenerationProvider.ts +70 -28
  162. package/front_end/ui/legacy/SearchableView.ts +11 -5
  163. package/front_end/ui/legacy/SplitWidget.ts +1 -1
  164. package/front_end/ui/legacy/TabbedPane.ts +1 -1
  165. package/front_end/ui/legacy/components/perf_ui/FlameChart.ts +43 -9
  166. package/front_end/ui/visual_logging/KnownContextValues.ts +16 -0
  167. package/package.json +2 -1
@@ -5,7 +5,9 @@
5
5
  /**
6
6
  * This handler stores page load metrics, including web vitals,
7
7
  * and exports them in the shape of a map with the following shape:
8
- * Map(FrameId -> Map(navigationID -> metrics) )
8
+ * Map(FrameId -> Map(navigation -> metrics) )
9
+ *
10
+ * Includes soft navigations.
9
11
  *
10
12
  * It also exports all markers in a trace in an array.
11
13
  *
@@ -22,14 +24,15 @@ import type {HandlerName} from './types.js';
22
24
 
23
25
  // Small helpers to make the below type easier to read.
24
26
  type FrameId = string;
25
- type NavigationId = string;
27
+ type AnyNavigationStart = Types.Events.NavigationStart|Types.Events.SoftNavigationStart;
28
+
26
29
  /**
27
30
  * This represents the metric scores for all navigations, for all frames in a trace.
28
31
  * Given a frame id, the map points to another map from navigation id to metric scores.
29
32
  * The metric scores include the event related to the metric as well as the data regarding
30
33
  * the score itself.
31
34
  */
32
- let metricScoresByFrameId = new Map<FrameId, Map<NavigationId, Map<MetricName, MetricScore>>>();
35
+ let metricScoresByFrameId = new Map<FrameId, Map<AnyNavigationStart, Map<MetricName, MetricScore>>>();
33
36
 
34
37
  /**
35
38
  * Page load events with no associated duration that happened in the
@@ -54,7 +57,7 @@ let pageLoadEventsArray: Types.Events.PageLoadEvent[] = [];
54
57
  // trace, we store that and delete the prior event. When we've parsed the
55
58
  // entire trace this set will contain all the LCP events that were used - e.g.
56
59
  // the candidates that were the actual LCP events.
57
- let selectedLCPCandidateEvents = new Set<Types.Events.LargestContentfulPaintCandidate>();
60
+ let selectedLCPCandidateEvents = new Set<Types.Events.AnyLargestContentfulPaintCandidate>();
58
61
 
59
62
  export function handleEvent(event: Types.Events.Event): void {
60
63
  if (!Types.Events.eventIsPageLoadEvent(event)) {
@@ -64,11 +67,7 @@ export function handleEvent(event: Types.Events.Event): void {
64
67
  }
65
68
 
66
69
  function storePageLoadMetricAgainstNavigationId(
67
- navigation: Types.Events.NavigationStart, event: Types.Events.PageLoadEvent): void {
68
- const navigationId = navigation.args.data?.navigationId;
69
- if (!navigationId) {
70
- throw new Error('Navigation event unexpectedly had no navigation ID.');
71
- }
70
+ navigation: AnyNavigationStart, event: Types.Events.PageLoadEvent): void {
72
71
  const frameId = getFrameIdForPageLoadEvent(event);
73
72
  const {rendererProcessesByFrame} = metaHandlerData();
74
73
 
@@ -95,7 +94,7 @@ function storePageLoadMetricAgainstNavigationId(
95
94
  const fcpTime = Types.Timing.Micro(event.ts - navigation.ts);
96
95
  const classification = scoreClassificationForFirstContentfulPaint(fcpTime);
97
96
  const metricScore = {event, metricName: MetricName.FCP, classification, navigation, timing: fcpTime};
98
- storeMetricScore(frameId, navigationId, metricScore);
97
+ storeMetricScore(frameId, navigation, metricScore);
99
98
  return;
100
99
  }
101
100
 
@@ -103,7 +102,7 @@ function storePageLoadMetricAgainstNavigationId(
103
102
  const paintTime = Types.Timing.Micro(event.ts - navigation.ts);
104
103
  const classification = ScoreClassification.UNCLASSIFIED;
105
104
  const metricScore = {event, metricName: MetricName.FP, classification, navigation, timing: paintTime};
106
- storeMetricScore(frameId, navigationId, metricScore);
105
+ storeMetricScore(frameId, navigation, metricScore);
107
106
  return;
108
107
  }
109
108
 
@@ -116,7 +115,7 @@ function storePageLoadMetricAgainstNavigationId(
116
115
  navigation,
117
116
  timing: dclTime,
118
117
  };
119
- storeMetricScore(frameId, navigationId, metricScore);
118
+ storeMetricScore(frameId, navigation, metricScore);
120
119
  return;
121
120
  }
122
121
 
@@ -129,7 +128,7 @@ function storePageLoadMetricAgainstNavigationId(
129
128
  navigation,
130
129
  timing: ttiValue,
131
130
  };
132
- storeMetricScore(frameId, navigationId, tti);
131
+ storeMetricScore(frameId, navigation, tti);
133
132
 
134
133
  const tbtValue = Helpers.Timing.milliToMicro(Types.Timing.Milli(event.args.args.total_blocking_time_ms));
135
134
  const tbt = {
@@ -139,7 +138,7 @@ function storePageLoadMetricAgainstNavigationId(
139
138
  navigation,
140
139
  timing: tbtValue,
141
140
  };
142
- storeMetricScore(frameId, navigationId, tbt);
141
+ storeMetricScore(frameId, navigation, tbt);
143
142
  return;
144
143
  }
145
144
 
@@ -152,11 +151,11 @@ function storePageLoadMetricAgainstNavigationId(
152
151
  navigation,
153
152
  timing: loadTime,
154
153
  };
155
- storeMetricScore(frameId, navigationId, metricScore);
154
+ storeMetricScore(frameId, navigation, metricScore);
156
155
  return;
157
156
  }
158
157
 
159
- if (Types.Events.isLargestContentfulPaintCandidate(event)) {
158
+ if (Types.Events.isAnyLargestContentfulPaintCandidate(event)) {
160
159
  const candidateIndex = event.args.data?.candidateIndex;
161
160
  if (!candidateIndex) {
162
161
  throw new Error('Largest Contentful Paint unexpectedly had no candidateIndex.');
@@ -170,16 +169,16 @@ function storePageLoadMetricAgainstNavigationId(
170
169
  timing: lcpTime,
171
170
  };
172
171
  const metricsByNavigation = Platform.MapUtilities.getWithDefault(metricScoresByFrameId, frameId, () => new Map());
173
- const metrics = Platform.MapUtilities.getWithDefault(metricsByNavigation, navigationId, () => new Map());
172
+ const metrics = Platform.MapUtilities.getWithDefault(metricsByNavigation, navigation, () => new Map());
174
173
  const lastLCPCandidate = metrics.get(MetricName.LCP);
175
174
  if (lastLCPCandidate === undefined) {
176
175
  selectedLCPCandidateEvents.add(lcp.event);
177
- storeMetricScore(frameId, navigationId, lcp);
176
+ storeMetricScore(frameId, navigation, lcp);
178
177
  return;
179
178
  }
180
179
  const lastLCPCandidateEvent = lastLCPCandidate.event;
181
180
 
182
- if (!Types.Events.isLargestContentfulPaintCandidate(lastLCPCandidateEvent)) {
181
+ if (!Types.Events.isAnyLargestContentfulPaintCandidate(lastLCPCandidateEvent)) {
183
182
  return;
184
183
  }
185
184
  const lastCandidateIndex = lastLCPCandidateEvent.args.data?.candidateIndex;
@@ -192,19 +191,22 @@ function storePageLoadMetricAgainstNavigationId(
192
191
  if (lastCandidateIndex < candidateIndex) {
193
192
  selectedLCPCandidateEvents.delete(lastLCPCandidateEvent);
194
193
  selectedLCPCandidateEvents.add(lcp.event);
195
- storeMetricScore(frameId, navigationId, lcp);
194
+ storeMetricScore(frameId, navigation, lcp);
196
195
  }
197
196
  return;
198
197
  }
199
198
  if (Types.Events.isLayoutShift(event)) {
200
199
  return;
201
200
  }
201
+ if (Types.Events.isSoftNavigationStart(event)) {
202
+ return;
203
+ }
202
204
  return Platform.assertNever(event, `Unexpected event type: ${event}`);
203
205
  }
204
206
 
205
- function storeMetricScore(frameId: string, navigationId: string, metricScore: MetricScore): void {
207
+ function storeMetricScore(frameId: string, navigation: AnyNavigationStart, metricScore: MetricScore): void {
206
208
  const metricsByNavigation = Platform.MapUtilities.getWithDefault(metricScoresByFrameId, frameId, () => new Map());
207
- const metrics = Platform.MapUtilities.getWithDefault(metricsByNavigation, navigationId, () => new Map());
209
+ const metrics = Platform.MapUtilities.getWithDefault(metricsByNavigation, navigation, () => new Map());
208
210
  // If an entry with that metric name is present, delete it so that the new entry that
209
211
  // will replace it is added at the end of the map. This way we guarantee the map entries
210
212
  // are ordered in ASC manner by timestamp.
@@ -214,8 +216,9 @@ function storeMetricScore(frameId: string, navigationId: string, metricScore: Me
214
216
 
215
217
  export function getFrameIdForPageLoadEvent(event: Types.Events.PageLoadEvent): string {
216
218
  if (Types.Events.isFirstContentfulPaint(event) || Types.Events.isInteractiveTime(event) ||
217
- Types.Events.isLargestContentfulPaintCandidate(event) || Types.Events.isNavigationStart(event) ||
218
- Types.Events.isLayoutShift(event) || Types.Events.isFirstPaint(event)) {
219
+ Types.Events.isAnyLargestContentfulPaintCandidate(event) || Types.Events.isNavigationStart(event) ||
220
+ Types.Events.isSoftNavigationStart(event) || Types.Events.isLayoutShift(event) ||
221
+ Types.Events.isFirstPaint(event)) {
219
222
  return event.args.frame;
220
223
  }
221
224
  if (Types.Events.isMarkDOMContent(event) || Types.Events.isMarkLoad(event)) {
@@ -228,15 +231,27 @@ export function getFrameIdForPageLoadEvent(event: Types.Events.PageLoadEvent): s
228
231
  Platform.assertNever(event, `Unexpected event type: ${event}`);
229
232
  }
230
233
 
231
- function getNavigationForPageLoadEvent(event: Types.Events.PageLoadEvent): Types.Events.NavigationStart|null {
232
- if (Types.Events.isFirstContentfulPaint(event) || Types.Events.isLargestContentfulPaintCandidate(event) ||
234
+ function getNavigationForPageLoadEvent(event: Types.Events.PageLoadEvent): AnyNavigationStart|null {
235
+ if (Types.Events.isFirstContentfulPaint(event) || Types.Events.isAnyLargestContentfulPaintCandidate(event) ||
233
236
  Types.Events.isFirstPaint(event)) {
234
- const navigationId = event.args.data?.navigationId;
235
- if (!navigationId) {
236
- throw new Error('Trace event unexpectedly had no navigation ID.');
237
+ const {navigationsByNavigationId, softNavigationsById} = metaHandlerData();
238
+
239
+ let navigation;
240
+ if (event.name === Types.Events.Name.MARK_LCP_CANDIDATE_FOR_SOFT_NAVIGATION &&
241
+ event.args.data?.performanceTimelineNavigationId) {
242
+ navigation = softNavigationsById.get(event.args.data.performanceTimelineNavigationId);
243
+ if (!navigation) {
244
+ // The most recent soft navigation must have been before the trace started.
245
+ return null;
246
+ }
247
+ } else {
248
+ const navigationId = event.args.data?.navigationId;
249
+ if (!navigationId) {
250
+ throw new Error(`Trace event unexpectedly had no navigation ID: ${JSON.stringify(event, null, 2)}`);
251
+ }
252
+
253
+ navigation = navigationsByNavigationId.get(navigationId);
237
254
  }
238
- const {navigationsByNavigationId} = metaHandlerData();
239
- const navigation = navigationsByNavigationId.get(navigationId);
240
255
 
241
256
  if (!navigation) {
242
257
  // This event's navigation has been filtered out by the meta handler as a noise event.
@@ -245,6 +260,11 @@ function getNavigationForPageLoadEvent(event: Types.Events.PageLoadEvent): Types
245
260
  return navigation;
246
261
  }
247
262
 
263
+ if (Types.Events.isSoftNavigationStart(event)) {
264
+ const {softNavigationsById} = metaHandlerData();
265
+ return softNavigationsById.get(event.args.context.performanceTimelineNavigationId) ?? null;
266
+ }
267
+
248
268
  if (Types.Events.isMarkDOMContent(event) || Types.Events.isInteractiveTime(event) ||
249
269
  Types.Events.isLayoutShift(event) || Types.Events.isMarkLoad(event)) {
250
270
  const frameId = getFrameIdForPageLoadEvent(event);
@@ -378,7 +398,8 @@ export async function finalize(): Promise<void> {
378
398
  const allFinalLCPEvents = gatherFinalLCPEvents();
379
399
  const mainFrame = metaHandlerData().mainFrameId;
380
400
  // Filter out LCP candidates to use only definitive LCP values
381
- const allEventsButLCP = pageLoadEventsArray.filter(event => !Types.Events.isLargestContentfulPaintCandidate(event));
401
+ const allEventsButLCP =
402
+ pageLoadEventsArray.filter(event => !Types.Events.isAnyLargestContentfulPaintCandidate(event));
382
403
  const markerEvents = [...allFinalLCPEvents, ...allEventsButLCP].filter(Types.Events.isMarkerEvent);
383
404
  // Filter by main frame and sort.
384
405
  allMarkerEvents =
@@ -391,8 +412,10 @@ export interface PageLoadMetricsData {
391
412
  * Given a frame id, the map points to another map from navigation id to metric scores.
392
413
  * The metric scores include the event related to the metric as well as the data regarding
393
414
  * the score itself.
415
+ *
416
+ * Includes soft navigations.
394
417
  */
395
- metricScoresByFrameId: Map<string, Map<string, Map<MetricName, MetricScore>>>;
418
+ metricScoresByFrameId: Map<string, Map<AnyNavigationStart, Map<MetricName, MetricScore>>>;
396
419
  /**
397
420
  * Page load events with no associated duration that happened in the
398
421
  * main frame.
@@ -437,6 +460,8 @@ export const enum MetricName {
437
460
  CLS = 'CLS',
438
461
  // Navigation
439
462
  NAV = 'Nav',
463
+ // Soft Navigation (just "Nav" b/c space is limited in flame chart)
464
+ SOFT_NAV = 'Nav',
440
465
  // Note: INP is handled in UserInteractionsHandler
441
466
  }
442
467
 
@@ -445,7 +470,7 @@ export interface MetricScore {
445
470
  classification: ScoreClassification;
446
471
  event?: Types.Events.PageLoadEvent;
447
472
  // The last navigation that occurred before this metric score.
448
- navigation?: Types.Events.NavigationStart;
473
+ navigation?: AnyNavigationStart;
449
474
  estimated?: boolean;
450
475
  timing: Types.Timing.Micro;
451
476
  }
@@ -22,10 +22,17 @@ export function timeStampForEventAdjustedByClosestNavigation(
22
22
  event: Types.Events.Event,
23
23
  traceBounds: Types.Timing.TraceWindowMicro,
24
24
  navigationsByNavigationId: Map<string, Types.Events.NavigationStart>,
25
+ softNavigationsById: Map<number, Types.Events.SoftNavigationStart>,
25
26
  navigationsByFrameId: Map<string, Types.Events.NavigationStart[]>,
26
27
  ): Types.Timing.Micro {
27
28
  let eventTimeStamp = event.ts - traceBounds.min;
28
- if (event.args?.data?.navigationId) {
29
+ if (event.name === Types.Events.Name.MARK_LCP_CANDIDATE_FOR_SOFT_NAVIGATION &&
30
+ event.args?.data?.performanceTimelineNavigationId) {
31
+ const navigationForEvent = softNavigationsById.get(event.args.data.performanceTimelineNavigationId);
32
+ if (navigationForEvent) {
33
+ eventTimeStamp = event.ts - navigationForEvent.ts;
34
+ }
35
+ } else if (event.args?.data?.navigationId) {
29
36
  const navigationForEvent = navigationsByNavigationId.get(event.args.data.navigationId);
30
37
  if (navigationForEvent) {
31
38
  eventTimeStamp = event.ts - navigationForEvent.ts;
@@ -27,7 +27,7 @@ export function getInsight<InsightName extends keyof InsightModels>(
27
27
  }
28
28
 
29
29
  export function getLCP(insightSet: InsightSet):
30
- {value: Types.Timing.Micro, event: Types.Events.LargestContentfulPaintCandidate}|null {
30
+ {value: Types.Timing.Micro, event: Types.Events.AnyLargestContentfulPaintCandidate}|null {
31
31
  const insight = getInsight(InsightKeys.LCP_BREAKDOWN, insightSet);
32
32
  if (!insight || !insight.lcpMs || !insight.lcpEvent) {
33
33
  return null;
@@ -95,7 +95,7 @@ export function isLCPBreakdownInsight(model: InsightModel): model is LCPBreakdow
95
95
  export type LCPBreakdownInsightModel = InsightModel<typeof UIStrings, {
96
96
  lcpMs?: Types.Timing.Milli,
97
97
  lcpTs?: Types.Timing.Milli,
98
- lcpEvent?: Types.Events.LargestContentfulPaintCandidate,
98
+ lcpEvent?: Types.Events.AnyLargestContentfulPaintCandidate,
99
99
  /** The network request for the LCP image, if there was one. */
100
100
  lcpRequest?: Types.Events.SyntheticNetworkRequest,
101
101
  subparts?: LCPSubparts,
@@ -112,7 +112,7 @@ function anyValuesNaN(...values: number[]): boolean {
112
112
  */
113
113
  function determineSubparts(
114
114
  nav: Types.Events.NavigationStart, docRequest: Types.Events.SyntheticNetworkRequest,
115
- lcpEvent: Types.Events.LargestContentfulPaintCandidate,
115
+ lcpEvent: Types.Events.AnyLargestContentfulPaintCandidate,
116
116
  lcpRequest: Types.Events.SyntheticNetworkRequest|undefined): LCPSubparts|null {
117
117
  const firstDocByteTs = calculateDocFirstByteTs(docRequest);
118
118
  if (firstDocByteTs === null) {
@@ -218,13 +218,13 @@ export function generateInsight(
218
218
  throw new Error('no frame metrics');
219
219
  }
220
220
 
221
- const navMetrics = frameMetrics.get(context.navigationId);
221
+ const navMetrics = frameMetrics.get(context.navigation);
222
222
  if (!navMetrics) {
223
223
  throw new Error('no navigation metrics');
224
224
  }
225
225
  const metricScore = navMetrics.get(Handlers.ModelHandlers.PageLoadMetrics.MetricName.LCP);
226
226
  const lcpEvent = metricScore?.event;
227
- if (!lcpEvent || !Types.Events.isLargestContentfulPaintCandidate(lcpEvent)) {
227
+ if (!lcpEvent || !Types.Events.isAnyLargestContentfulPaintCandidate(lcpEvent)) {
228
228
  return finalize({warnings: [InsightWarning.NO_LCP]});
229
229
  }
230
230
 
@@ -66,7 +66,7 @@ export function isLCPDiscoveryInsight(model: InsightModel): model is LCPDiscover
66
66
  return model.insightKey === 'LCPDiscovery';
67
67
  }
68
68
  export type LCPDiscoveryInsightModel = InsightModel<typeof UIStrings, {
69
- lcpEvent?: Types.Events.LargestContentfulPaintCandidate,
69
+ lcpEvent?: Types.Events.AnyLargestContentfulPaintCandidate,
70
70
  /** The network request for the LCP image, if there was one. */
71
71
  lcpRequest?: Types.Events.SyntheticNetworkRequest,
72
72
  earliestDiscoveryTimeTs?: Types.Timing.Micro,
@@ -108,13 +108,13 @@ export function generateInsight(
108
108
  throw new Error('no frame metrics');
109
109
  }
110
110
 
111
- const navMetrics = frameMetrics.get(context.navigationId);
111
+ const navMetrics = frameMetrics.get(context.navigation);
112
112
  if (!navMetrics) {
113
113
  throw new Error('no navigation metrics');
114
114
  }
115
115
  const metricScore = navMetrics.get(Handlers.ModelHandlers.PageLoadMetrics.MetricName.LCP);
116
116
  const lcpEvent = metricScore?.event;
117
- if (!lcpEvent || !Types.Events.isLargestContentfulPaintCandidate(lcpEvent)) {
117
+ if (!lcpEvent || !Types.Events.isAnyLargestContentfulPaintCandidate(lcpEvent)) {
118
118
  return finalize({warnings: [InsightWarning.NO_LCP]});
119
119
  }
120
120
 
@@ -185,7 +185,7 @@ export function generateInsight(
185
185
  }
186
186
 
187
187
  const firstPaintTs = data.PageLoadMetrics.metricScoresByFrameId.get(context.frameId)
188
- ?.get(context.navigationId)
188
+ ?.get(context.navigation)
189
189
  ?.get(Handlers.ModelHandlers.PageLoadMetrics.MetricName.FP)
190
190
  ?.event?.ts;
191
191
  if (!firstPaintTs) {
@@ -96,7 +96,7 @@ export type InsightModel<UIStrings extends Record<string, string> = Record<strin
96
96
  /**
97
97
  * If this insight is attached to a navigation, this stores its ID.
98
98
  */
99
- navigationId?: string,
99
+ navigation?: Types.Events.NavigationStart,
100
100
  /** This is lazily-generated because some insights may create many overlays. */
101
101
  createOverlays?: () => Types.Overlays.Overlay[],
102
102
  };
@@ -100,6 +100,8 @@ export interface ArgsData {
100
100
  sampleTraceId?: number;
101
101
  url?: string;
102
102
  navigationId?: string;
103
+ /** For soft navs. */
104
+ performanceTimelineNavigationId?: number;
103
105
  frame?: string;
104
106
  }
105
107
 
@@ -702,6 +704,29 @@ export interface NavigationStart extends Mark {
702
704
  };
703
705
  }
704
706
 
707
+ export interface SoftNavigationStart extends Event {
708
+ name: Name.SOFT_NAVIGATION_START;
709
+ ph: Phase.ASYNC_NESTABLE_INSTANT;
710
+ args: Args&{
711
+ frame: string,
712
+ context: {
713
+ softNavContextId: number,
714
+ // eslint-disable-next-line @typescript-eslint/naming-convention
715
+ URL: string,
716
+ timeOrigin: number,
717
+ domModifications: number,
718
+ firstContentfulPaint: number,
719
+ paintedArea: number,
720
+ performanceTimelineNavigationId: number,
721
+ repaintedArea: number,
722
+ },
723
+ };
724
+ }
725
+
726
+ export function isSoftNavigationStart(event: Event): event is SoftNavigationStart {
727
+ return event.name === Name.SOFT_NAVIGATION_START;
728
+ }
729
+
705
730
  export interface FirstContentfulPaint extends Mark {
706
731
  name: Name.MARK_FCP;
707
732
  args: Args&{
@@ -722,27 +747,30 @@ export interface FirstPaint extends Mark {
722
747
  };
723
748
  }
724
749
 
725
- export type PageLoadEvent = FirstContentfulPaint|MarkDOMContent|InteractiveTime|LargestContentfulPaintCandidate|
726
- LayoutShift|FirstPaint|MarkLoad|NavigationStart;
750
+ export type PageLoadEvent = FirstContentfulPaint|MarkDOMContent|InteractiveTime|AnyLargestContentfulPaintCandidate|
751
+ LayoutShift|FirstPaint|MarkLoad|NavigationStart|SoftNavigationStart;
727
752
 
728
753
  const markerTypeGuards = [
729
754
  isMarkDOMContent,
730
755
  isMarkLoad,
731
756
  isFirstPaint,
732
757
  isFirstContentfulPaint,
733
- isLargestContentfulPaintCandidate,
758
+ isAnyLargestContentfulPaintCandidate,
734
759
  isNavigationStart,
760
+ isSoftNavigationStart,
735
761
  ];
736
762
 
737
- export const MarkerName =
738
- ['MarkDOMContent', 'MarkLoad', 'firstPaint', 'firstContentfulPaint', 'largestContentfulPaint::Candidate'] as const;
763
+ export const MarkerName = [
764
+ 'MarkDOMContent', 'MarkLoad', 'firstPaint', 'firstContentfulPaint', 'largestContentfulPaint::Candidate',
765
+ 'largestContentfulPaint::CandidateForSoftNavigation'
766
+ ] as const;
739
767
 
740
768
  export interface MarkerEvent extends Event {
741
769
  name: typeof MarkerName[number];
742
770
  }
743
771
 
744
772
  export function isMarkerEvent(event: Event): event is MarkerEvent {
745
- if (event.ph === Phase.INSTANT || event.ph === Phase.MARK) {
773
+ if (event.ph === Phase.INSTANT || Phase.ASYNC_NESTABLE_INSTANT || event.ph === Phase.MARK) {
746
774
  return markerTypeGuards.some(fn => fn(event));
747
775
  }
748
776
  return false;
@@ -754,7 +782,7 @@ const pageLoadEventTypeGuards = [
754
782
  ];
755
783
 
756
784
  export function eventIsPageLoadEvent(event: Event): event is PageLoadEvent {
757
- if (event.ph === Phase.INSTANT || event.ph === Phase.MARK) {
785
+ if (event.ph === Phase.INSTANT || Phase.ASYNC_NESTABLE_INSTANT || event.ph === Phase.MARK) {
758
786
  return pageLoadEventTypeGuards.some(fn => fn(event));
759
787
  }
760
788
  return false;
@@ -777,6 +805,28 @@ export interface LargestContentfulPaintCandidate extends Mark {
777
805
  },
778
806
  };
779
807
  }
808
+
809
+ export interface LargestContentfulPaintCandidateForSoftNavigation extends Mark {
810
+ name: Name.MARK_LCP_CANDIDATE_FOR_SOFT_NAVIGATION;
811
+ args: Args&{
812
+ frame: string,
813
+ data?: ArgsData&{
814
+ candidateIndex: number,
815
+ isOutermostMainFrame: boolean,
816
+ isMainFrame: boolean,
817
+ nodeId: Protocol.DOM.BackendNodeId,
818
+ loadingAttr: string,
819
+ performanceTimelineNavigationId: number,
820
+ type?: string,
821
+ // Landed in Chrome M140: crrev.com/c/6702010
822
+ nodeName?: string,
823
+ },
824
+ };
825
+ }
826
+
827
+ export type AnyLargestContentfulPaintCandidate =
828
+ LargestContentfulPaintCandidate|LargestContentfulPaintCandidateForSoftNavigation;
829
+
780
830
  export interface LargestImagePaintCandidate extends Mark {
781
831
  name: 'LargestImagePaint::Candidate';
782
832
  args: Args&{
@@ -2209,8 +2259,8 @@ export function isFirstContentfulPaint(event: Event): event is FirstContentfulPa
2209
2259
  return event.name === 'firstContentfulPaint';
2210
2260
  }
2211
2261
 
2212
- export function isLargestContentfulPaintCandidate(event: Event): event is LargestContentfulPaintCandidate {
2213
- return event.name === Name.MARK_LCP_CANDIDATE;
2262
+ export function isAnyLargestContentfulPaintCandidate(event: Event): event is AnyLargestContentfulPaintCandidate {
2263
+ return event.name === Name.MARK_LCP_CANDIDATE || event.name === Name.MARK_LCP_CANDIDATE_FOR_SOFT_NAVIGATION;
2214
2264
  }
2215
2265
  export function isLargestImagePaintCandidate(event: Event): event is LargestImagePaintCandidate {
2216
2266
  return event.name === 'LargestImagePaint::Candidate';
@@ -2336,7 +2386,7 @@ export function isPrePaint(
2336
2386
 
2337
2387
  /** A VALID navigation start (as it has a populated documentLoaderURL) */
2338
2388
  export function isNavigationStart(event: Event): event is NavigationStart {
2339
- return event.name === 'navigationStart' && (event as NavigationStart).args?.data?.documentLoaderURL !== '';
2389
+ return event.name === Name.NAVIGATION_START && (event as NavigationStart).args?.data?.documentLoaderURL !== '';
2340
2390
  }
2341
2391
 
2342
2392
  export interface DidCommitSameDocumentNavigation extends Complete {
@@ -3089,8 +3139,10 @@ export const enum Name {
3089
3139
  MARK_FIRST_PAINT = 'firstPaint',
3090
3140
  MARK_FCP = 'firstContentfulPaint',
3091
3141
  MARK_LCP_CANDIDATE = 'largestContentfulPaint::Candidate',
3142
+ MARK_LCP_CANDIDATE_FOR_SOFT_NAVIGATION = 'largestContentfulPaint::CandidateForSoftNavigation',
3092
3143
  MARK_LCP_INVALIDATE = 'largestContentfulPaint::Invalidate',
3093
3144
  NAVIGATION_START = 'navigationStart',
3145
+ SOFT_NAVIGATION_START = 'SoftNavigationStart',
3094
3146
  CONSOLE_TIME = 'ConsoleTime',
3095
3147
  USER_TIMING = 'UserTiming',
3096
3148
  INTERACTIVE_TIME = 'InteractiveTime',