Concepto clave
Module Federation es una funcionalidad de Webpack 5 que permite cargar código de aplicaciones independientes en tiempo de ejecución, creando un ecosistema de micro-frontends. Imagina un centro comercial donde cada tienda (micro-frontend) opera de forma autónoma, pero comparte servicios comunes como estacionamiento (dependencias) y permite a los clientes moverse entre ellas sin reiniciar su experiencia. En términos técnicos, Module Federation habilita la composición dinámica de bundles entre diferentes builds de Webpack, eliminando la necesidad de monorepos o builds monolíticos.
La arquitectura se basa en dos roles principales: host (aplicación contenedora que consume módulos remotos) y remote (aplicación que expone módulos). La magia ocurre mediante un manifesto de federación que Webpack genera automáticamente, describiendo qué módulos están disponibles y cómo acceder a ellos. Esto permite que equipos distribuidos desarrollen y desplieguen independientemente, mientras mantienen una experiencia de usuario cohesiva.
Cómo funciona en la práctica
Configurar Module Federation implica tres pasos principales en tu archivo webpack.config.js:
- Definir la configuración de federación usando el plugin ModuleFederationPlugin
- Especificar qué módulos expones (remotes) o consumes (host)
- Configurar las dependencias compartidas para evitar duplicación de librerías
Veamos un ejemplo básico: supongamos que tienes una aplicación de dashboard (host) que necesita incorporar un widget de gráficos desde una aplicación separada (remote). Primero, en la aplicación remote, configuras Webpack para exponer el componente ChartWidget. Luego, en el host, configuras la referencia a ese remote y lo importas dinámicamente en tu código. Webpack se encarga de resolver las dependencias y cargar el código cuando sea necesario, sin requerir un deploy conjunto.
Código en acción
Configuración de una aplicación remote que expone un componente:
// webpack.config.js de la aplicación remote (widget-app)
const { ModuleFederationPlugin } = require('webpack').container;
module.exports = {
// ... otras configuraciones de Webpack
plugins: [
new ModuleFederationPlugin({
name: 'widgetApp',
filename: 'remoteEntry.js',
exposes: {
'./ChartWidget': './src/components/ChartWidget.jsx',
'./DashboardHeader': './src/components/DashboardHeader.jsx'
},
shared: {
react: { singleton: true, eager: false },
'react-dom': { singleton: true, eager: false }
}
})
]
};
Configuración del host que consume el módulo remoto:
// webpack.config.js de la aplicación host (main-dashboard)
const { ModuleFederationPlugin } = require('webpack').container;
module.exports = {
// ... otras configuraciones
plugins: [
new ModuleFederationPlugin({
name: 'mainDashboard',
remotes: {
widgetApp: 'widgetApp@http://localhost:3001/remoteEntry.js'
},
shared: {
react: { singleton: true, eager: false },
'react-dom': { singleton: true, eager: false },
'chart.js': { singleton: true }
}
})
]
};
Uso en el código del host con importación dinámica:
// En main-dashboard/src/App.jsx
import React, { Suspense } from 'react';
const RemoteChartWidget = React.lazy(() => import('widgetApp/ChartWidget'));
function App() {
return (
Dashboard Principal
Cargando widget... }>