summaryrefslogtreecommitdiff
path: root/packages/integrations/web-vitals/src/client-script.ts
blob: 86591745e946e2a8ec6590eaa21e5f18e8f39267 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import { type Metric, onCLS, onFCP, onINP, onLCP, onTTFB } from 'web-vitals';
import { WEB_VITALS_ENDPOINT_PATH } from './constants.js';
import type { ClientMetric } from './schemas.js';

const pathname = location.pathname.replace(/(?<=.)\/$/, '');
const route =
	document
		.querySelector<HTMLMetaElement>('meta[name="x-astro-vitals-route"]')
		?.getAttribute('content') || pathname;

const queue = new Set<Metric>();
const addToQueue = (metric: Metric) => queue.add(metric);
function flushQueue() {
	if (!queue.size) return;
	const rawBody: ClientMetric[] = [...queue].map(({ name, id, value, rating }) => ({
		pathname,
		route,
		name,
		id,
		value,
		rating,
	}));
	const body = JSON.stringify(rawBody);
	if (navigator.sendBeacon) navigator.sendBeacon(WEB_VITALS_ENDPOINT_PATH, body);
	else fetch(WEB_VITALS_ENDPOINT_PATH, { body, method: 'POST', keepalive: true });
	queue.clear();
}

for (const listener of [onCLS, onLCP, onINP, onFCP, onTTFB]) {
	listener(addToQueue);
}

addEventListener('visibilitychange', () => {
	if (document.visibilityState === 'hidden') flushQueue();
});
addEventListener('pagehide', flushQueue);