Los micro-frontends existen porque los monolitos frontend se vuelven lentos de desarrollar cuando múltiples equipos trabajan sobre el mismo código. Pero la solución introduce complejidad propia, y la mayoría de los equipos que adopta micro-frontends subestima esa complejidad.

El problema que resuelven los micro-frontends

En equipos grandes, 5+ squads trabajando en el mismo repositorio frontend enfrentan: conflictos de merge constantes, builds que se vuelven más lentos en cada sprint, dificultad de deploy independiente por squad, y acoplamiento entre features que deberían ser independientes.

Los micro-frontends separan la aplicación en unidades independientes que se componen en runtime. Cada squad controla su parte, hace deploy independiente y no bloquea a los demás.

Enfoques existentes

Build-time integration (Module Federation)

Webpack Module Federation permite que aplicaciones carguen módulos de otras aplicaciones en runtime. Cada micro-frontend es una aplicación standalone que exporta componentes.

// webpack.config.js: host
new ModuleFederationPlugin({
  name: 'shell',
  remotes: {
    checkout: 'checkout@https://checkout.example.com/remoteEntry.js',
    catalog: 'catalog@https://catalog.example.com/remoteEntry.js',
  },
})

Run-time integration (iframe o Web Components)

Los iframes son el enfoque más aislado. Los Web Components permiten composición más granular, pero exigen una capa de comunicación entre micro-frontends.

Server-side composition (SSI, ESI, edge-side includes)

El servidor compone los micro-frontends antes de enviarlos al cliente. Elimina waterfalls de carga pero requiere infraestructura de servidor que soporte includes.

Lo que cambia en la práctica

// Estructura típica
shell-app/              # Shell que monta la página
├── src/
│   ├── Header.tsx      # Compartido entre todos
│   ├── Footer.tsx      # Compartido entre todos
│   └── MicroApp.tsx    # Loader de micro-frontends
│
checkout/               # Squad de checkout
├── src/
│   ├── Checkout.tsx
│   ├── Payment.tsx
│   └── Shipping.tsx
│
catalog/                # Squad de catálogo
├── src/
│   ├── ProductList.tsx
│   └── ProductDetail.tsx

Los costos que nadie avisa

  • Comunicación entre micro-frontends: los datos compartidos exigen un mecanismo explícito: event bus, store compartida o prop drilling vía shell.
  • Estilo consistente: un design system compartido es obligatorio, no opcional. Cada squad puede customizar, pero la base viene de un paquete común.
  • Performance: múltiples bundles significan más requests HTTP, más JavaScript parseado, más memoria. El shell necesita optimizar la carga.
  • Debug: un bug que cruza fronteras entre micro-frontends es más difícil de rastrear que en un monolito.
  • Deploy coordinado: dependencias entre micro-frontends pueden exigir deploys coordinados, lo que elimina parte de la independencia.

Cuándo vale la pena

Los micro-frontends se justifican cuando: tienes 3+ equipos trabajando en el mismo frontend, con releases independientes y poca superposición de código. La ganancia de velocity del equipo supera el costo de infraestructura.

Cuándo no vale la pena

Si tienes 1-2 equipos, o los squads trabajan en features que se superponen constantemente, un monolito con buena organización de carpetas y módulos es más simple y más eficiente. No adoptes arquitectura por anticipar problemas que no tienes.