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 App from "./App.tsx";
|
||||||
import "./index.css";
|
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
|
// CRÍTICO: Desregistrar Service Worker en desarrollo ANTES de cualquier otra cosa
|
||||||
// Esto evita que el SW intercepte peticiones de Vite HMR
|
// Esto evita que el SW intercepte peticiones de Vite HMR
|
||||||
if ('serviceWorker' in navigator) {
|
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
|
// Separar node_modules en chunks por librería
|
||||||
if (id.includes('node_modules')) {
|
if (id.includes('node_modules')) {
|
||||||
// React y React DOM juntos (crítico, cargar primero)
|
// 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';
|
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')) {
|
if (id.includes('react-router')) {
|
||||||
return 'vendor-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')) {
|
if (id.includes('react-markdown') || id.includes('remark') || id.includes('rehype') || id.includes('unified') || id.includes('micromark') || id.includes('mdast')) {
|
||||||
return 'vendor-markdown';
|
return 'vendor-markdown';
|
||||||
}
|
}
|
||||||
// Radix UI (componentes UI, agrupar)
|
// Radix UI (componentes UI, agrupar, depende de React)
|
||||||
if (id.includes('@radix-ui')) {
|
if (id.includes('@radix-ui')) {
|
||||||
return 'vendor-ui';
|
return 'vendor-ui';
|
||||||
}
|
}
|
||||||
// TanStack Query
|
// TanStack Query (depende de React)
|
||||||
if (id.includes('@tanstack')) {
|
if (id.includes('@tanstack')) {
|
||||||
return 'vendor-query';
|
return 'vendor-query';
|
||||||
}
|
}
|
||||||
// Icons (lucide-react)
|
// Icons (lucide-react, depende de React)
|
||||||
if (id.includes('lucide-react')) {
|
if (id.includes('lucide-react')) {
|
||||||
return 'vendor-icons';
|
return 'vendor-icons';
|
||||||
}
|
}
|
||||||
// Charts (recharts, si se usa)
|
// Charts (recharts, si se usa, depende de React)
|
||||||
if (id.includes('recharts')) {
|
if (id.includes('recharts')) {
|
||||||
return 'vendor-charts';
|
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')) {
|
if (id.includes('react-hook-form') || id.includes('zod') || id.includes('@hookform')) {
|
||||||
return 'vendor-forms';
|
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')) {
|
if (id.includes('date-fns') || id.includes('react-day-picker')) {
|
||||||
return 'vendor-dates';
|
return 'vendor-dates';
|
||||||
}
|
}
|
||||||
// Carousel (embla)
|
// Carousel (embla, puede depender de React)
|
||||||
if (id.includes('embla')) {
|
if (id.includes('embla')) {
|
||||||
return 'vendor-carousel';
|
return 'vendor-carousel';
|
||||||
}
|
}
|
||||||
// Themes (next-themes)
|
// Themes (next-themes, depende de React)
|
||||||
if (id.includes('next-themes')) {
|
if (id.includes('next-themes')) {
|
||||||
return 'vendor-themes';
|
return 'vendor-themes';
|
||||||
}
|
}
|
||||||
// Sonner (toasts)
|
// Sonner (toasts, depende de React)
|
||||||
if (id.includes('sonner')) {
|
if (id.includes('sonner')) {
|
||||||
return 'vendor-toasts';
|
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';
|
return 'vendor-other';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue