Concepto clave
Los componentes federados son módulos de UI que se desarrollan, despliegan y ejecutan de forma independiente, pero que pueden ser consumidos dinámicamente por otras aplicaciones en tiempo de ejecución. Imagina una ciudad donde cada edificio (micro-frontend) tiene su propia administración y reglas, pero comparten servicios públicos (componentes federados) como parques o bibliotecas que cualquier residente puede usar sin necesidad de construirlos desde cero.
La comunicación entre micro-frontends es crucial para mantener la coherencia del estado y la experiencia de usuario. En lugar de acoplar las aplicaciones, se establecen contratos claros mediante eventos, props compartidos o un estado global ligero. Piensa en cómo los departamentos de una empresa colaboran: cada uno tiene autonomía, pero se coordinan mediante reuniones (eventos) y documentos compartidos (estado), evitando interferir en los procesos internos del otro.
Cómo funciona en la práctica
Para implementar componentes federados, primero defines un remote en Webpack que expone módulos específicos. Luego, en la aplicación host, configuras un remotes para consumir esos módulos. La magia ocurre en tiempo de ejecución: cuando el host necesita un componente, Webpack lo carga dinámicamente desde el remote, inyectándolo en la aplicación como si fuera local.
La comunicación se maneja típicamente mediante un bus de eventos o un store compartido. Por ejemplo, si un componente federado de carrito de compras necesita notificar a la aplicación host sobre un cambio, emite un evento custom. El host escucha ese evento y actualiza su estado o UI correspondiente. Esto mantiene el desacoplamiento: el componente no necesita saber detalles de implementación del host, solo sigue el contrato definido.
Codigo en accion
Configuración en el remote (app-productos):
// webpack.config.js del remote
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: "productos",
filename: "remoteEntry.js",
exposes: {
"./ProductCard": "./src/components/ProductCard",
"./ProductList": "./src/components/ProductList"
},
shared: ["react", "react-dom"]
})
]
};Consumo en el host (app-principal):
// webpack.config.js del host
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: "principal",
remotes: {
productos: "productos@http://localhost:3001/remoteEntry.js"
},
shared: ["react", "react-dom"]
})
]
};
// Uso en un componente React del host
import React, { Suspense } from 'react';
const ProductCard = React.lazy(() => import("productos/ProductCard"));
function App() {
return (
Cargando...