Skip to content

Commit d2d5660

Browse files
committed
feat: add core CWV measurement scripts (LCP, CLS, INP)
1 parent 097ec5c commit d2d5660

3 files changed

Lines changed: 632 additions & 0 deletions

File tree

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// CLS Quick Check
2+
// https://webperf-snippets.nucliweb.net
3+
4+
(() => {
5+
let cls = 0;
6+
7+
const valueToRating = (score) =>
8+
score <= 0.1 ? "good" : score <= 0.25 ? "needs-improvement" : "poor";
9+
10+
const RATING = {
11+
good: { icon: "🟢", color: "#0CCE6A" },
12+
"needs-improvement": { icon: "🟡", color: "#FFA400" },
13+
poor: { icon: "🔴", color: "#FF4E42" },
14+
};
15+
16+
const logCLS = () => {
17+
const rating = valueToRating(cls);
18+
const { icon, color } = RATING[rating];
19+
console.log(
20+
`%cCLS: ${icon} ${cls.toFixed(4)} (${rating})`,
21+
`color: ${color}; font-weight: bold; font-size: 14px;`
22+
);
23+
};
24+
25+
const observer = new PerformanceObserver((list) => {
26+
for (const entry of list.getEntries()) {
27+
if (!entry.hadRecentInput) {
28+
cls += entry.value;
29+
}
30+
}
31+
logCLS();
32+
});
33+
34+
observer.observe({ type: "layout-shift", buffered: true });
35+
36+
// Update on visibility change (final CLS)
37+
document.addEventListener("visibilitychange", () => {
38+
if (document.visibilityState === "hidden") {
39+
observer.takeRecords();
40+
console.log("%c📊 Final CLS (on page hide):", "font-weight: bold;");
41+
logCLS();
42+
}
43+
});
44+
45+
// Expose function for manual check
46+
window.getCLS = () => {
47+
logCLS();
48+
const rating = valueToRating(cls);
49+
return {
50+
script: "CLS",
51+
status: "ok",
52+
metric: "CLS",
53+
value: Math.round(cls * 10000) / 10000,
54+
unit: "score",
55+
rating,
56+
thresholds: { good: 0.1, needsImprovement: 0.25 },
57+
};
58+
};
59+
60+
console.log(
61+
" Call %cgetCLS()%c anytime to check current value.",
62+
"font-family: monospace; background: #f3f4f6; padding: 2px 4px;",
63+
""
64+
);
65+
66+
// Synchronous return for agent (buffered entries)
67+
const clsSync = performance.getEntriesByType("layout-shift")
68+
.reduce((sum, e) => !e.hadRecentInput ? sum + e.value : sum, 0);
69+
const clsRating = valueToRating(clsSync);
70+
return {
71+
script: "CLS",
72+
status: "ok",
73+
metric: "CLS",
74+
value: Math.round(clsSync * 10000) / 10000,
75+
unit: "score",
76+
rating: clsRating,
77+
thresholds: { good: 0.1, needsImprovement: 0.25 },
78+
};
79+
})();

0 commit comments

Comments
 (0)