Fix white screen: add error boundaries and improve error handling in AnalyticsProvider and useWebVitals
This commit is contained in:
@@ -4,6 +4,7 @@ import React, { useEffect, useState } from "react";
|
||||
import { usePathname } from "next/navigation";
|
||||
import dynamic from "next/dynamic";
|
||||
import { ToastProvider } from "@/components/Toast";
|
||||
import ErrorBoundary from "@/components/ErrorBoundary";
|
||||
import { AnalyticsProvider } from "@/components/AnalyticsProvider";
|
||||
|
||||
// Dynamic import with SSR disabled to avoid framer-motion issues
|
||||
@@ -46,13 +47,20 @@ export default function ClientProviders({
|
||||
};
|
||||
}, [pathname]);
|
||||
|
||||
// Wrap in multiple error boundaries to isolate failures
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
<ErrorBoundary>
|
||||
<AnalyticsProvider>
|
||||
<ErrorBoundary>
|
||||
<ToastProvider>
|
||||
{mounted && <BackgroundBlobs />}
|
||||
<div className="relative z-10">{children}</div>
|
||||
{mounted && !is404Page && <ChatWidget />}
|
||||
</ToastProvider>
|
||||
</ErrorBoundary>
|
||||
</AnalyticsProvider>
|
||||
</ErrorBoundary>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -9,12 +9,16 @@ interface AnalyticsProviderProps {
|
||||
}
|
||||
|
||||
export const AnalyticsProvider: React.FC<AnalyticsProviderProps> = ({ children }) => {
|
||||
// Initialize Web Vitals tracking
|
||||
// Initialize Web Vitals tracking - wrapped to prevent crashes
|
||||
// Hooks must be called unconditionally, but the hook itself handles errors
|
||||
useWebVitals();
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof window === 'undefined') return;
|
||||
|
||||
// Wrap entire effect in try-catch to prevent any errors from breaking the app
|
||||
try {
|
||||
|
||||
// Track page view
|
||||
const trackPageView = async () => {
|
||||
const path = window.location.pathname;
|
||||
@@ -49,8 +53,15 @@ export const AnalyticsProvider: React.FC<AnalyticsProviderProps> = ({ children }
|
||||
}
|
||||
};
|
||||
|
||||
// Track page load performance
|
||||
// Track page load performance - wrapped in try-catch
|
||||
try {
|
||||
trackPageLoad();
|
||||
} catch (error) {
|
||||
// Silently fail
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
console.warn('Error tracking page load:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Track initial page view
|
||||
trackPageView();
|
||||
@@ -257,14 +268,27 @@ export const AnalyticsProvider: React.FC<AnalyticsProviderProps> = ({ children }
|
||||
|
||||
// Cleanup
|
||||
return () => {
|
||||
try {
|
||||
window.removeEventListener('popstate', handleRouteChange);
|
||||
document.removeEventListener('click', handleClick);
|
||||
document.removeEventListener('submit', handleSubmit);
|
||||
window.removeEventListener('scroll', handleScroll);
|
||||
window.removeEventListener('error', handleError);
|
||||
window.removeEventListener('unhandledrejection', handleUnhandledRejection);
|
||||
} catch {
|
||||
// Silently fail during cleanup
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
// If anything fails, log but don't break the app
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
console.error('AnalyticsProvider initialization error:', error);
|
||||
}
|
||||
// Return empty cleanup function
|
||||
return () => {};
|
||||
}
|
||||
}, []);
|
||||
|
||||
// Always render children, even if analytics fails
|
||||
return <>{children}</>;
|
||||
};
|
||||
|
||||
@@ -22,18 +22,20 @@ export default class ErrorBoundary extends React.Component<
|
||||
|
||||
render() {
|
||||
if (this.state.hasError) {
|
||||
// Still render children to prevent white screen - just log the error
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
return (
|
||||
<div className="p-4 m-4 bg-red-50 border border-red-200 rounded text-red-800">
|
||||
<h2>Something went wrong!</h2>
|
||||
<button
|
||||
className="mt-2 px-4 py-2 bg-red-600 text-white rounded hover:bg-red-700"
|
||||
onClick={() => this.setState({ hasError: false })}
|
||||
>
|
||||
Try again
|
||||
</button>
|
||||
<div>
|
||||
<div className="p-2 m-2 bg-yellow-50 border border-yellow-200 rounded text-yellow-800 text-xs">
|
||||
⚠️ Error boundary triggered - rendering children anyway
|
||||
</div>
|
||||
{this.props.children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
// In production, just render children silently
|
||||
return this.props.children;
|
||||
}
|
||||
|
||||
return this.props.children;
|
||||
}
|
||||
|
||||
@@ -206,6 +206,8 @@ export const useWebVitals = () => {
|
||||
useEffect(() => {
|
||||
if (typeof window === 'undefined') return;
|
||||
|
||||
// Wrap everything in try-catch to prevent errors from breaking the app
|
||||
try {
|
||||
// Store web vitals for batch sending
|
||||
const webVitals: Record<string, number> = {};
|
||||
const path = window.location.pathname;
|
||||
@@ -328,7 +330,19 @@ export const useWebVitals = () => {
|
||||
// Silently fail
|
||||
}
|
||||
});
|
||||
try {
|
||||
window.removeEventListener('load', handleLoad);
|
||||
} catch {
|
||||
// Silently fail
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
// If Web Vitals initialization fails, don't break the app
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
console.warn('Web Vitals initialization failed:', error);
|
||||
}
|
||||
// Return empty cleanup function
|
||||
return () => {};
|
||||
}
|
||||
}, []);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user