// Optimized bootstrap process - import CSS before JS for better paint performance import "./index.css"; import { createRoot } from "react-dom/client"; import App from "./App"; // Type declarations for performance metrics interface PerfMetrics { startTime: number; logPerformance: () => void; } // Add window augmentation for custom properties declare global { interface Window { perfMetrics?: PerfMetrics; } // Fix for requestIdleCallback // Already defined in lib.dom.d.ts but ensuring compatibility interface PerformanceEntry { // Layout Shift API hadRecentInput?: boolean; value?: number; } } // Immediately invoke the render function for faster startup // Use an IIFE to prevent global scope pollution (function () { // Start performance measurement const startTime = performance.now(); // Get the root element with non-null assertion (verified in HTML structure) const appRoot = document.getElementById("root"); if (!appRoot) { console.error("Root element not found"); return; } // Create root only once - improves performance by avoiding repeat calculations const root = createRoot(appRoot); // Directly render the app without StrictMode in production // This reduces double-rendering and improves initial load performance root.render(); // Register callback to track performance metrics after initial render queueMicrotask(() => { const initialRenderTime = performance.now() - startTime; console.debug(`Initial render in ${initialRenderTime.toFixed(2)}ms`); }); // Comprehensive performance monitoring after full page load window.addEventListener('load', () => { // Use the globally defined performance metrics object from index.html if (window.perfMetrics && typeof window.perfMetrics.startTime === 'number') { const loadTime = performance.now() - window.perfMetrics.startTime; console.log(`Total load in ${loadTime.toFixed(2)}ms`); } // Report core web vitals after a small delay to ensure they're available if ('performance' in window && 'getEntriesByType' in performance) { // Use setTimeout fallback for non-critical metrics - avoid requestIdleCallback type issues const scheduleIdleTask = (cb: IdleRequestCallback) => { setTimeout(() => cb({ didTimeout: false, timeRemaining: () => 50 }), 50); }; scheduleIdleTask(() => { // First Contentful Paint and First Paint const paintMetrics = performance.getEntriesByType('paint'); paintMetrics.forEach(metric => { console.debug(`${metric.name}: ${metric.startTime.toFixed(0)}ms`); }); // Track LCP using PerformanceObserver with a cleaner implementation if (PerformanceObserver.supportedEntryTypes?.includes('largest-contentful-paint')) { const lcpObserver = new PerformanceObserver((entryList) => { const entries = entryList.getEntries(); if (entries.length > 0) { const lastEntry = entries[entries.length - 1]; console.debug(`LCP: ${lastEntry.startTime.toFixed(0)}ms`); // Disconnect observer after getting the final LCP value lcpObserver.disconnect(); } }); // Only observe LCP events lcpObserver.observe({ type: 'largest-contentful-paint', buffered: true }); } // Track CLS (Cumulative Layout Shift) if (PerformanceObserver.supportedEntryTypes?.includes('layout-shift')) { let cumulativeLayoutShift = 0; const layoutShiftObserver = new PerformanceObserver((entryList) => { for (const entry of entryList.getEntries()) { // Type assertion for layout shift entries const layoutShiftEntry = entry as PerformanceEntry & { hadRecentInput?: boolean; value?: number; }; // Only count layout shifts without recent user input if (layoutShiftEntry.hadRecentInput === false && typeof layoutShiftEntry.value === 'number') { cumulativeLayoutShift += layoutShiftEntry.value; } } console.debug(`CLS: ${cumulativeLayoutShift.toFixed(3)}`); }); layoutShiftObserver.observe({ type: 'layout-shift', buffered: true }); } }); } }); })();