Fix: guard Umami tracking and web vitals performance APIs
Avoid calling undefined umami.track, add safe checks for Performance APIs, and clean up load listeners to prevent .call() crashes in Chrome.
This commit is contained in:
@@ -69,6 +69,10 @@ export const AnalyticsProvider: React.FC<AnalyticsProviderProps> = ({ children }
|
|||||||
// Track performance metrics to our API
|
// Track performance metrics to our API
|
||||||
const trackPerformanceToAPI = async () => {
|
const trackPerformanceToAPI = async () => {
|
||||||
try {
|
try {
|
||||||
|
if (typeof performance === "undefined" || typeof performance.getEntriesByType !== "function") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Get current page path to extract project ID if on project page
|
// Get current page path to extract project ID if on project page
|
||||||
const path = window.location.pathname;
|
const path = window.location.pathname;
|
||||||
const projectMatch = path.match(/\/projects\/([^\/]+)/);
|
const projectMatch = path.match(/\/projects\/([^\/]+)/);
|
||||||
@@ -266,6 +270,8 @@ export const AnalyticsProvider: React.FC<AnalyticsProviderProps> = ({ children }
|
|||||||
// Cleanup
|
// Cleanup
|
||||||
return () => {
|
return () => {
|
||||||
try {
|
try {
|
||||||
|
// Remove load handler if we added it
|
||||||
|
window.removeEventListener('load', trackPerformanceToAPI);
|
||||||
window.removeEventListener('popstate', handleRouteChange);
|
window.removeEventListener('popstate', handleRouteChange);
|
||||||
document.removeEventListener('click', handleClick);
|
document.removeEventListener('click', handleClick);
|
||||||
document.removeEventListener('submit', handleSubmit);
|
document.removeEventListener('submit', handleSubmit);
|
||||||
|
|||||||
@@ -25,12 +25,21 @@ export interface WebVitalsMetric {
|
|||||||
|
|
||||||
// Track custom events to Umami
|
// Track custom events to Umami
|
||||||
export const trackEvent = (event: string, data?: Record<string, unknown>) => {
|
export const trackEvent = (event: string, data?: Record<string, unknown>) => {
|
||||||
if (typeof window !== 'undefined' && window.umami) {
|
if (typeof window === "undefined") return;
|
||||||
window.umami.track(event, {
|
const trackFn = window.umami?.track;
|
||||||
|
if (typeof trackFn !== "function") return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
trackFn(event, {
|
||||||
...data,
|
...data,
|
||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
url: window.location.pathname,
|
url: window.location.pathname,
|
||||||
});
|
});
|
||||||
|
} catch (error) {
|
||||||
|
// Silently fail - analytics must never break the app
|
||||||
|
if (process.env.NODE_ENV === "development") {
|
||||||
|
console.warn("Error tracking Umami event:", error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -208,6 +208,13 @@ export const useWebVitals = () => {
|
|||||||
|
|
||||||
// Wrap everything in try-catch to prevent errors from breaking the app
|
// Wrap everything in try-catch to prevent errors from breaking the app
|
||||||
try {
|
try {
|
||||||
|
const safeNow = () => {
|
||||||
|
if (typeof performance !== "undefined" && typeof performance.now === "function") {
|
||||||
|
return performance.now();
|
||||||
|
}
|
||||||
|
return Date.now();
|
||||||
|
};
|
||||||
|
|
||||||
// Store web vitals for batch sending
|
// Store web vitals for batch sending
|
||||||
const webVitals: Record<string, number> = {};
|
const webVitals: Record<string, number> = {};
|
||||||
const path = window.location.pathname;
|
const path = window.location.pathname;
|
||||||
@@ -233,7 +240,7 @@ export const useWebVitals = () => {
|
|||||||
cls: webVitals.CLS || 0,
|
cls: webVitals.CLS || 0,
|
||||||
fid: webVitals.FID || 0,
|
fid: webVitals.FID || 0,
|
||||||
ttfb: webVitals.TTFB || 0,
|
ttfb: webVitals.TTFB || 0,
|
||||||
loadTime: performance.now()
|
loadTime: safeNow()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
@@ -307,7 +314,7 @@ export const useWebVitals = () => {
|
|||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
trackPerformance({
|
trackPerformance({
|
||||||
name: 'page-load-complete',
|
name: 'page-load-complete',
|
||||||
value: performance.now(),
|
value: safeNow(),
|
||||||
url: window.location.pathname,
|
url: window.location.pathname,
|
||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
userAgent: navigator.userAgent,
|
userAgent: navigator.userAgent,
|
||||||
|
|||||||
Reference in New Issue
Block a user