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]);
}