nano-insights
Version:
A framework-agnostic performance monitoring component to fetch and display web page speed insights using tools like Google PageSpeed Insights.
221 lines (219 loc) • 7.78 kB
JavaScript
;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var __decorateClass = (decorators, target, key, kind) => {
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
for (var i = decorators.length - 1, decorator; i >= 0; i--)
if (decorator = decorators[i])
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
if (kind && result) __defProp(target, key, result);
return result;
};
// src/index.ts
var index_exports = {};
__export(index_exports, {
NanoInsights: () => NanoInsights
});
module.exports = __toCommonJS(index_exports);
var import_lit = require("lit");
var import_decorators = require("lit/decorators.js");
var NanoInsights = class extends import_lit.LitElement {
constructor() {
super();
this.projectKey = "";
this.sessionId = typeof localStorage !== "undefined" && localStorage.getItem("nanoInsightsSessionId") || typeof crypto !== "undefined" && crypto.randomUUID && crypto.randomUUID() || Math.random().toString(36).slice(2);
if (typeof localStorage !== "undefined") {
localStorage.setItem("nanoInsightsSessionId", this.sessionId);
}
}
connectedCallback() {
super.connectedCallback();
this.trackWebVitals();
}
disconnectedCallback() {
super.disconnectedCallback();
}
trackWebVitals() {
this.trackLCP();
this.trackFID();
this.trackCLS();
this.trackTTFB();
this.trackFCP();
this.trackNavigationTiming();
}
trackLCP() {
if (!PerformanceObserver) return;
const lcpObserver = new PerformanceObserver((entryList) => {
const entries = entryList.getEntries();
const lastEntry = entries[entries.length - 1];
if (document.readyState === "complete") {
const lcp = lastEntry.startTime;
this.sendToApi({
metric_type: "web_vital",
metric_name: "LCP",
metric_value: lcp,
metric_unit: "ms"
});
lcpObserver.disconnect();
}
});
lcpObserver.observe({ type: "largest-contentful-paint", buffered: true });
}
trackFID() {
if (!PerformanceObserver) return;
const fidObserver = new PerformanceObserver((entryList) => {
const entries = entryList.getEntries();
entries.forEach((entry) => {
const fidEntry = entry;
if (fidEntry.processingStart) {
const fid = fidEntry.processingStart - fidEntry.startTime;
this.sendToApi({
metric_type: "web_vital",
metric_name: "FID",
metric_value: fid,
metric_unit: "ms"
});
}
});
});
fidObserver.observe({ type: "first-input", buffered: true });
}
trackCLS() {
if (!PerformanceObserver) return;
let clsValue = 0;
let clsEntries = [];
const clsObserver = new PerformanceObserver((entryList) => {
const entries = entryList.getEntries();
entries.forEach((entry) => {
const layoutShiftEntry = entry;
if (layoutShiftEntry.hadRecentInput === false && typeof layoutShiftEntry.value === "number") {
clsValue += layoutShiftEntry.value;
clsEntries.push(entry);
}
});
});
clsObserver.observe({ type: "layout-shift", buffered: true });
const reportCLS = () => {
if (clsEntries.length > 0) {
this.sendToApi({
metric_type: "web_vital",
metric_name: "CLS",
metric_value: clsValue,
metric_unit: ""
});
}
};
["visibilitychange", "beforeunload"].forEach((type) => {
window.addEventListener(type, reportCLS, { once: true });
});
}
trackTTFB() {
window.addEventListener("load", () => {
if (performance && performance.getEntriesByType) {
const navEntries = performance.getEntriesByType("navigation");
if (navEntries.length > 0) {
const navEntry = navEntries[0];
const ttfb = navEntry.responseStart;
this.sendToApi({
metric_type: "web_vital",
metric_name: "TTFB",
metric_value: ttfb,
metric_unit: "ms"
});
}
}
});
}
trackFCP() {
if (!PerformanceObserver) return;
const fcpObserver = new PerformanceObserver((entryList) => {
const entries = entryList.getEntries();
entries.forEach((entry) => {
const fcp = entry.startTime;
this.sendToApi({
metric_type: "web_vital",
metric_name: "FCP",
metric_value: fcp,
metric_unit: "ms"
});
fcpObserver.disconnect();
});
});
fcpObserver.observe({ type: "paint", buffered: true });
}
trackNavigationTiming() {
window.addEventListener("load", () => {
if (performance && performance.getEntriesByType) {
const navEntries = performance.getEntriesByType("navigation");
if (navEntries.length > 0) {
const navEntry = navEntries[0];
this.sendToApi({
metric_type: "navigation_timing",
dns_lookup: navEntry.domainLookupEnd - navEntry.domainLookupStart,
tcp_connection: navEntry.connectEnd - navEntry.connectStart,
server_response: navEntry.responseEnd - navEntry.responseStart,
dom_interactive: navEntry.domInteractive - navEntry.responseEnd,
dom_complete: navEntry.domComplete - navEntry.domInteractive,
page_load: navEntry.loadEventEnd - navEntry.loadEventStart,
total_page_load: navEntry.loadEventEnd
});
}
}
});
}
sendToApi(data) {
fetch("https://www.nanosights.dev/api/tags/insights", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(__spreadValues({
projectKey: this.projectKey,
sessionId: this.sessionId,
userAgent: navigator.userAgent,
referrer: document.referrer,
url: window.location.href,
page_title: document.title,
page_path: window.location.pathname,
timestamp: (/* @__PURE__ */ new Date()).toISOString()
}, data))
});
}
};
__decorateClass([
(0, import_decorators.property)({ type: String })
], NanoInsights.prototype, "projectKey", 2);
NanoInsights = __decorateClass([
(0, import_decorators.customElement)("nano-insights")
], NanoInsights);
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
NanoInsights
});