navigation-performance-tracker.tsx3.6 KBView on GitHub /**
* Navigation Performance Tracker
*
* Add this to your root layout to track navigation performance
*/
import { perfLogger, perfLog, ENABLE_PERF_LOGGING } from './performance-logger';
import { useLocation, useNavigationType } from 'react-router';
import { useEffect, useRef } from 'react';
// Global click tracker
let lastClickTime = 0;
let lastClickTarget = '';
if (ENABLE_PERF_LOGGING && typeof window !== 'undefined') {
document.addEventListener(
'click',
(e) => {
const target = e.target as HTMLElement;
const link = target.closest('a[href], button[data-nav]');
if (link) {
const href = link.getAttribute('href') || link.getAttribute('data-nav') || 'unknown';
lastClickTime = performance.now();
lastClickTarget = href;
perfLog(
`🖱️ CLICK DETECTED: ${href}`,
'color: #ffffff; background: #0000ff; font-weight: bold; font-size: 16px; padding: 4px 8px;',
`at ${lastClickTime.toFixed(2)}ms`,
);
}
},
true,
); // Use capture phase to catch it early
}
export function NavigationPerformanceTracker() {
const location = useLocation();
const navigationType = useNavigationType();
const previousPathRef = useRef<string | null>(null);
const navigationStartRef = useRef<number>(0);
useEffect(() => {
const currentPath = location.pathname;
const previousPath = previousPathRef.current;
if (previousPath && previousPath !== currentPath) {
// Navigation completed
const duration = performance.now() - navigationStartRef.current;
// Measure from click if available
let fromClick = 0;
if (lastClickTime > 0) {
fromClick = performance.now() - lastClickTime;
}
console.group(
`%c🚀 NAVIGATION COMPLETE: ${previousPath} → ${currentPath}`,
'color: #ff00ff; font-weight: bold; font-size: 16px; background: #000; padding: 4px 8px; border-radius: 4px;',
);
if (fromClick > 0) {
console.log(
`%c⏱️ Total Time from CLICK: ${fromClick.toFixed(2)}ms`,
'font-weight: bold; font-size: 16px; color: #ff0000',
);
console.log(`%cClicked target: ${lastClickTarget}`, 'font-size: 12px');
}
console.log(
`%cTotal Duration (from tracking start): ${duration.toFixed(2)}ms`,
'font-weight: bold; font-size: 14px',
);
console.log(`Navigation Type: ${navigationType}`);
console.log(`From: ${previousPath}`);
console.log(`To: ${currentPath}`);
// Show performance summary
perfLogger.getSummary();
console.groupEnd();
// Clear logs for next navigation
perfLogger.clear();
lastClickTime = 0;
}
// Start tracking next navigation
previousPathRef.current = currentPath;
navigationStartRef.current = performance.now();
perfLogger.start('navigation', {
from: previousPath || 'initial',
to: currentPath,
type: navigationType,
});
}, [location.pathname, navigationType]);
return null;
}
// Hook for manual navigation tracking
export function useNavigationPerformance(componentName: string) {
const mountTimeRef = useRef<number>(0);
const location = useLocation();
useEffect(() => {
const mountTime = performance.now();
mountTimeRef.current = mountTime;
perfLogger.start(`mount:${componentName}`, {
path: location.pathname,
});
return () => {
const unmountTime = performance.now();
const lifetime = unmountTime - mountTimeRef.current;
perfLogger.end(`mount:${componentName}`, {
lifetime: `${lifetime.toFixed(2)}ms`,
});
};
}, [componentName, location.pathname]);
}