diff options
Diffstat (limited to 'packages/integrations/web-vitals/src/client-script.ts')
-rw-r--r-- | packages/integrations/web-vitals/src/client-script.ts | 36 |
1 files changed, 36 insertions, 0 deletions
diff --git a/packages/integrations/web-vitals/src/client-script.ts b/packages/integrations/web-vitals/src/client-script.ts new file mode 100644 index 000000000..b69fa6772 --- /dev/null +++ b/packages/integrations/web-vitals/src/client-script.ts @@ -0,0 +1,36 @@ +import { type Metric, onCLS, onFCP, onFID, 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, onFID, onFCP, onTTFB]) { + listener(addToQueue); +} + +addEventListener('visibilitychange', () => { + if (document.visibilityState === 'hidden') flushQueue(); +}); +addEventListener('pagehide', flushQueue); |