@grafana/faro-web-sdk
Version:
Faro instrumentations, metas, transports for web.
118 lines • 6.06 kB
JavaScript
import { onCLS, onFCP, onINP, onLCP, onTTFB } from 'web-vitals/attribution';
import { unknownString } from '@grafana/faro-core';
import { getItem, webStorageType } from '../../utils';
import { NAVIGATION_ID_STORAGE_KEY } from '../instrumentationConstants';
// duplicate keys saved in variables to save bundle size
// refs: https://github.com/grafana/faro-web-sdk/pull/595#discussion_r1615833968
const loadStateKey = 'load_state';
const timeToFirstByteKey = 'time_to_first_byte';
export class WebVitalsWithAttribution {
constructor(corePushMeasurement, webVitalConfig) {
this.corePushMeasurement = corePushMeasurement;
this.webVitalConfig = webVitalConfig;
}
initialize() {
this.measureCLS();
this.measureFCP();
this.measureINP();
this.measureLCP();
this.measureTTFB();
}
measureCLS() {
var _a;
onCLS((metric) => {
const { loadState, largestShiftValue, largestShiftTime, largestShiftTarget } = metric.attribution;
const values = this.buildInitialValues(metric);
this.addIfPresent(values, 'largest_shift_value', largestShiftValue);
this.addIfPresent(values, 'largest_shift_time', largestShiftTime);
const context = this.buildInitialContext(metric);
this.addIfPresent(context, loadStateKey, loadState);
this.addIfPresent(context, 'largest_shift_target', largestShiftTarget);
this.pushMeasurement(values, context);
}, { reportAllChanges: (_a = this.webVitalConfig) === null || _a === void 0 ? void 0 : _a.reportAllChanges });
}
measureFCP() {
var _a;
onFCP((metric) => {
const { firstByteToFCP, timeToFirstByte, loadState } = metric.attribution;
const values = this.buildInitialValues(metric);
this.addIfPresent(values, 'first_byte_to_fcp', firstByteToFCP);
this.addIfPresent(values, timeToFirstByteKey, timeToFirstByte);
const context = this.buildInitialContext(metric);
this.addIfPresent(context, loadStateKey, loadState);
this.pushMeasurement(values, context);
}, { reportAllChanges: (_a = this.webVitalConfig) === null || _a === void 0 ? void 0 : _a.reportAllChanges });
}
measureINP() {
var _a;
onINP((metric) => {
const { interactionTime, presentationDelay, inputDelay, processingDuration, nextPaintTime, loadState, interactionTarget, interactionType, } = metric.attribution;
const values = this.buildInitialValues(metric);
this.addIfPresent(values, 'interaction_time', interactionTime);
this.addIfPresent(values, 'presentation_delay', presentationDelay);
this.addIfPresent(values, 'input_delay', inputDelay);
this.addIfPresent(values, 'processing_duration', processingDuration);
this.addIfPresent(values, 'next_paint_time', nextPaintTime);
const context = this.buildInitialContext(metric);
this.addIfPresent(context, loadStateKey, loadState);
this.addIfPresent(context, 'interaction_target', interactionTarget);
this.addIfPresent(context, 'interaction_type', interactionType);
this.pushMeasurement(values, context);
}, { reportAllChanges: (_a = this.webVitalConfig) === null || _a === void 0 ? void 0 : _a.reportAllChanges });
}
measureLCP() {
var _a;
onLCP((metric) => {
const { elementRenderDelay, resourceLoadDelay, resourceLoadDuration, timeToFirstByte, target } = metric.attribution;
const values = this.buildInitialValues(metric);
this.addIfPresent(values, 'element_render_delay', elementRenderDelay);
this.addIfPresent(values, 'resource_load_delay', resourceLoadDelay);
this.addIfPresent(values, 'resource_load_duration', resourceLoadDuration);
this.addIfPresent(values, timeToFirstByteKey, timeToFirstByte);
const context = this.buildInitialContext(metric);
this.addIfPresent(context, 'element', target);
this.pushMeasurement(values, context);
}, { reportAllChanges: (_a = this.webVitalConfig) === null || _a === void 0 ? void 0 : _a.reportAllChanges });
}
measureTTFB() {
var _a;
onTTFB((metric) => {
const { dnsDuration, connectionDuration, requestDuration, waitingDuration, cacheDuration } = metric.attribution;
const values = this.buildInitialValues(metric);
this.addIfPresent(values, 'dns_duration', dnsDuration);
this.addIfPresent(values, 'connection_duration', connectionDuration);
this.addIfPresent(values, 'request_duration', requestDuration);
this.addIfPresent(values, 'waiting_duration', waitingDuration);
this.addIfPresent(values, 'cache_duration', cacheDuration);
const context = this.buildInitialContext(metric);
this.pushMeasurement(values, context);
}, { reportAllChanges: (_a = this.webVitalConfig) === null || _a === void 0 ? void 0 : _a.reportAllChanges });
}
buildInitialValues(metric) {
const indicator = metric.name.toLowerCase();
return {
[indicator]: metric.value,
delta: metric.delta,
};
}
buildInitialContext(metric) {
var _a;
const navigationEntryId = (_a = getItem(NAVIGATION_ID_STORAGE_KEY, webStorageType.session)) !== null && _a !== void 0 ? _a : unknownString;
return {
id: metric.id,
rating: metric.rating,
navigation_type: metric.navigationType,
navigation_entry_id: navigationEntryId,
};
}
pushMeasurement(values, context) {
const type = 'web-vitals';
this.corePushMeasurement({ type, values }, { context });
}
addIfPresent(source, key, metric) {
if (metric) {
source[key] = metric;
}
}
}
//# sourceMappingURL=webVitalsWithAttribution.js.map