@@ -43,7 +43,13 @@ export interface Metric {
43
43
* The array may also be empty if the metric value was not based on any
44
44
* entries (e.g. a CLS value of 0 given no layout shifts).
45
45
*/
46
- entries : PerformanceEntry [ ] | PerformanceEventTiming [ ] ;
46
+ entries : PerformanceEntry [ ] | LayoutShift [ ] ;
47
+ }
48
+
49
+ interface LayoutShift extends PerformanceEntry {
50
+ value : number ;
51
+ sources : LayoutShiftAttribution [ ] ;
52
+ hadRecentInput : boolean ;
47
53
}
48
54
49
55
interface LayoutShiftAttribution {
@@ -52,6 +58,11 @@ interface LayoutShiftAttribution {
52
58
currentRect : DOMRectReadOnly ;
53
59
}
54
60
61
+ interface Attribution {
62
+ value : number ;
63
+ nodeIds ?: number [ ] ;
64
+ }
65
+
55
66
/**
56
67
* Handler creater for web vitals
57
68
*/
@@ -187,22 +198,32 @@ export function getLargestContentfulPaint(metric: Metric): ReplayPerformanceEntr
187
198
return getWebVital ( metric , 'largest-contentful-paint' , node ) ;
188
199
}
189
200
201
+ function isLayoutShift ( entry : PerformanceEntry | LayoutShift ) : entry is LayoutShift {
202
+ return ( entry as LayoutShift ) . sources !== undefined ;
203
+ }
204
+
190
205
/**
191
206
* Add a CLS event to the replay based on a CLS metric.
192
207
*/
193
208
export function getCumulativeLayoutShift ( metric : Metric ) : ReplayPerformanceEntry < WebVitalData > {
194
- const lastEntry = metric . entries [ metric . entries . length - 1 ] as
195
- | ( PerformanceEntry & { sources ?: LayoutShiftAttribution [ ] } )
196
- | undefined ;
209
+ const layoutShifts : Attribution [ ] = [ ] ;
197
210
const nodes : Node [ ] = [ ] ;
198
- if ( lastEntry && lastEntry . sources ) {
199
- for ( const source of lastEntry . sources ) {
200
- if ( source . node ) {
201
- nodes . push ( source . node ) ;
211
+ for ( const entry of metric . entries ) {
212
+ if ( isLayoutShift ( entry ) ) {
213
+ const nodeIds = [ ] ;
214
+ for ( const source of entry . sources ) {
215
+ if ( source . node ) {
216
+ nodes . push ( source . node ) ;
217
+ const nodeId = record . mirror . getId ( source . node ) ;
218
+ if ( nodeId ) {
219
+ nodeIds . push ( nodeId ) ;
220
+ }
221
+ }
202
222
}
223
+ layoutShifts . push ( { value : entry . value , nodeIds } ) ;
203
224
}
204
225
}
205
- return getWebVital ( metric , 'cumulative-layout-shift' , nodes ) ;
226
+ return getWebVital ( metric , 'cumulative-layout-shift' , nodes , layoutShifts ) ;
206
227
}
207
228
208
229
/**
@@ -226,7 +247,12 @@ export function getInteractionToNextPaint(metric: Metric): ReplayPerformanceEntr
226
247
/**
227
248
* Add an web vital event to the replay based on the web vital metric.
228
249
*/
229
- function getWebVital ( metric : Metric , name : string , nodes : Node [ ] | undefined ) : ReplayPerformanceEntry < WebVitalData > {
250
+ function getWebVital (
251
+ metric : Metric ,
252
+ name : string ,
253
+ nodes : Node [ ] | undefined ,
254
+ attributions ?: Attribution [ ] ,
255
+ ) : ReplayPerformanceEntry < WebVitalData > {
230
256
const value = metric . value ;
231
257
const rating = metric . rating ;
232
258
@@ -242,6 +268,7 @@ function getWebVital(metric: Metric, name: string, nodes: Node[] | undefined): R
242
268
size : value ,
243
269
rating,
244
270
nodeIds : nodes ? nodes . map ( node => record . mirror . getId ( node ) ) : undefined ,
271
+ attributions,
245
272
} ,
246
273
} ;
247
274
0 commit comments