Módulo 3 · Integración: routing, estado, estilos y sesión
Curso 05 · Microfrontends · 150 min
Por qué esto importa en la entrevista
Sección titulada «Por qué esto importa en la entrevista»Montar un remote es fácil; hacer que varios equipos convivan en la misma página sin pisarse es lo difícil. Aquí están los casos que aparecen en producción y en el banco: estilos que se pisan, sesión desincronizada, fugas al desmontar, acoplamiento accidental entre equipos.
El contrato: la pieza central
Sección titulada «El contrato: la pieza central»El contrato de un microfrontend tiene cinco partes, y saber enumerarlas es la respuesta a “¿qué es exactamente el contrato de un MFE?”:
- Punto de montaje: cómo se monta y desmonta (
mount(el, props)/unmount(el)), o el componente expuesto. - Props de entrada: datos que el shell provee (usuario, locale, tema, feature flags, callbacks de navegación).
- Eventos de salida: lo que el remote comunica hacia arriba (navegar, cambio de carrito, error).
- Dependencias compartidas: versiones de React/router/design system que espera.
- Requisitos de entorno: rutas que reclama, permisos, endpoints que consume.
Versiona el contrato como versionarías una API (ver curso 07): añadir props opcionales es compatible; cambiar el significado de una prop o eliminarla es breaking. Y comprueba el contrato en CI con tests de integración o contract tests de UI.
Routing: quién es dueño de la URL
Sección titulada «Routing: quién es dueño de la URL»El patrón sano: el shell posee el enrutado de primer nivel y delega el resto.
/ → shell (home)/catalogo/* → remote catálogo (posee todo lo que hay debajo)/checkout/* → remote checkoutReglas: una única instancia del router (singleton), el shell decide qué remote monta para cada prefijo, y los remotes nunca manipulan window.history directamente — usan la API de navegación que el shell les pasa. Si dos routers escuchan popstate, aparecen dobles renderizados y navegaciones fantasma: es un bug clásico y difícil de depurar.
Enlaces entre microfrontends: por URL (no por importación directa de otro remote), para no acoplar equipos.
Comunicación entre microfrontends: minimízala
Sección titulada «Comunicación entre microfrontends: minimízala»Jerarquía, de mejor a peor:
- Props y callbacks desde el shell. Explícito, tipado, testeable.
- La URL como estado compartido. Filtros, ids, pestañas: es la opción más subestimada y la que mejor sobrevive a recargas.
- Eventos del navegador o un bus mínimo (
CustomEventsobre un canal con nombre y payload versionado) para notificaciones puntuales: “carrito actualizado”. - Estado global compartido (un store común): úsalo solo para datos verdaderamente transversales (sesión, tema, flags). Es acoplamiento fuerte: si el equipo A cambia la forma del estado, rompe al equipo B.
⚠️ Trampa: un store global compartido “para que todo sea más fácil” convierte tus microfrontends en un monolito distribuido con peor depuración. La comunicación excesiva es la señal de que las fronteras están mal trazadas: si dos remotes hablan todo el rato, probablemente deberían ser uno.
Sesión y autenticación
Sección titulada «Sesión y autenticación»Lo que preguntan: “¿dónde vives el token si cada MFE hace llamadas?”.
- El shell es dueño de la sesión. Autentica (OIDC), guarda el token y lo provee: o pasándolo por props/contexto, o —mejor— exponiendo un cliente HTTP compartido que ya inyecta el token, lo refresca y maneja el 401. Así ningún remote toca el token.
- Cookies
HttpOnly+SameSitesi todos los MFE viven bajo el mismo dominio: el navegador lo hace por ti y evitas guardar tokens enlocalStorage(donde cualquier XSS los roba — ver curso 06). - Refresco de token: una sola entidad debe refrescar (el shell), con coalescing para que N peticiones simultáneas no disparen N refrescos.
- Cierre de sesión y expiración: hay que propagarlo a todos los remotes montados (evento global) o quedan mostrando datos de un usuario que ya no está. Ese es el caso 7 del banco.
Aislamiento de estilos
Sección titulada «Aislamiento de estilos»| Técnica | Aislamiento | Coste |
|---|---|---|
| CSS Modules / CSS-in-JS con hash | alto en la práctica | requiere disciplina de build |
Prefijos por equipo (.chk-) |
medio, por convención | fácil de violar |
| Shadow DOM | total | difícil con librerías que inyectan estilos en head, portales, y accesibilidad |
| iframe | total | ver módulo 1 |
Los que fallan siempre: estilos globales (body, *, resets duplicados), z-index sin escala acordada, y variables CSS con el mismo nombre y distinto significado. Un design system con tokens (custom properties) y una escala de z-index documentada resuelve el 90% de los conflictos.
Fugas de memoria al montar/desmontar
Sección titulada «Fugas de memoria al montar/desmontar»Cuando el shell monta y desmonta remotes al navegar, todo lo que el remote registre y no limpie se acumula:
- Listeners globales (
window.addEventListener) sinremoveEventListener. - Timers e intervalos.
- Suscripciones a stores o WebSockets.
- Observadores (
IntersectionObserver,MutationObserver,ResizeObserver). - Nodos DOM retenidos por closures.
Diagnóstico: navega 20 veces entre dos MFEs, fuerza GC en DevTools y compara heap snapshots (Comparison); mira también el contador de listeners y de nodos DOM separados (Detached). El contrato debe exigir un unmount que limpie todo, y el shell debe llamarlo siempre.
Errores comunes que delatan a un no-senior
Sección titulada «Errores comunes que delatan a un no-senior»- Cada remote gestionando su propio token.
- Bus de eventos sin versionar el payload (acoplamiento invisible).
- Dos routers manipulando el historial.
- Estilos globales sin aislamiento y sin tokens.
- No definir
unmountni limpiar suscripciones. - Importar directamente código de otro remote en vez de navegar por URL.
🧪 Laboratorio
Sección titulada «🧪 Laboratorio»- Define el contrato de tus dos remotes en un documento y en tipos TypeScript compartidos (paquete versionado). Rompe una prop a propósito y comprueba que CI lo detecta.
- Sesión compartida: implementa el cliente HTTP del shell con inyección de token y refresco coalescido; simula un token expirado con 3 llamadas simultáneas y verifica que solo hay un refresco.
- Logout global: propaga el cierre de sesión a los remotes montados y comprueba que ninguno sigue mostrando datos privados.
- Colisión de estilos: provoca que un remote pise al otro; arréglalo con CSS Modules y luego con Shadow DOM; anota qué se rompe con Shadow DOM (portales, librerías de UI).
- Fuga al desmontar: añade un
setIntervaly un listener global sin limpiar; reprodúcelo con 20 navegaciones y encuéntralo en los snapshots. Arréglalo.
✅ Autoevaluación
Sección titulada «✅ Autoevaluación»- Enumera las cinco partes del contrato de un MFE.
- ¿Quién es dueño de la URL y por qué no debe haber dos routers?
- Ordena las cuatro formas de comunicación entre MFEs y di cuándo cada una.
- ¿Dónde vive el token y cómo se refresca sin condiciones de carrera?
- Tres formas de aislar CSS con sus trade-offs.
- ¿Cómo diagnosticas una fuga de memoria al navegar entre microfrontends?
🎯 Preguntas del banco que ya puedes responder
Sección titulada «🎯 Preguntas del banco que ya puedes responder»microfrontends/01-fundamentos-y-arquitectura.md— 10, 11, 12, 13, 14, 15microfrontends/02-casos-y-problemas.md— 5 (estilos), 6 (memory leak), 7 (auth desincronizada), 9 (design system)
Anterior: Módulo 2 · Siguiente: Módulo 4 · Operación y performance