summaryrefslogtreecommitdiff
path: root/packages/integrations/web-vitals/src/client-script.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/integrations/web-vitals/src/client-script.ts')
-rw-r--r--packages/integrations/web-vitals/src/client-script.ts36
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);