Skip to content

Commit 67a067a

Browse files
authored
ref(replay): Update CLS web vitals to align with browserTracing (#13058)
NodeId has been replaced with nodeIds which now accepts several nodes since CLS scores are cumulative. Also updated CLS metrics to match CLS captured from browserTracing. Relates to getsentry/sentry#69881
1 parent 51f85e6 commit 67a067a

File tree

6 files changed

+32
-30
lines changed

6 files changed

+32
-30
lines changed

.size-limit.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ module.exports = [
149149
name: 'CDN Bundle (incl. Tracing, Replay)',
150150
path: createCDNPath('bundle.tracing.replay.min.js'),
151151
gzip: true,
152-
limit: '72 KB',
152+
limit: '73 KB',
153153
},
154154
{
155155
name: 'CDN Bundle (incl. Tracing, Replay, Feedback)',

dev-packages/browser-integration-tests/utils/replayEventTemplates.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ export const expectedLCPPerformanceSpan = {
127127
endTimestamp: expect.any(Number),
128128
data: {
129129
value: expect.any(Number),
130-
nodeId: expect.any(Number),
130+
nodeIds: expect.any(Array),
131131
rating: expect.any(String),
132132
size: expect.any(Number),
133133
},
@@ -140,6 +140,7 @@ export const expectedCLSPerformanceSpan = {
140140
endTimestamp: expect.any(Number),
141141
data: {
142142
value: expect.any(Number),
143+
nodeIds: expect.any(Array),
143144
rating: expect.any(String),
144145
size: expect.any(Number),
145146
},
@@ -154,7 +155,7 @@ export const expectedFIDPerformanceSpan = {
154155
value: expect.any(Number),
155156
rating: expect.any(String),
156157
size: expect.any(Number),
157-
nodeId: expect.any(Number),
158+
nodeIds: expect.any(Array),
158159
},
159160
};
160161

@@ -167,7 +168,7 @@ export const expectedINPPerformanceSpan = {
167168
value: expect.any(Number),
168169
rating: expect.any(String),
169170
size: expect.any(Number),
170-
nodeId: expect.any(Number),
171+
nodeIds: expect.any(Array),
171172
},
172173
};
173174

dev-packages/e2e-tests/test-applications/react-send-to-sentry/tests/fixtures/ReplayRecordingData.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ export const ReplayRecordingData = [
220220
value: expect.any(Number),
221221
size: expect.any(Number),
222222
rating: expect.any(String),
223-
nodeId: 16,
223+
nodeIds: [16],
224224
},
225225
},
226226
},
@@ -239,6 +239,7 @@ export const ReplayRecordingData = [
239239
value: expect.any(Number),
240240
size: expect.any(Number),
241241
rating: expect.any(String),
242+
nodeIds: expect.any(Array),
242243
},
243244
},
244245
},
@@ -257,7 +258,7 @@ export const ReplayRecordingData = [
257258
value: expect.any(Number),
258259
size: expect.any(Number),
259260
rating: expect.any(String),
260-
nodeId: 10,
261+
nodeIds: [10],
261262
},
262263
},
263264
},

packages/replay-internal/src/types/performance.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,9 @@ export interface WebVitalData {
108108
*/
109109
rating: 'good' | 'needs-improvement' | 'poor';
110110
/**
111-
* The recording id of the LCP node. -1 if not found
111+
* The recording id of the web vital nodes. -1 if not found
112112
*/
113-
nodeId?: number;
113+
nodeIds?: number[];
114114
}
115115

116116
/**

packages/replay-internal/src/util/createPerformanceEntries.ts

+17-17
Original file line numberDiff line numberDiff line change
@@ -183,30 +183,34 @@ function createResourceEntry(
183183
*/
184184
export function getLargestContentfulPaint(metric: Metric): ReplayPerformanceEntry<WebVitalData> {
185185
const lastEntry = metric.entries[metric.entries.length - 1] as (PerformanceEntry & { element?: Node }) | undefined;
186-
const node = lastEntry ? lastEntry.element : undefined;
186+
const node = lastEntry && lastEntry.element ? [lastEntry.element] : undefined;
187187
return getWebVital(metric, 'largest-contentful-paint', node);
188188
}
189189

190190
/**
191191
* Add a CLS event to the replay based on a CLS metric.
192192
*/
193193
export function getCumulativeLayoutShift(metric: Metric): ReplayPerformanceEntry<WebVitalData> {
194-
// get first node that shifts
195-
const firstEntry = metric.entries[0] as (PerformanceEntry & { sources?: LayoutShiftAttribution[] }) | undefined;
196-
const node = firstEntry
197-
? firstEntry.sources && firstEntry.sources[0]
198-
? firstEntry.sources[0].node
199-
: undefined
200-
: undefined;
201-
return getWebVital(metric, 'cumulative-layout-shift', node);
194+
const lastEntry = metric.entries[metric.entries.length - 1] as
195+
| (PerformanceEntry & { sources?: LayoutShiftAttribution[] })
196+
| undefined;
197+
const nodes: Node[] = [];
198+
if (lastEntry && lastEntry.sources) {
199+
for (const source of lastEntry.sources) {
200+
if (source.node) {
201+
nodes.push(source.node);
202+
}
203+
}
204+
}
205+
return getWebVital(metric, 'cumulative-layout-shift', nodes);
202206
}
203207

204208
/**
205209
* Add a FID event to the replay based on a FID metric.
206210
*/
207211
export function getFirstInputDelay(metric: Metric): ReplayPerformanceEntry<WebVitalData> {
208212
const lastEntry = metric.entries[metric.entries.length - 1] as (PerformanceEntry & { target?: Node }) | undefined;
209-
const node = lastEntry ? lastEntry.target : undefined;
213+
const node = lastEntry && lastEntry.target ? [lastEntry.target] : undefined;
210214
return getWebVital(metric, 'first-input-delay', node);
211215
}
212216

@@ -215,18 +219,14 @@ export function getFirstInputDelay(metric: Metric): ReplayPerformanceEntry<WebVi
215219
*/
216220
export function getInteractionToNextPaint(metric: Metric): ReplayPerformanceEntry<WebVitalData> {
217221
const lastEntry = metric.entries[metric.entries.length - 1] as (PerformanceEntry & { target?: Node }) | undefined;
218-
const node = lastEntry ? lastEntry.target : undefined;
222+
const node = lastEntry && lastEntry.target ? [lastEntry.target] : undefined;
219223
return getWebVital(metric, 'interaction-to-next-paint', node);
220224
}
221225

222226
/**
223227
* Add an web vital event to the replay based on the web vital metric.
224228
*/
225-
export function getWebVital(
226-
metric: Metric,
227-
name: string,
228-
node: Node | undefined,
229-
): ReplayPerformanceEntry<WebVitalData> {
229+
function getWebVital(metric: Metric, name: string, nodes: Node[] | undefined): ReplayPerformanceEntry<WebVitalData> {
230230
const value = metric.value;
231231
const rating = metric.rating;
232232

@@ -241,7 +241,7 @@ export function getWebVital(
241241
value,
242242
size: value,
243243
rating,
244-
nodeId: node ? record.mirror.getId(node) : undefined,
244+
nodeIds: nodes ? nodes.map(node => record.mirror.getId(node)) : undefined,
245245
},
246246
};
247247

packages/replay-internal/test/unit/util/createPerformanceEntry.test.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,13 @@ describe('Unit | util | createPerformanceEntries', () => {
8383
name: 'largest-contentful-paint',
8484
start: 1672531205.108299,
8585
end: 1672531205.108299,
86-
data: { value: 5108.299, rating: 'good', size: 5108.299, nodeId: undefined },
86+
data: { value: 5108.299, rating: 'good', size: 5108.299, nodeIds: undefined },
8787
});
8888
});
8989
});
9090

9191
describe('getCumulativeLayoutShift', () => {
92-
it('works with an CLS metric', async () => {
92+
it('works with a CLS metric', async () => {
9393
const metric = {
9494
value: 5108.299,
9595
rating: 'good' as const,
@@ -103,7 +103,7 @@ describe('Unit | util | createPerformanceEntries', () => {
103103
name: 'cumulative-layout-shift',
104104
start: 1672531205.108299,
105105
end: 1672531205.108299,
106-
data: { value: 5108.299, size: 5108.299, rating: 'good', nodeId: undefined },
106+
data: { value: 5108.299, size: 5108.299, rating: 'good', nodeIds: [] },
107107
});
108108
});
109109
});
@@ -123,7 +123,7 @@ describe('Unit | util | createPerformanceEntries', () => {
123123
name: 'first-input-delay',
124124
start: 1672531205.108299,
125125
end: 1672531205.108299,
126-
data: { value: 5108.299, size: 5108.299, rating: 'good', nodeId: undefined },
126+
data: { value: 5108.299, size: 5108.299, rating: 'good', nodeIds: undefined },
127127
});
128128
});
129129
});
@@ -143,7 +143,7 @@ describe('Unit | util | createPerformanceEntries', () => {
143143
name: 'interaction-to-next-paint',
144144
start: 1672531205.108299,
145145
end: 1672531205.108299,
146-
data: { value: 5108.299, size: 5108.299, rating: 'good', nodeId: undefined },
146+
data: { value: 5108.299, size: 5108.299, rating: 'good', nodeIds: undefined },
147147
});
148148
});
149149
});

0 commit comments

Comments
 (0)