Aquí es donde entra en juego la arquitectura de micro frontales.

Piensa que es como construir un barrio: cada casa (o micro frontend) se desarrolla de forma independiente, pero todas se unen para crear una comunidad. Este enfoque permite a los diferentes equipos trabajar en partes separadas de una aplicación sin pisarse unos a otros.

En este blog, recorreremos la configuración de una arquitectura de micro frontend utilizando Angular con múltiples repositorios, impulsada por Native Federation. ¡Vamos a sumergirnos y descubrir cómo esto puede simplificar su proceso de desarrollo!

Configuración de la escena


Para empezar, vamos a crear: la aplicación host y dos micro frontends. Abre tu terminal y vamos a rodar:

# Create the host application
ng new host-app --routing 

# Create the first micro frontend
ng new micro-frontend-1 --routing 

# Create the second micro frontend
ng new micro-frontend-2 --routing

A continuación, añadiremos Native Federation en nuestras aplicaciones para que puedan comunicarse sin problemas.

# Add Native Federation to the host application
cd host-app 
ng add @angular-architects/native-federation

# Add Native Federation to micro-frontend-1
cd ../micro-frontend-1 
ng add @angular-architects/native-federation

# Add Native Federation to micro-frontend-2
cd ../micro-frontend-2 
ng add @angular-architects/native-federation

Creación de la aplicación host


Ahora, vamos a transformar nuestra aplicación host en un centro de control. Empezaremos configurándola para que reconozca nuestros micro frontends.

CPU
1 vCPU
MEMORIA
1 GB
ALMACENAMIENTO
10 GB
TRANSFERENCIA
1 TB
PRECIO
$ 4 mes
Para obtener el servidor GRATIS debes de escribir el cupon "LEIFER"

Modificar federation.config.js


Dirígete al archivo federation.config.js en tu aplicación host y simplifícalo eliminando el bloque exposes. Así es como debería verse:

const { withNativeFederation, shareAll } = require('@angular-architects/native-federation/config');

module.exports = withNativeFederation({
  name: 'host-app',
  shared: {
    ...shareAll({ singleton: true, strictVersion: true, requiredVersion: 'auto' }),
  },
  skip: [
    'rxjs/ajax',
    'rxjs/fetch',
    'rxjs/testing',
    'rxjs/webSocket',
    // Add further packages you don't need at runtime
  ]
});

Actualizar el punto de entrada


A continuación, actualizaremos el archivo main.ts para cargar nuestro manifiesto:

import { initFederation } from '@angular-architects/native-federation';

initFederation('/assets/federation.manifest.json') 
  .catch(err => console.error(err))
  .then(_ => import('./bootstrap'))
  .catch(err => console.error(err));

Configuración de rutas para su micro frontend


Ahora es el momento de decirle a la aplicación host cómo navegar a nuestro micro frontend. Actualiza el archivo app.routes.ts así:

import { loadRemoteModule } from '@angular-architects/native-federation';
import { Routes } from '@angular/router';

export const routes: Routes = [
    {
        path: 'micro-frontend-1',
        loadComponent: () => loadRemoteModule('micro-frontend-1', './Component').then(m => m.AppComponent)
    },
    {
        path: 'micro-frontend-2',
        loadComponent: () => loadRemoteModule('micro-frontend-2', './Component').then(m => m.AppComponent)
    }
];

Cambiar los puertos


Toda gran ciudad tiene su propia dirección. Vamos a establecer los puertos para nuestros micro frontends para que puedan estar orgullosamente en sus respectivas esquinas. Modifica el archivo angular.json para cada micro frontend para que se vea así:

"defaultConfiguration": "development",
"options": {
    "port": 4201 // for micro-frontend-1
}
"defaultConfiguration": "development",
"options": {
    "port": 4202 // for micro-frontend-2
}

Ahora, vamos a encender nuestras aplicaciones. Cada una debería estar funcionando sin problemas en su puerto designado.

First App running on port 4201
Segunda aplicación ejecutándose en el puerto 4202

Diseñar la experiencia del usuario


Con nuestras aplicaciones configuradas, vamos a crear un menú de navegación en el archivo app.component.html de la aplicación anfitriona. Esto actuará como la vía principal de la ciudad:

<div class="menu">
  <a routerLink="/micro-frontend-1" routerLinkActive="active">MF1</a>
  <a routerLink="/micro-frontend-2" routerLinkActive="active">MF2</a>
</div>
<div class="container">
  <router-outlet></router-outlet>
</div>

Manejo de cambios de ruta


Por último, vamos a añadir un toque de magia a nuestro enrutamiento mediante la configuración de eventos de enrutador en app.component.ts. Esto permitirá a nuestra aplicación anfitriona responder dinámicamente a los cambios en las rutas hijas:

import { Component, HostListener } from '@angular/core';
import { RouterOutlet, Router, RouterModule } from '@angular/router';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [RouterOutlet, RouterModule],
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  constructor(private router: Router) {}
  
  @HostListener('window:childRouteChanged', ['$event'])
  onChildRouteChanged(event: any) {
    this.router.navigate([event.detail.route], event.detail.extras);
  }
}

Un futuro modular

Aplicación shell con los dos microfrontend en ejecución

¡Y ahí lo tienes! Has configurado una arquitectura de micro frontend utilizando Angular con múltiples repositorios, creando un entorno en el que los equipos pueden innovar de forma independiente al tiempo que contribuyen a un todo mayor. A medida que tus aplicaciones crecen, esta arquitectura permite una integración perfecta, implementaciones más rápidas y una experiencia de usuario más fluida.

Entonces, ¿a qué esperas?
¿Has probado a implementar micro frontend en tus proyectos? ¡Comparte tus experiencias o preguntas en los comentarios!

¡Feliz programación!