Skip to content

Commit 0c0d49c

Browse files
committed
refactor(browser): consolidate web vitals tracking
1 parent 91c2936 commit 0c0d49c

4 files changed

Lines changed: 28 additions & 57 deletions

File tree

packages/browser-utils/src/index.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,18 @@ export {
88

99
export {
1010
addPerformanceEntries,
11+
registerInpInteractionListener,
1112
startTrackingInteractions,
1213
startTrackingLongTasks,
1314
startTrackingLongAnimationFrames,
1415
startTrackingWebVitals,
15-
registerInpInteractionListener,
1616
} from './metrics/browserMetrics';
17+
export type { WebVitalName } from './metrics/browserMetrics';
1718

1819
export { elementTimingIntegration, startTrackingElementTiming } from './metrics/elementTiming';
1920

2021
export { extractNetworkProtocol } from './metrics/utils';
2122

22-
export { trackClsAsSpan, trackInpAsSpan, trackLcpAsSpan } from './metrics/webVitalSpans';
23-
2423
export { addClickKeypressInstrumentationHandler } from './instrument/dom';
2524

2625
export { addHistoryInstrumentationHandler } from './instrument/history';

packages/browser-utils/src/metrics/browserMetrics.ts

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* eslint-disable max-lines */
2-
import type { Measurements, Span, SpanAttributes, SpanAttributeValue, StartSpanOptions } from '@sentry/core';
2+
import type { Client, Measurements, Span, SpanAttributes, SpanAttributeValue, StartSpanOptions } from '@sentry/core';
33
import {
44
browserPerformanceTimeOrigin,
55
debug,
@@ -23,6 +23,7 @@ import { getBrowserPerformanceAPI, isMeasurementValue, msToSec, startAndEndSpan
2323
import { getActivationStart } from './web-vitals/lib/getActivationStart';
2424
import { getNavigationEntry } from './web-vitals/lib/getNavigationEntry';
2525
import { getVisibilityWatcher } from './web-vitals/lib/getVisibilityWatcher';
26+
import { trackClsAsSpan, trackInpAsSpan, trackLcpAsSpan } from './webVitalSpans';
2627
import { DEBUG_BUILD } from '../debug-build';
2728
interface NavigatorNetworkInformation {
2829
readonly connection?: NetworkInformation;
@@ -69,6 +70,7 @@ let _performanceCursor: number = 0;
6970
let _measurements: Measurements = {};
7071

7172
type PageloadWebVitalName = 'ttfb' | 'fp' | 'fcp';
73+
export type WebVitalName = PageloadWebVitalName | 'lcp' | 'cls' | 'inp';
7274

7375
const DEFAULT_PAGELOAD_WEB_VITALS = new Set<PageloadWebVitalName>(['ttfb', 'fp', 'fcp']);
7476

@@ -78,17 +80,26 @@ let _collectTtfb: (() => void) | undefined;
7880

7981
/**
8082
* Start tracking web vitals.
81-
*
82-
* LCP, CLS and INP are handled separately as spans by `webVitalsIntegration`;
83-
* this function tracks pageload web vitals which are attached as attributes.
8483
*/
85-
export function startTrackingWebVitals(options: { disable?: Array<'ttfb' | 'fp' | 'fcp'> } = {}): void {
84+
export function startTrackingWebVitals(client: Client, disabled: ReadonlySet<WebVitalName>): void {
85+
startTrackingPageloadWebVitals(disabled);
86+
87+
if (!disabled.has('lcp')) {
88+
trackLcpAsSpan(client);
89+
}
90+
if (!disabled.has('cls')) {
91+
trackClsAsSpan(client);
92+
}
93+
if (!disabled.has('inp')) {
94+
trackInpAsSpan();
95+
}
96+
}
97+
98+
function startTrackingPageloadWebVitals(disabled: ReadonlySet<WebVitalName>): void {
8699
_collectTtfb?.();
87100
_collectTtfb = undefined;
88101

89-
_enabledPageloadWebVitals = new Set(
90-
Array.from(DEFAULT_PAGELOAD_WEB_VITALS).filter(vital => !options.disable?.includes(vital)),
91-
);
102+
_enabledPageloadWebVitals = new Set(Array.from(DEFAULT_PAGELOAD_WEB_VITALS).filter(vital => !disabled.has(vital)));
92103

93104
const performance = getBrowserPerformanceAPI();
94105
if (performance && browserPerformanceTimeOrigin()) {
Lines changed: 3 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,9 @@
11
import type { IntegrationFn } from '@sentry/core';
22
import { debug, defineIntegration, hasSpansEnabled } from '@sentry/core';
3-
import {
4-
startTrackingWebVitals,
5-
registerInpInteractionListener,
6-
trackClsAsSpan,
7-
trackInpAsSpan,
8-
trackLcpAsSpan,
9-
} from '@sentry-internal/browser-utils';
3+
import { registerInpInteractionListener, startTrackingWebVitals } from '@sentry-internal/browser-utils';
4+
import type { WebVitalName } from '@sentry-internal/browser-utils';
105
import { DEBUG_BUILD } from '../debug-build';
116

12-
type WebVitalName = 'lcp' | 'cls' | 'inp' | 'ttfb' | 'fp' | 'fcp';
13-
type PageloadWebVitalName = Extract<WebVitalName, 'ttfb' | 'fp' | 'fcp'>;
14-
157
interface WebVitalsOptions {
168
/**
179
* How web vitals are emitted.
@@ -42,7 +34,6 @@ export const INTEGRATION_NAME = 'WebVitals';
4234
*/
4335
export const webVitalsIntegration = defineIntegration((options: WebVitalsOptions = {}) => {
4436
const disabled = new Set(options.disable ?? []);
45-
const disabledPageloadWebVitals = options.disable?.filter(isPageloadWebVitalName);
4637

4738
return {
4839
name: INTEGRATION_NAME,
@@ -54,19 +45,7 @@ export const webVitalsIntegration = defineIntegration((options: WebVitalsOptions
5445
);
5546
}
5647

57-
startTrackingWebVitals({
58-
disable: disabledPageloadWebVitals,
59-
});
60-
61-
if (!disabled.has('lcp')) {
62-
trackLcpAsSpan(client);
63-
}
64-
if (!disabled.has('cls')) {
65-
trackClsAsSpan(client);
66-
}
67-
if (!disabled.has('inp')) {
68-
trackInpAsSpan();
69-
}
48+
startTrackingWebVitals(client, disabled);
7049
},
7150
afterAllSetup() {
7251
if (!disabled.has('inp')) {
@@ -75,7 +54,3 @@ export const webVitalsIntegration = defineIntegration((options: WebVitalsOptions
7554
},
7655
};
7756
}) satisfies IntegrationFn;
78-
79-
function isPageloadWebVitalName(vital: WebVitalName): vital is PageloadWebVitalName {
80-
return vital === 'ttfb' || vital === 'fp' || vital === 'fcp';
81-
}

packages/browser/test/integrations/webVitals.test.ts

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,10 @@ import { webVitalsIntegration } from '../../src/integrations/webVitals';
44

55
const mockRegisterInpInteractionListener = vi.hoisted(() => vi.fn());
66
const mockStartTrackingWebVitals = vi.hoisted(() => vi.fn());
7-
const mockTrackClsAsSpan = vi.hoisted(() => vi.fn());
8-
const mockTrackInpAsSpan = vi.hoisted(() => vi.fn());
9-
const mockTrackLcpAsSpan = vi.hoisted(() => vi.fn());
107

118
vi.mock('@sentry-internal/browser-utils', () => ({
129
registerInpInteractionListener: mockRegisterInpInteractionListener,
1310
startTrackingWebVitals: mockStartTrackingWebVitals,
14-
trackClsAsSpan: mockTrackClsAsSpan,
15-
trackInpAsSpan: mockTrackInpAsSpan,
16-
trackLcpAsSpan: mockTrackLcpAsSpan,
1711
}));
1812

1913
describe('webVitalsIntegration', () => {
@@ -35,12 +29,8 @@ describe('webVitalsIntegration', () => {
3529
integration.setup?.(client as never);
3630
integration.afterAllSetup?.(client as never);
3731

38-
expect(mockStartTrackingWebVitals).toHaveBeenCalledWith({
39-
disable: undefined,
40-
});
41-
expect(mockTrackLcpAsSpan).toHaveBeenCalledWith(client);
42-
expect(mockTrackClsAsSpan).toHaveBeenCalledWith(client);
43-
expect(mockTrackInpAsSpan).toHaveBeenCalledTimes(1);
32+
expect(mockStartTrackingWebVitals).toHaveBeenCalledWith(client, expect.any(Set));
33+
expect(mockStartTrackingWebVitals.mock.calls[0]?.[1]).toEqual(new Set());
4434
expect(mockRegisterInpInteractionListener).toHaveBeenCalledTimes(1);
4535
expect(debug.warn).not.toHaveBeenCalled();
4636
});
@@ -54,12 +44,8 @@ describe('webVitalsIntegration', () => {
5444
integration.setup?.(client as never);
5545
integration.afterAllSetup?.(client as never);
5646

57-
expect(mockStartTrackingWebVitals).toHaveBeenCalledWith({
58-
disable: ['ttfb', 'fcp'],
59-
});
60-
expect(mockTrackLcpAsSpan).not.toHaveBeenCalled();
61-
expect(mockTrackClsAsSpan).toHaveBeenCalledWith(client);
62-
expect(mockTrackInpAsSpan).not.toHaveBeenCalled();
47+
expect(mockStartTrackingWebVitals).toHaveBeenCalledWith(client, expect.any(Set));
48+
expect(mockStartTrackingWebVitals.mock.calls[0]?.[1]).toEqual(new Set(['ttfb', 'fcp', 'lcp', 'inp']));
6349
expect(mockRegisterInpInteractionListener).not.toHaveBeenCalled();
6450
});
6551

0 commit comments

Comments
 (0)