Ejercicio: Construir un Sistema de Notificaciones Federado

Video
30 min~5 min lectura

Reproductor de video

Concepto clave

En arquitecturas de micro-frontends, la comunicacion entre aplicaciones federadas y el manejo de estado compartido son desafios criticos. Un sistema de notificaciones federado permite que diferentes micro-frontends se comuniquen de forma desacoplada, similar a como un sistema de mensajeria corporativa conecta departamentos independientes sin que cada uno conozca los detalles internos de los otros.

Module Federation de Webpack habilita este patron mediante la exposicion y consumo de modulos entre aplicaciones. El estado compartido se gestiona tipicamente a traves de un event bus o un store global accesible por todos los micro-frontends, manteniendo la autonomia de cada aplicacion mientras permiten interacciones coordinadas.

Como funciona en la practica

Imagina tres micro-frontends: una aplicacion principal (shell), un panel de usuario y un sistema de alertas. El shell expone un modulo de notificaciones que otros consumen. Paso a paso:

  1. El shell configura Module Federation para exponer un modulo notifications.
  2. El panel de usuario consume este modulo y registra eventos (ej: "usuario-actualizado").
  3. El sistema de alertas tambien consume el modulo y escucha esos eventos para mostrar notificaciones.
  4. Cuando el panel de usuario dispara un evento, el sistema de alertas reacciona sin acoplamiento directo.

Esto se implementa usando Webpack 5 con configuraciones especificas en cada aplicacion, compartiendo codigo en tiempo de ejecucion.

Codigo en accion

Configuracion del shell (aplicacion principal) que expone el modulo de notificaciones:

// webpack.config.js del shell
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");

module.exports = {
  // ... otras configuraciones
  plugins: [
    new ModuleFederationPlugin({
      name: "shell",
      filename: "remoteEntry.js",
      exposes: {
        "./notifications": "./src/notifications/eventBus.js",
      },
      shared: ["react", "react-dom"],
    }),
  ],
};

// src/notifications/eventBus.js
export class EventBus {
  constructor() {
    this.listeners = {};
  }

  emit(event, data) {
    if (this.listeners[event]) {
      this.listeners[event].forEach(callback => callback(data));
    }
  }

  on(event, callback) {
    if (!this.listeners[event]) this.listeners[event] = [];
    this.listeners[event].push(callback);
  }
}

export const eventBus = new EventBus();

Consumo desde un micro-frontend (panel de usuario):

// webpack.config.js del panel de usuario
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");

module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      name: "userPanel",
      remotes: {
        shell: "shell@http://localhost:3000/remoteEntry.js",
      },
      shared: ["react", "react-dom"],
    }),
  ],
};

// Componente que usa el modulo federado
import React, { useEffect } from "react";

const UserPanel = () => {
  useEffect(() => {
    import("shell/notifications").then(module => {
      const { eventBus } = module;
      // Emitir evento cuando el usuario se actualiza
      eventBus.emit("usuario-actualizado", { userId: 123, action: "edit" });
    });
  }, []);

  return 
Panel de Usuario
; }; export default UserPanel;

Errores comunes

  • Ciclos de dependencia: Configurar remotes de forma circular entre aplicaciones, causando errores de carga. Solucion: Diseñar una topologia jerarquica clara.
  • Versionado inconsistente: Compartir librerias como React con versiones diferentes, llevando a errores en runtime. Solucion: Usar shared con versiones exactas y estrategias de resolución.
  • Eventos no tipados: Emitir eventos sin estructura definida, dificultando el debug. Solucion: Definir contratos de eventos con TypeScript o documentacion.
  • Falta de manejo de errores: No capturar fallos en la carga de modulos remotos. Solucion: Implementar retries y estados de fallback.
  • Acoplamiento excesivo: Micro-frontends que dependen demasiado de detalles internos de otros. Solucion: Limitar la comunicacion a eventos genericos y APIs publicas.

Checklist de dominio

  1. Configurar Module Federation para exponer y consumir modulos entre al menos dos aplicaciones.
  2. Implementar un event bus o store global accesible via modulos federados.
  3. Manejar ciclos de vida de modulos remotos (carga, error, actualizacion).
  4. Garantizar consistencia en dependencias compartidas (ej: React, estado).
  5. Diseñar una estrategia de versionado para modulos federados.
  6. Probar la comunicacion en diferentes entornos (dev, prod).
  7. Documentar los contratos de eventos y APIs expuestas.

Implementar un Sistema de Notificaciones Federado entre Tres Micro-frontends

En este ejercicio, construiras un sistema de notificaciones que permita a tres micro-frontends independientes comunicarse usando Module Federation de Webpack. Sigue estos pasos:

  1. Configura el entorno: Crea tres aplicaciones React independientes (shell, userPanel, alertSystem) con Webpack 5. Instala Module Federation via npm install webpack webpack-cli webpack-dev-server.
  2. Configura el shell: En la aplicacion shell, configura Module Federation para exponer un modulo notifications que contenga un event bus. Usa el codigo de ejemplo de la leccion como base.
  3. Configura los micro-frontends: En userPanel y alertSystem, configura Module Federation para consumir el modulo notifications del shell. Asegurate de que compartan dependencias como React correctamente.
  4. Implementa la comunicacion: En userPanel, agrega un boton que, al hacer clic, emita un evento "usuario-actualizado" via el event bus. En alertSystem, escucha este evento y muestra una notificacion en la interfaz (ej: un mensaje emergente).
  5. Prueba la integracion: Ejecuta las tres aplicaciones en puertos diferentes (ej: 3000, 3001, 3002) y verifica que la notificacion se muestre correctamente cuando se activa el evento.
  6. Agrega manejo de errores: Implementa un fallback en alertSystem en caso de que el modulo notifications no cargue, mostrando un mensaje de error amigable.
  7. Documenta el flujo: Crea un diagrama simple que muestre como los eventos fluyen entre las aplicaciones y anade comentarios al codigo explicando las decisiones clave.
Pistas
  • Usa Webpack Dev Server con diferentes puertos para cada aplicacion y configura CORS si es necesario.
  • Considera usar una libreria como "events" para el event bus si prefieres no implementarlo desde cero, pero exponla via Module Federation.
  • Para compartir estado mas complejo, explora opciones como Redux o Zustand federados, pero empieza con un event bus simple.

Evalua tu comprension

Completa el quiz interactivo de arriba para ganar XP.