Can we optimise this script to handle submission of metrics in SPAs

34 views
Skip to first unread message

Basit Qayoom

unread,
Aug 12, 2024, 8:49:53 AM8/12/24
to web-vitals-feedback
import { onLCP, onINP, onCLS, onTTFB, onFCP, Metric } from "web-vitals";

/**
* Represents a timestamp with milliseconds and date.
*
* @interface Timestamp
*/
interface Timestamp {
/**
* The timestamp in milliseconds.
*
* @type {number}
*/
milliseconds: number;

/**
* The timestamp as a Date object.
*
* @type {Date}
*/
date: Date;
}

/**
* Represents the data returned from web vitals metrics.
*
* @interface ReturnedData
*/
interface ReturnedData {
/**
* An array of web vitals metrics.
*
* @type {Metric[]}
*/
data: Metric[];

/**
* The timestamp when the data was collected.
*
* @type {?Timestamp}
*/
timestamp?: Timestamp;

/**
* The location of the page where metrics were collected.
*
* @type {?Location}
*/
location?: Location;
}

/**
* The key used to store web vitals data in local storage.
*
* @type {string}
*/
const LOCAL_STORAGE_KEY = "pw-web-vitals";

/**
* The expiration time for the stored data in milliseconds.
*
* @type {number}
*/
const EXPIRATION_TIME_MS = 1 * 60 * 1000; // 1 minute in milliseconds

// Initialize returnedData properly
/**
* The data structure to store collected web vitals metrics.
*
* @type {ReturnedData}
*/
const returnedData: ReturnedData = {
data: [], // Ensure data is initialized as an array
};

// Handle web vitals metrics
/**
* Handles a web vitals metric by adding it to the returnedData if not already present.
*
* @param {Metric} metric - The web vitals metric to handle.
*/
const handleMetric = (metric: Metric) => {
const { data } = returnedData;

// Initialize location only once
if (!returnedData.location) {
returnedData.location = { ...window.location };
}

// Add new metric if it doesn't already exist and the array length is less than 5
if (
!data.some((existingMetric) => existingMetric.name === metric.name) &&
data.length < 5
) {
data.push(metric);
}

// Update the timestamp and store in local storage if 5 metrics are collected
if (data.length === 5) {
returnedData.timestamp = {
milliseconds: Date.now(),
date: new Date(),
};

saveWebVitalsData();
// send to endpoint
}

// Log the updated returnedData
console.log(returnedData);
};

// Save web vitals data to local storage
/**
* Saves the web vitals data to local storage.
*/
const saveWebVitalsData = () => {
const currentPath = returnedData.location!.pathname;
const timestamp = returnedData.timestamp!.milliseconds;

const storedDataString = localStorage.getItem(LOCAL_STORAGE_KEY);
const webVitalsData: { [path: string]: number } = storedDataString
? JSON.parse(storedDataString)
: {};

// Update or add entry for the current path
webVitalsData[currentPath] = timestamp;

localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(webVitalsData));
};

// Main function to start monitoring metrics
/**
* Starts monitoring web vitals metrics.
*/
function main() {
onCLS(handleMetric);
onFCP(handleMetric);
onLCP(handleMetric);
onTTFB(handleMetric);
onINP(handleMetric);
}

// Initialize monitoring based on local storage data
/**
* Initializes monitoring based on the data stored in local storage.
*/
function initializeMonitoring() {
if (typeof window !== "undefined") {
const webVitalsDataString = localStorage.getItem(LOCAL_STORAGE_KEY);

try {
if (!webVitalsDataString) {
main();
return;
}

const webVitalsData: { [path: string]: number } =
JSON.parse(webVitalsDataString);
const currentPath = window.location.pathname;
const timestamp = webVitalsData[currentPath];

if (timestamp) {
// Check if data is expired
if (Date.now() - timestamp > EXPIRATION_TIME_MS) {
// Remove the expired data
delete webVitalsData[currentPath];
localStorage.setItem(
LOCAL_STORAGE_KEY,
JSON.stringify(webVitalsData)
);

// Start monitoring metrics
main();
}
} else {
// No data for current path, start monitoring metrics
main();
}
} catch (error) {
console.error("Error handling web vitals data:", error);
main();
}
}
}

export { initializeMonitoring };

Barry Pollard

unread,
Aug 12, 2024, 9:01:18 AM8/12/24
to Basit Qayoom, web-vitals-feedback
The Web Vitals currently cannot be measured for soft navigation as used by SPAs.

Chrome is currently experimenting with ways of enabling this, which are detailed in this post:
https://developer.chrome.com/docs/web-platform/soft-navigations-experiment

This can be enabled with the chrome://flags/#enable-experimental-web-platform-features flag.

Thanks,
Barry


--
You received this message because you are subscribed to the Google Groups "web-vitals-feedback" group.
To unsubscribe from this group and stop receiving emails from it, send an email to web-vitals-feed...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/web-vitals-feedback/db0c85d4-edfc-4391-8e35-fcba5190ce22n%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages