Un microfrontend aplica el principio de microservicio a la capa de presentación: en lugar de una única aplicación Angular monolítica, la interfaz se divide en partes independientes (a menudo alineados con equipos de productos separados), cada uno con su propia construcción, implementación y canalización. ciclo de lanzamiento, compuesto junto con el tiempo de ejecución o el tiempo de compilación en una única experiencia de usuario. el beneficio El principal no es técnico sino organizativo: diferentes equipos pueden lanzar de forma autónoma sin coordinar un despliegue monolítico compartido. La contrapartida igualmente real es la complejidad adicional de composición, dependencias compartidas y pruebas de integración: las microfronteras no son la opción adecuado para cada proyecto, y debería adoptarse cuando el coste de coordinación entre equipos ya supera el actual el coste de la complejidad técnica que introducen.
Patrones de integración: Comparación
| Patrón | Pros | Contras | Cuándo preferirlo |
|---|---|---|---|
| Lado del cliente (shell + remotos) | Máxima flexibilidad en tiempo de ejecución, implementaciones independientes reales | Complejidad de compartir dependencias, riesgo de duplicación | Múltiples equipos, lanzamientos frecuentes independiente |
| Composición del lado del servidor | SEO nativo, sin JS adicional para la composición | Requiere infraestructura de servidor dedicado (SSI/ESI) | Contenido público de alto tráfico, SEO crítico |
| Proxy de borde/inverso | Composición centralizada, caché granular por fragmento | El proxy se convierte en un único punto de falla | Equipo de infraestructura maduro, gran necesidad de borde almacenamiento en caché |
| Componentes web | Encapsulación DOM nativa independiente del marco | La comunicación entre componentes es menos natural que un marco nativo | Equipos con pilas de frontend heterogéneas (no solo Angular) |
| iFrame | Aislamiento total, cero conflictos CSS/JS | Usuario deficiente, comunicación incómoda entre marcos, cero SEO | Solo para confianza de integración que no sea de terceros yo |
Para la mayoría de los equipos empresariales de Angular, el patrón del lado del cliente con Module Federation sigue siendo la opción predeterminada: equilibra la flexibilidad del tiempo de ejecución y la integración natural con enrutamiento e inyección de dependencia de Angular, sin el aislamiento excesivo de un iframe.
Federación de módulos (Webpack 5): Shell y control remoto
El shell (host) carga dinámicamente paquetes remotos en tiempo de ejecución, compartiendo dependencias los más comunes (Angular, RxJS) como singletons para evitar descargarlos varias veces.
// webpack.config.js — SHELL (host)
const { ModuleFederationPlugin } = require('webpack').container;
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'shell',
remotes: {
checkout: 'checkout@https://cdn.example.com/checkout/remoteEntry.js',
},
shared: { '@angular/core': { singleton: true, strictVersion: true }, 'rxjs': { singleton: true } },
}),
],
};
// webpack.config.js — REMOTE (checkout)
new ModuleFederationPlugin({
name: 'checkout',
filename: 'remoteEntry.js',
exposes: { './Module': './src/app/checkout/checkout.module.ts' },
shared: { '@angular/core': { singleton: true, strictVersion: true }, 'rxjs': { singleton: true } },
});
// Routing shell — lazy load dinamico del remote
export const routes: Routes = [
{
path: 'checkout',
loadChildren: () => import('checkout/Module').then(m => m.CheckoutModule),
},
];
SPA único: registro y ciclo de vida
// Registrazione di un microfrontend Angular in single-spa
registerApplication({
name: 'checkout',
app: () => import('./checkout.app'),
activeWhen: ['/checkout'],
});
// Lifecycle esposto dal microfrontend
export const { bootstrap, mount, unmount } = singleSpaAngular({
bootstrapFunction: singleSpaProps => bootstrapApplication(CheckoutRootComponent),
template: '',
});
Elementos angulares/Componentes web
// Esporre un componente Angular come Web Component standard
const app = await bootstrapApplication(ProductCardComponent);
const element = createCustomElement(ProductCardComponent, { injector: app.injector });
customElements.define('product-card', element);
El consumidor, aunque no está basado en Angular, utiliza el componente como cualquier etiqueta HTML nativa:
: esto es lo que hace que Web
Componentes es la opción correcta cuando el shell u otros microfrontends no son Angular.
Alternativas más ligeras: importar mapa con módulos ES dinámicos (sin herramienta de compilación)
dedicado a la federación, solo el import() nativo apuntaba a URL versionadas) para los equipos que
desea evitar la complejidad de configuración de Module Federation y el patrón Nx
monorepo cuando los microfrontends comparten el mismo repositorio de todos modos pero quieren
mantener tuberías de construcción independientes a través del gráfico afectado.
Sistema de diseño y uso compartido de dependencias
Angular y RxJS siempre deben compartirse como singleton: true en Module Federation: without
esto, cada control remoto descarga su propia copia del marco, inflando el paquete y arriesgándolo
cambie la incompatibilidad de detección entre el shell y el control remoto cargados juntos.
// package.json della libreria di design system condivisa — peerDependencies, non dependencies
{
"name": "@azienda/mfe-ui",
"peerDependencies": { "@angular/core": "^18.0.0", "rxjs": "^7.0.0" }
}
Publicar componentes principales y tokens de diseño como una biblioteca con versiones separadas (no duplicadas en cada una). microfrontend), documentado en Storybook: exactamente el mismo patrón que un sistema de diseño centralizado, con la única diferencia de que aquí los consumidores son microfrontends independientes en lugar de aplicaciones separadas.
Enrutamiento, estado y comunicación entre microfronteras
Global routing (qué microfrontend mostrar) sigue siendo responsabilidad del shell; cada control remoto administra su propia enrutamiento local (las subrutas internas) en un completamente independiente: el shell no necesita conocer la estructura de enrutamiento interno de un remoto, solo su ruta de entrada.
// Event bus condiviso con RxJS — comunicazione shell/remote senza accoppiamento diretto
export class MfeEventBus {
private readonly subject = new Subject<{ type: string; payload: unknown }>();
emit(type: string, payload: unknown) { this.subject.next({ type, payload }); }
on(type: string) { return this.subject.pipe(filter(e => e.type === type), map(e => e.payload)); }
}
Para el estado compartido, hay tres opciones con diferentes compensaciones: la URL (la más simple y robusto, pero limitado al estado serializable), un bus de eventos como arriba (desacoplado pero sin su propio estado persistente), o una store compartida publicada como biblioteca singleton (más potente pero introduce un acoplamiento implícito entre microfrontends que deben coincidir en una forma estatal común). El contrato entre shell y control remoto siempre debe ser explícito y escrito: accesorios eventos entrantes y salientes, nunca acceso directo e indocumentado al estado interno de un otro control remoto.
CI/CD, pruebas e implementación
Cada microfrontend tiene su propio proceso independiente: compilación, prueba unitaria, Storybook y publicación del
remoteEntry.js toma de huellas digitales en CDN, sin depender del despliegue de otras microfronteras.
# GitHub Actions — sintesi pipeline per un singolo microfrontend
jobs:
build-and-deploy:
steps:
- run: npm ci
- run: npm run build -- --configuration production
- run: npm test -- --watch=false
- run: npx cypress run
- run: aws s3 cp dist/checkout s3://cdn.example.com/checkout/$GITHUB_SHA --recursive
- run: node scripts/update-manifest.js checkout $GITHUB_SHA
// scripts/update-manifest.js — aggiorna il manifest che la shell legge per risolvere i remoteEntry
const manifest = JSON.parse(fs.readFileSync('manifest.json'));
manifest[process.argv[2]] = `https://cdn.example.com/${process.argv[2]}/${process.argv[3]}/remoteEntry.js`;
fs.writeFileSync('manifest.json', JSON.stringify(manifest, null, 2));
Para la integración entre shell y remoto, dos niveles de pruebas: prueba de contrato que verificar que el control remoto exponga la interfaz esperada (accesorios/eventos) sin implementar todo el shell, e E2E contra un entorno de prueba con el caparazón real y controles remotos reales, reservados para flujos críticos entre microfrontends: controles remotos simulados en pruebas unitarias de shell, no confíe solo a eso para validar una integración real.
Rendimiento y optimización
<!-- Prefetch del remoteEntry del prossimo microfrontend probabile, senza bloccare il rendering corrente -->
<link rel="prefetch" href="https://cdn.example.com/checkout/remoteEntry.js" as="script" />
- Carga diferida de cada control remoto solo cuando se visita la ruta correspondiente, nunca en el paquete de shell inicial.
- Huellas digitales de la entrada remota (hash en la ruta, no en el nombre del archivo para compatibilidad con Module Federation) para caché largo sin invalidaciones accidentales.
- Analizador de paquetes para cada control remoto de forma independiente, no solo en el shell agregado, para detectar duplicaciones de dependencias que no se comparten correctamente.
- TTI/LCP medido por cada microfrontend, no sólo en la página general: un control remoto lento degrada la percepción de todo el shell incluso si el resto es rápido.
Seguridad y operaciones
# CSP che permette script solo dai domini CDN dei microfrontend fidati
Content-Security-Policy: script-src 'self' https://cdn.example.com; connect-src 'self' https://cdn.example.com;
Se requiere HTTPS en cada CDN que sirve una entrada remota y CORS configurado explícitamente para Permita que el shell cargue scripts de origen cruzado desde dominios de microfrontend. Gestiona siempre el Error al cargar un control remoto con un componente alternativo explícito, nunca una página en blanco: un microfrontend secundario que no responde no debería impedir el uso del resto de la aplicación.
// Fallback route nella shell se un remote non è raggiungibile
loadChildren: () => import('checkout/Module')
.then(m => m.CheckoutModule)
.catch(() => import('./fallback/checkout-unavailable.module').then(m => m.CheckoutUnavailableModule)),
El monitoreo debe configurarse para un único microfrontend, no solo para un agregado: tasa de error, implementación Frecuencia de carga de entrada remota y latencia para cada equipo, por lo que se identifica un problema. inmediatamente en el microfrontend responsable en lugar de genéricamente "en el shell".
Escalabilidad y reversión
Cada implementación de un control remoto tiene una versión (ruta con hash/SHA de la confirmación en CDN); la reversión consiste en redireccione el manifiesto a la versión anterior, sin necesidad de una nueva implementación o reconstruir: la operación más rápida posible en caso de regresión.
# Rollback: ripunta il manifest alla versione precedente del remote
node scripts/update-manifest.js checkout $PREVIOUS_SHA
Para implementaciones fluidas, use indicador de característica en el nivel de shell (¿qué versión del manifiesto sirve a qué porcentaje de usuarios) en lugar de un canario a nivel de infraestructura más complejo de orquestar para fragmentos individuales de la interfaz de usuario.
Estudio de caso 1: Mercado con 4 equipos de productos
Un mercado con 4 equipos independientes (búsqueda, producto, pago, cuenta) ha adoptado el módulo Federación con caparazón centralizado. Esfuerzo de configuración inicial: ~120 horas-persona para shell, manifiesto y canalización CI/CD compartida. Después de 5 meses: la frecuencia de implementación pasó de 1 por semana (monolito) a 12 por semana en total en los 4 equipos, tiempo promedio de reversión de 25 minutos (reconstrucción completa) a 40 segundos (actualización de manifiesto), 0 conflictos de fusión entre equipos en la interfaz.
Estudio de caso 2: Plataforma SaaS en expansión internacional
Una plataforma SaaS con equipos repartidos en 3 zonas horarias ha adoptado componentes web para permitir un equipo con pila React para integrarse en el shell Angular existente sin reescribir nada. Esfuerzo: ~80 horas persona para el primer componente web remoto más una biblioteca de diseño de tokens compartida. Resultado: El tiempo de comercialización de la primera función entre equipos se redujo de 6 a 3 semanas, sin dependencias forzadas. desde una única pila de interfaz para la incorporación de nuevos equipos.
Lista de verificación operativa previa al inicio
- Limites claros del dominio empresarial entre microfrontends, alineados en equipo, no arbitrarios.
- Sistema de diseño compartido lanzado antes del primer control remoto, no después.
- Contrato remoto de Shell (accesorios/eventos) explícitamente documentado y versionado.
- Canalización de CI/CD independiente ya lista para al menos el primer control remoto antes de agregar un segundo.
Plan de 30/60/90 días
Días 1-30
- Shell y primer control remoto en producción con Module Federation — KPI: tasa de éxito de compilación del 100 %, implementación independiente verificada.
Días 31-60
- Segundo y tercer control remoto integrado, por microfrontend, activo — KPI: tasa de error rastreada por separado para cada control remoto.
Días 61-90
- Reversión probada de extremo a extremo, indicadores de funciones para implementaciones graduales activas — KPI: tiempo de reversión medido en menos de un minuto.
Preguntas frecuentes
¿La Federación de Módulos siempre duplica Angular si no está bien configurada?
Sí, sin singleton: true en la sección compartida, cada control remoto descarga su propia copia del marco, inflando el paquete y arriesgándose a la incompatibilidad.
¿Cómo se gestiona el enrutamiento cuando no se puede acceder a un control remoto?
Con un respaldo explícito en la cadena de carga diferida, sin permitir nunca que el error de importación se propague como una página en blanco.
¿Realmente necesitas Nx para crear microfrontends con Angular?
No, es útil para orquestar múltiples proyectos en el mismo repositorio, pero Module Federation también funciona con repositorios completamente separados.
¿Cuántas microfronteras son "demasiadas"?
No existe un número fijo; la señal de alerta es cuando el costo de coordinación entre contratos remotos excede el beneficio de implementaciones independientes.
¿Cómo se prueban las integraciones entre shell y control remoto?
Con pruebas por contrato en controles remotos individuales más E2E en un entorno de prueba con shells reales y controles remotos para flujos críticos.
¿Las microfronteras ralentizan el rendimiento en comparación con un monolito?
Puede, si no se maneja con carga diferida y captación previa correctas; bien configurado, el impacto es marginal en comparación con los beneficios organizacionales.
¿Cómo se comparten tokens de diseño entre diferentes microfronteras?
Con una biblioteca publicada por separado, versionada y consumida como dependencia de pares por cada control remoto.
¿Componentes web o federación de módulos?
Federación de módulos cuando todos los microfrontends son angulares; Componentes web cuando la pila es heterogénea o se necesita un aislamiento independiente del marco.
¿Cómo puedo revertir rápidamente un único microfrontend?
Redireccionar el manifiesto a la versión anterior de RemoteEntry, sin necesidad de una nueva implementación.
¿Necesita un shell dedicado o también puede ser una aplicación?
Es preferible un shell dedicado, mínimo y estable, para reducir el riesgo de que su redespliegue afecte a todos los controles remotos al mismo tiempo.
¿Cómo se evita la duplicación de CSS entre microfrontends?
Con un sistema de diseño compartido como única fuente de estilos básicos y encapsulación (Shadow DOM o convención de nomenclatura rigurosa) para los estilos específicos de cada control remoto.
¿Tienen sentido las microfrontends incluso para un solo equipo?
Rara vez: el principal beneficio es organizacional; con un solo equipo, el costo de la composición del tiempo de ejecución generalmente supera los beneficios.
Errores comunes que se deben evitar
- Angular no compartido como singleton: provoca la duplicación del marco y un error de detección de cambios entre el shell y el control remoto.
- Sin respaldo de UX para controles remotos inaccesibles: convierte un problema aislado en una página en blanco para toda la aplicación.
- Contrato remoto de shell indocumentado: cada equipo adivina la interfaz, lo que provoca regresiones silenciosas en cada implementación.
- Límites de dominio arbitrarios entre microfrontends: generar excesiva comunicación cruzada remota en lugar de reducir el acoplamiento.
- Sistema de diseño duplicado en lugar de compartido: Produce inconsistencia visual entre microfrontends en unas pocas semanas.
- No hay pruebas de contrato entre shell y remoto: las regresiones de integración solo se descubren en producción.
- Implementar controles remotos sin versión: hace que la reversión sea tan lenta y riesgosa como una reconstrucción completa.
- Monitoreo solo agregado en el shell: Le impide identificar rápidamente qué microfrontend está causando un problema.
- iFrame utilizado para la composición interna entre equipos de confianza: introduce cero comunicación y complejidad SEO sin la necesidad real de un aislamiento total.
- Sin precarga de probables controles remotos: cada navegación a un nuevo microfrontend paga el costo total de la carga en frío.
Cómo comprobar
- Construya cada control remoto aislado:
npx webpack --config webpack.config.jsy verifique si hay errores. - Pruebas E2E en shells reales + controles remotos en preparación:
npx cypress run. - Verificación de manifiesto: verifique que cada entrada apunte a un
remoteEntry.jsrealmente accesible (curl -Ien cada URL). - Controle el tamaño del paquete por control remoto individual con un analizador de paquetes, no solo en el conjunto.
- Prueba de respaldo: deshabilite temporalmente un control remoto y verifique que el shell muestre el componente de respaldo en lugar de un error.
- Monitoreo activo: verifique que la tasa de error, la frecuencia de implementación y la latencia se realicen un seguimiento por separado para cada microfrontend.
Conclusión
Los microfrontends con Angular resuelven un problema organizacional, no principalmente técnico: el Necesidad de que varios equipos lancen de forma autónoma sin coordinar un monolito compartido. Módulo Federación con dependencias compartidas como singletons, un sistema de diseño centralizado, contratos explícito entre shell y remoto, y una reversión basada en manifiesto versionado son los elementos que distinguir una arquitectura de microfrontend verdaderamente sostenible de una complejidad añadida sin verdadero beneficio.
¿Quiere un repositorio básico para comenzar o una evaluación de su arquitectura frontend? existente? Solicitar una auditoría técnica: en pocas horas de análisis es posible identificar el Corrija los límites del dominio y los riesgos clave de la adopción de un microfrontend para su equipo.