Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ref(replay): Update CLS web vitals to align with browserTracing #13058

Merged
merged 13 commits into from
Jul 30, 2024
2 changes: 1 addition & 1 deletion .size-limit.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ module.exports = [
name: 'CDN Bundle (incl. Tracing, Replay)',
path: createCDNPath('bundle.tracing.replay.min.js'),
gzip: true,
limit: '72 KB',
limit: '73 KB',
},
{
name: 'CDN Bundle (incl. Tracing, Replay, Feedback)',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ export const expectedLCPPerformanceSpan = {
endTimestamp: expect.any(Number),
data: {
value: expect.any(Number),
nodeId: expect.any(Number),
nodeIds: expect.any(Array),
rating: expect.any(String),
size: expect.any(Number),
},
Expand All @@ -140,6 +140,7 @@ export const expectedCLSPerformanceSpan = {
endTimestamp: expect.any(Number),
data: {
value: expect.any(Number),
nodeIds: expect.any(Array),
rating: expect.any(String),
size: expect.any(Number),
},
Expand All @@ -154,7 +155,7 @@ export const expectedFIDPerformanceSpan = {
value: expect.any(Number),
rating: expect.any(String),
size: expect.any(Number),
nodeId: expect.any(Number),
nodeIds: expect.any(Array),
},
};

Expand All @@ -167,7 +168,7 @@ export const expectedINPPerformanceSpan = {
value: expect.any(Number),
rating: expect.any(String),
size: expect.any(Number),
nodeId: expect.any(Number),
nodeIds: expect.any(Array),
},
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ export const ReplayRecordingData = [
value: expect.any(Number),
size: expect.any(Number),
rating: expect.any(String),
nodeId: 16,
nodeIds: [16],
},
},
},
Expand All @@ -239,6 +239,7 @@ export const ReplayRecordingData = [
value: expect.any(Number),
size: expect.any(Number),
rating: expect.any(String),
nodeIds: expect.any(Array),
},
},
},
Expand All @@ -257,7 +258,7 @@ export const ReplayRecordingData = [
value: expect.any(Number),
size: expect.any(Number),
rating: expect.any(String),
nodeId: 10,
nodeIds: [10],
},
},
},
Expand Down
4 changes: 2 additions & 2 deletions packages/replay-internal/src/types/performance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,9 @@ export interface WebVitalData {
*/
rating: 'good' | 'needs-improvement' | 'poor';
/**
* The recording id of the LCP node. -1 if not found
* The recording id of the web vital nodes. -1 if not found
*/
nodeId?: number;
nodeIds?: number[];
}

/**
Expand Down
34 changes: 17 additions & 17 deletions packages/replay-internal/src/util/createPerformanceEntries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,30 +183,34 @@ function createResourceEntry(
*/
export function getLargestContentfulPaint(metric: Metric): ReplayPerformanceEntry<WebVitalData> {
const lastEntry = metric.entries[metric.entries.length - 1] as (PerformanceEntry & { element?: Node }) | undefined;
const node = lastEntry ? lastEntry.element : undefined;
const node = lastEntry && lastEntry.element ? [lastEntry.element] : undefined;
return getWebVital(metric, 'largest-contentful-paint', node);
}

/**
* Add a CLS event to the replay based on a CLS metric.
*/
export function getCumulativeLayoutShift(metric: Metric): ReplayPerformanceEntry<WebVitalData> {
// get first node that shifts
const firstEntry = metric.entries[0] as (PerformanceEntry & { sources?: LayoutShiftAttribution[] }) | undefined;
const node = firstEntry
? firstEntry.sources && firstEntry.sources[0]
? firstEntry.sources[0].node
: undefined
: undefined;
return getWebVital(metric, 'cumulative-layout-shift', node);
const lastEntry = metric.entries[metric.entries.length - 1] as
| (PerformanceEntry & { sources?: LayoutShiftAttribution[] })
| undefined;
const nodes: Node[] = [];
if (lastEntry && lastEntry.sources) {
for (const source of lastEntry.sources) {
if (source.node) {
nodes.push(source.node);
}
}
}
return getWebVital(metric, 'cumulative-layout-shift', nodes);
}

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

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

/**
* Add an web vital event to the replay based on the web vital metric.
*/
export function getWebVital(
metric: Metric,
name: string,
node: Node | undefined,
): ReplayPerformanceEntry<WebVitalData> {
function getWebVital(metric: Metric, name: string, nodes: Node[] | undefined): ReplayPerformanceEntry<WebVitalData> {
const value = metric.value;
const rating = metric.rating;

Expand All @@ -241,7 +241,7 @@ export function getWebVital(
value,
size: value,
rating,
nodeId: node ? record.mirror.getId(node) : undefined,
nodeIds: nodes ? nodes.map(node => record.mirror.getId(node)) : undefined,
},
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,13 @@ describe('Unit | util | createPerformanceEntries', () => {
name: 'largest-contentful-paint',
start: 1672531205.108299,
end: 1672531205.108299,
data: { value: 5108.299, rating: 'good', size: 5108.299, nodeId: undefined },
data: { value: 5108.299, rating: 'good', size: 5108.299, nodeIds: undefined },
});
});
});

describe('getCumulativeLayoutShift', () => {
it('works with an CLS metric', async () => {
it('works with a CLS metric', async () => {
const metric = {
value: 5108.299,
rating: 'good' as const,
Expand All @@ -103,7 +103,7 @@ describe('Unit | util | createPerformanceEntries', () => {
name: 'cumulative-layout-shift',
start: 1672531205.108299,
end: 1672531205.108299,
data: { value: 5108.299, size: 5108.299, rating: 'good', nodeId: undefined },
data: { value: 5108.299, size: 5108.299, rating: 'good', nodeIds: [] },
});
});
});
Expand All @@ -123,7 +123,7 @@ describe('Unit | util | createPerformanceEntries', () => {
name: 'first-input-delay',
start: 1672531205.108299,
end: 1672531205.108299,
data: { value: 5108.299, size: 5108.299, rating: 'good', nodeId: undefined },
data: { value: 5108.299, size: 5108.299, rating: 'good', nodeIds: undefined },
});
});
});
Expand All @@ -143,7 +143,7 @@ describe('Unit | util | createPerformanceEntries', () => {
name: 'interaction-to-next-paint',
start: 1672531205.108299,
end: 1672531205.108299,
data: { value: 5108.299, size: 5108.299, rating: 'good', nodeId: undefined },
data: { value: 5108.299, size: 5108.299, rating: 'good', nodeIds: undefined },
});
});
});
Expand Down
Loading