single-spa vs Module Federation: cómo elegir
Estas dos herramientas se suelen comparar como si hicieran el mismo trabajo. Se superponen, pero parten de lugares distintos: una administra ciclos de vida de aplicaciones, la otra carga código y comparte dependencias.
Dos trabajos distintos
single-spa es un orquestador. Es una librería pequeña que decide qué aplicaciones están activas para la URL actual, y las monta y desmonta.
Module Federation es un mecanismo de carga y de compartir dependencias. Permite que un build consuma módulos de otro build en tiempo de ejecución y que compartan dependencias.
Cómo funciona single-spa
Una plataforma single-spa tiene un root config: una página HTML y un script que registra las aplicaciones.
registerApplication({
name: 'billing',
app: () => import('billing'),
activeWhen: '/billing'
});
start();
Cada aplicación registrada exporta tres funciones de ciclo de vida: bootstrap, mount y unmount. Paquetes de ayuda como single-spa-angular, single-spa-react y single-spa-vue las generan para cada framework.
Cuando la URL cambia, single-spa desmonta las aplicaciones que ya no están activas y monta las que sí. Puede haber varias aplicaciones activas a la vez, por ejemplo una barra de navegación y la página que está debajo.
single-spa no impone cómo se carga el código. Su documentación recomienda desde hace tiempo los import maps, cargados con SystemJS o, en navegadores actuales, de forma nativa. En el ejemplo anterior, un import map nativo resuelve el nombre billing a una URL.
Cómo funciona una plataforma con Module Federation
El host es una aplicación normal en un framework, por ejemplo Angular. Su router carga de forma diferida las rutas de los remotos. No hay un ciclo de vida aparte. Las rutas y los componentes del remoto pasan a formar parte de la aplicación del host: una instancia del framework, un router, un árbol de inyección de dependencias.
El mismo modelo aplica a Native Federation, que se compara en Module Federation vs Native Federation.
Lado a lado
| single-spa | Module Federation | |
|---|---|---|
| Qué es | Router de nivel superior y administrador de ciclos de vida | Carga de módulos en tiempo de ejecución y dependencias compartidas |
| Unidad de composición | Una aplicación completa que se monta y se desmonta | Un módulo: rutas, un componente, un servicio |
| Varios frameworks | Diseñado para eso | Posible, con un envoltorio por framework |
| Rutas | single-spa elige la aplicación; cada una enruta dentro de su prefijo | El router del host es dueño de la URL; los remotos agregan rutas hijas |
| Dependencias compartidas | Con import maps y externals, administradas por ti | Incluidas, con reglas de versión |
| Servicios compartidos | Instancias de aplicación separadas; se comparte con módulos utilitarios | Una instancia del framework; los servicios singleton funcionan como siempre |
| Particularidades de Angular | Cada aplicación arranca su propia app Angular; zone.js debe cargarse una sola vez por página | Los remotos se sienten como funcionalidades con lazy loading |
Soporte para varios frameworks
Esta es la diferencia más clara.
single-spa trata cada aplicación como una caja negra con tres funciones. Una app AngularJS, una React y una Angular pueden convivir, cada una con su propia instancia de framework. Existe incluso un paquete single-spa-angularjs, y por eso es una elección común durante migraciones de código legacy.
Module Federation supone que host y remoto pueden compartir un runtime. Con un solo framework, eso es una fortaleza. Con varios, el remoto de otro framework tiene que envolverse, normalmente como custom element, y el host lo carga como un script o módulo común. Funciona, pero el manejo de ciclo de vida que single-spa entrega hay que escribirlo a mano.
Pros y contras
single-spa
- Separación limpia entre instancias de aplicación. Es raro que una aplicación rompa los internos de otra.
- Cada aplicación arranca su propia instancia del framework. Eso cuesta tiempo de inicio y memoria, aunque el código del framework se comparta.
- Compartir un servicio entre aplicaciones es manual: un módulo utilitario compartido, eventos o la URL.
Module Federation
- En una plataforma de un solo framework, ofrece la experiencia de desarrollo más simple. Un remoto se desarrolla casi como una funcionalidad con lazy loading.
- Exige alinear de cerca las versiones del framework. Una dependencia compartida mal configurada puede afectar a todos los remotos.
- Menos aislamiento. Los remotos corren dentro de la aplicación del host, así que un remoto que falla necesita contención explícita. Mira Aislamiento de errores y resiliencia.
Cuándo elegir cada uno
- Todos los equipos en Angular, con versiones alineadas por política: federation (Module o Native). Es la opción más barata de operar.
- Frameworks distintos a largo plazo, o productos adquiridos con su propio stack: single-spa, o federation con envoltorios de custom elements si solo una o dos partes son diferentes.
- AngularJS junto a Angular moderno durante una migración: los dos sirven. single-spa tiene paquetes dedicados. Con federation, la app legacy se envuelve y se carga como un remoto más, como se describe en Una app legacy dentro de un host de microfrontends.
- Los dos juntos: single-spa para los ciclos de vida, federation para cargar y compartir. Es una combinación válida, y significa dos herramientas que entender y depurar. Elígela solo cuando necesites los dos trabajos.
Decide primero cuántos frameworks habrá. Si la respuesta honesta a largo plazo es "uno", federation sola alcanza. Si es "varios, y eso no va a cambiar", un orquestador se gana su lugar.
Más en esta sección
- Iframes, web components, paquetes o federation: técnicas de integración comparadas
- El host de microfrontends: de qué es responsable y qué no debe hacer
- Rutas entre microfrontends: dueños de rutas, deep links y contrato de navegación
- Cómo compartir login y sesión entre microfrontends
¿Planeas una migración o una plataforma de microfrontends?
En una llamada de 20 minutos me cuentas tu situación y te digo cómo la abordaría. Si todavía no vale la pena, también te lo digo.
Escríbeme por LinkedIn