codigo0/docs/SOLUCION_DEFINITIVA_USELAYOUTEFFECT.md
planetazuzu d80f1947f5 fix: solución definitiva para error useLayoutEffect en producción
PROBLEMA RESUELTO:
- hast-util-to-jsx-runtime estaba en vendor-utils pero necesita React
- Orden de carga de chunks incorrecto
- Posibles múltiples instancias de React

SOLUCIÓN IMPLEMENTADA:

1. vite.config.ts - Clasificación correcta:
   - hast-util-to-jsx-runtime movido a vendor-react (usa React)
   - Alias explícitos de React para una sola instancia
   - optimizeDeps mejorado con todas las dependencias React
   - Orden de carga de chunks (vendor-react primero)

2. package.json - Overrides:
   - Fuerza una sola versión de React en todas las dependencias

3. scripts/diagnose-react.js (nuevo):
   - Script de diagnóstico para verificar configuración

4. docs/SOLUCION_DEFINITIVA_USELAYOUTEFFECT.md:
   - Documentación completa de la solución

RESULTADO:
 Una sola instancia de React
 Orden de carga correcto
 Todas las dependencias React clasificadas
 Sin errores useLayoutEffect
 Build estable
2026-01-02 19:26:03 +01:00

5.8 KiB

🔧 Solución Definitiva: Error useLayoutEffect en Producción

Problema Identificado

Uncaught TypeError: Cannot read properties of undefined (reading 'useLayoutEffect')
at vendor-other-*.js

Causa Raíz

El error ocurre porque:

  1. hast-util-to-jsx-runtime (dependencia de react-markdown) usa React pero estaba siendo clasificado como vendor-utils
  2. Orden de carga incorrecto: Los chunks se cargaban en orden aleatorio, permitiendo que código que necesita React se ejecute antes de que React esté disponible
  3. Múltiples instancias potenciales: Sin alias explícitos, diferentes partes del bundle podían resolver React desde diferentes ubicaciones

Solución Implementada

1. Clasificación Correcta de Dependencias (vite.config.ts)

Cambio crítico:

// CRÍTICO: hast-util-to-jsx-runtime USA React - debe estar en vendor-react
if (id.includes('hast-util-to-jsx-runtime')) {
  return 'vendor-react';
}

Razón: hast-util-to-jsx-runtime convierte HTML a JSX usando React, por lo que necesita React disponible cuando se carga.

2. Alias Explícitos de React (vite.config.ts)

resolve: {
  alias: {
    "@": path.resolve(__dirname, "./src"),
    // CRÍTICO: Forzar alias de React para asegurar una sola instancia
    "react": path.resolve(__dirname, "./node_modules/react"),
    "react-dom": path.resolve(__dirname, "./node_modules/react-dom"),
    "react/jsx-runtime": path.resolve(__dirname, "./node_modules/react/jsx-runtime.js"),
  },
  dedupe: ["react", "react-dom", "react/jsx-runtime"],
}

Razón: Garantiza que todas las importaciones de React resuelven a la misma instancia física.

3. OptimizeDeps Mejorado (vite.config.ts)

optimizeDeps: {
  include: [
    "react",
    "react-dom",
    "react/jsx-runtime",
    "react-markdown",
    "hast-util-to-jsx-runtime",
    "use-sidecar",
    "use-callback-ref",
    "@radix-ui/react-use-callback-ref",
    "react-router-dom",
    "@tanstack/react-query",
  ],
  esbuildOptions: {
    target: "es2020",
    jsx: "automatic",
  },
}

Razón: Pre-bundlea todas las dependencias React para que estén disponibles inmediatamente.

4. Overrides en package.json

"overrides": {
  "react": "^18.3.1",
  "react-dom": "^18.3.1"
}

Razón: Fuerza que todas las dependencias (incluso transitivas) usen la misma versión de React.

5. Orden de Carga de Chunks (vite.config.ts)

chunkFileNames: (chunkInfo) => {
  // vendor-react debe tener prioridad en el nombre para cargarse primero
  if (chunkInfo.name === 'vendor-react') {
    return 'assets/vendor-react-[hash].js';
  }
  return 'assets/[name]-[hash].js';
}

Razón: Asegura que vendor-react se carga antes que otros chunks.

🧪 Verificación

1. Verificar Configuración

node scripts/diagnose-react.js

Debería mostrar:

  • Versiones de React consistentes
  • overrides configurado
  • dedupe configurado
  • alias de React configurado
  • hast-util-to-jsx-runtime clasificado

2. Build y Verificación

npm run build

Debería:

  • Completar sin errores
  • NO generar vendor-other
  • Generar vendor-react, vendor-utils, vendor-markdown
  • Verificación post-build pasar

3. Verificar en Producción

  1. Abrir DevTools > Network

  2. Recargar la página

  3. Verificar orden de carga:

    • vendor-react-*.js debe cargarse PRIMERO
    • Luego vendor-utils-*.js y vendor-markdown-*.js
    • NO debe aparecer vendor-other-*.js
  4. Verificar en Console:

    • NO debe aparecer el error useLayoutEffect
    • NO debe haber warnings sobre React duplicado

🔍 Troubleshooting

Si el error persiste

  1. Limpiar completamente:

    rm -rf node_modules package-lock.json dist
    npm install
    npm run build
    
  2. Verificar que no hay React duplicado:

    npm ls react react-dom
    

    Debe mostrar solo una versión de cada uno.

  3. Verificar chunks generados:

    ls -la dist/assets/ | grep vendor
    

    NO debe aparecer vendor-other.

  4. Limpiar caché del navegador:

    • Ver docs/LIMPIAR_CACHE_NAVEGADOR.md

Si el build falla

  1. Revisar logs:

    npm run build 2>&1 | grep -i "error\|unclassified"
    
  2. Añadir dependencia no clasificada:

    • Si aparece una dependencia sin clasificar, añadirla a vite.config.ts
    • Si usa React → vendor-react
    • Si NO usa React → vendor-utils

📋 Checklist Pre-Deploy

  • npm run build pasa sin errores
  • node scripts/diagnose-react.js muestra todo
  • node scripts/verify-build.js pasa
  • NO se genera vendor-other
  • vendor-react se carga primero (verificar en Network tab)
  • No hay errores useLayoutEffect en Console
  • Docker build pasa sin errores

🎯 Resultado Esperado

Después de aplicar esta solución:

Una sola instancia de React en todo el bundle
Orden de carga correcto: vendor-react primero
Todas las dependencias React clasificadas correctamente
Sin errores useLayoutEffect
Build estable y reproducible

📝 Archivos Modificados

  1. vite.config.ts

    • Alias explícitos de React
    • Clasificación de hast-util-to-jsx-runtime en vendor-react
    • optimizeDeps mejorado
    • Orden de carga de chunks
  2. package.json

    • Añadido overrides para React
  3. scripts/diagnose-react.js (nuevo)

    • Script de diagnóstico
  4. scripts/verify-build.js (mejorado)

    • Verificación post-build

🔗 Referencias