fix: corregir errores de React useLayoutEffect y code splitting
- Asegurar que React se carga antes que otros chunks en vite.config.ts - Incluir scheduler en vendor-react para evitar errores de useLayoutEffect - Suprimir errores de extensiones del navegador (message channel closed) - Mejorar manejo de errores en main.tsx con mensajes amigables
This commit is contained in:
parent
6df53a2c88
commit
53fad0c4b0
42
src/main.tsx
42
src/main.tsx
|
|
@ -2,6 +2,24 @@ import { createRoot } from "react-dom/client";
|
|||
import App from "./App.tsx";
|
||||
import "./index.css";
|
||||
|
||||
// Suprimir errores de extensiones del navegador (no críticos)
|
||||
if (typeof window !== 'undefined') {
|
||||
const originalError = console.error;
|
||||
console.error = (...args: any[]) => {
|
||||
// Filtrar errores de extensiones del navegador
|
||||
const message = args[0]?.toString() || '';
|
||||
if (
|
||||
message.includes('message channel closed') ||
|
||||
message.includes('runtime.lastError') ||
|
||||
message.includes('Extension context invalidated')
|
||||
) {
|
||||
// Silenciar estos errores (son de extensiones del navegador, no de nuestra app)
|
||||
return;
|
||||
}
|
||||
originalError.apply(console, args);
|
||||
};
|
||||
}
|
||||
|
||||
// CRÍTICO: Desregistrar Service Worker en desarrollo ANTES de cualquier otra cosa
|
||||
// Esto evita que el SW intercepte peticiones de Vite HMR
|
||||
if ('serviceWorker' in navigator) {
|
||||
|
|
@ -102,4 +120,26 @@ if ('serviceWorker' in navigator) {
|
|||
}
|
||||
}
|
||||
|
||||
createRoot(document.getElementById("root")!).render(<App />);
|
||||
// Asegurar que React está disponible antes de renderizar
|
||||
const rootElement = document.getElementById("root");
|
||||
if (!rootElement) {
|
||||
throw new Error("Root element not found");
|
||||
}
|
||||
|
||||
// Renderizar la app
|
||||
// Nota: Si ves errores de "useLayoutEffect", puede ser un problema de code splitting.
|
||||
// Asegúrate de que vendor-react se carga antes que otros chunks.
|
||||
try {
|
||||
createRoot(rootElement).render(<App />);
|
||||
} catch (error) {
|
||||
console.error('[React] Error rendering app:', error);
|
||||
// Mostrar mensaje de error amigable
|
||||
rootElement.innerHTML = `
|
||||
<div style="padding: 2rem; text-align: center; font-family: sans-serif;">
|
||||
<h1>Error al cargar la aplicación</h1>
|
||||
<p>Por favor, recarga la página. Si el problema persiste, limpia la caché del navegador.</p>
|
||||
<p style="color: #666; font-size: 0.9rem;">Error: ${error instanceof Error ? error.message : String(error)}</p>
|
||||
</div>
|
||||
`;
|
||||
throw error;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,10 +50,11 @@ export default defineConfig({
|
|||
// Separar node_modules en chunks por librería
|
||||
if (id.includes('node_modules')) {
|
||||
// React y React DOM juntos (crítico, cargar primero)
|
||||
if (id.includes('react') || id.includes('react-dom')) {
|
||||
// IMPORTANTE: Debe ser el primer chunk para evitar errores de useLayoutEffect
|
||||
if (id.includes('react') || id.includes('react-dom') || id.includes('scheduler')) {
|
||||
return 'vendor-react';
|
||||
}
|
||||
// React Router (crítico para navegación)
|
||||
// React Router (crítico para navegación, depende de React)
|
||||
if (id.includes('react-router')) {
|
||||
return 'vendor-router';
|
||||
}
|
||||
|
|
@ -61,43 +62,44 @@ export default defineConfig({
|
|||
if (id.includes('react-markdown') || id.includes('remark') || id.includes('rehype') || id.includes('unified') || id.includes('micromark') || id.includes('mdast')) {
|
||||
return 'vendor-markdown';
|
||||
}
|
||||
// Radix UI (componentes UI, agrupar)
|
||||
// Radix UI (componentes UI, agrupar, depende de React)
|
||||
if (id.includes('@radix-ui')) {
|
||||
return 'vendor-ui';
|
||||
}
|
||||
// TanStack Query
|
||||
// TanStack Query (depende de React)
|
||||
if (id.includes('@tanstack')) {
|
||||
return 'vendor-query';
|
||||
}
|
||||
// Icons (lucide-react)
|
||||
// Icons (lucide-react, depende de React)
|
||||
if (id.includes('lucide-react')) {
|
||||
return 'vendor-icons';
|
||||
}
|
||||
// Charts (recharts, si se usa)
|
||||
// Charts (recharts, si se usa, depende de React)
|
||||
if (id.includes('recharts')) {
|
||||
return 'vendor-charts';
|
||||
}
|
||||
// Formularios (react-hook-form, zod)
|
||||
// Formularios (react-hook-form, zod, depende de React)
|
||||
if (id.includes('react-hook-form') || id.includes('zod') || id.includes('@hookform')) {
|
||||
return 'vendor-forms';
|
||||
}
|
||||
// Date/time (date-fns, react-day-picker)
|
||||
// Date/time (date-fns, react-day-picker, depende de React)
|
||||
if (id.includes('date-fns') || id.includes('react-day-picker')) {
|
||||
return 'vendor-dates';
|
||||
}
|
||||
// Carousel (embla)
|
||||
// Carousel (embla, puede depender de React)
|
||||
if (id.includes('embla')) {
|
||||
return 'vendor-carousel';
|
||||
}
|
||||
// Themes (next-themes)
|
||||
// Themes (next-themes, depende de React)
|
||||
if (id.includes('next-themes')) {
|
||||
return 'vendor-themes';
|
||||
}
|
||||
// Sonner (toasts)
|
||||
// Sonner (toasts, depende de React)
|
||||
if (id.includes('sonner')) {
|
||||
return 'vendor-toasts';
|
||||
}
|
||||
// Resto de node_modules pequeños
|
||||
// Resto de node_modules pequeños (NO incluir nada que dependa de React)
|
||||
// Si algo aquí usa React, moverlo arriba
|
||||
return 'vendor-other';
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue