Skip to content

Instantly share code, notes, and snippets.

@mmocny
Last active April 26, 2024 14:04
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mmocny/498bb7311ad944247feb090a9f26e848 to your computer and use it in GitHub Desktop.
Save mmocny/498bb7311ad944247feb090a9f26e848 to your computer and use it in GitHub Desktop.
Measure FCP/LCP + Soft Navs
const RATING_COLORS = {
"good": "#0CCE6A",
"needs-improvement": "#FFA400",
"poor": "#FF4E42",
"invalid": "#FFC0CB",
"default": "inherit", // Will default to this, anyway
};
function log(metric) {
const prettyScore = metric.value.toLocaleString(undefined, { maximumFractionDigits: 0 });
console.groupCollapsed(
`[${metric.name}] %c${prettyScore} ms (${
metric.rating
})`,
`color: ${RATING_COLORS[metric.rating] || "inherit"}`
);
console.log(metric);
console.log(...metric.entries);
console.groupEnd();
}
function getNavigationEntry(navigationId) {
const navs = [...performance.getEntriesByType('navigation'), ...performance.getEntriesByType('soft-navigation')];
// console.log(navs, navigationId);
return navs.filter(nav => nav.navigationId == navigationId)[0];
};
const valueToRating = (score) =>
score <= 0 ? "invalid" : score <= 2500 ? "good" : score <= 4000 ? "needs-improvement" : "poor";
// TODO: Ignore non-soft LCP.
const observer = new PerformanceObserver((entryList) => {
for (const paintEntry of entryList.getEntries()) {
const navEntry = getNavigationEntry(paintEntry.navigationId);
const name = `Soft.${(paintEntry.name || paintEntry.entryType).split('-').map((s)=>s[0].toUpperCase()).join('')}`;
const value = paintEntry.startTime - navEntry.startTime;
const metric = {
attribution: {
navEntry,
paintEntry,
pageUrl: navEntry.name,
elementUrl: paintEntry.url,
},
entries: [paintEntry],
name,
rating: valueToRating(value),
value,
};
performance.measure(name, {
start: navEntry.startTime,
end: paintEntry.startTime,
});
log(metric);
}
});
observer.observe({
type: 'paint',
buffered: true,
includeSoftNavigationObservations: true,
});
observer.observe({
type: 'largest-contentful-paint',
buffered: true,
includeSoftNavigationObservations: true,
});
const observer2 = new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
const name = `Soft.Nav`;
const value = entry.duration;
const metric = {
attribution: {
navEntry: entry,
pageUrl: entry.name,
},
entries: [entry],
name,
rating: "default",
value,
};
performance.measure(name, {
start: entry.startTime,
duration: entry.duration,
})
log(metric);
}
});
observer2.observe({
type: 'soft-navigation',
buffered: true,
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment