Micro Front-end com Module Federation: Implementação Prática em Angular
Parte 3 - Micro Front-end com Module Federation: Construindo Aplicações Extensíveis
Neste artigo
Introdução
Nesta seção, construiremos um exemplo completo de micro front-end em Angular utilizando Module Federation. A ideia é criar:
- Host Application – a aplicação principal que consome os módulos remotos.
- Remote Application Dashboard One – um módulo remoto com um gráfico de barras.
- Remote Application Dashboard Two – um módulo remoto com um gráfico de pizza.
Além disso, exploraremos:
- Configuração do Webpack para Module Federation.
- Rotas dinâmicas e carregamento assíncrono de módulos.
- Comunicação entre host e remotes.
- Boas práticas para projetos reais.
1. Setup do Projeto
Requisitos
- Angular 18
- Node 20.17.0
- Bibliotecas:
@angular-architects/module-federationchart.js
Comandos iniciais
Host Application
ng new mfe-app-host
cd mfe-app-host
ng add @angular-architects/module-federation --project mfe-app-host --port 4200 --type host --skip-confirmation
Remote Application Dashboard One
ng new mfe-dashboard-one
cd mfe-dashboard-one
ng add @angular-architects/module-federation --project mfe-dashboard-one --port 4201 --type remote --skip-confirmation
npm install chart.js
Remote Application Dashboard Two
ng new mfe-dashboard-two
cd mfe-dashboard-two
ng add @angular-architects/module-federation --project mfe-dashboard-two --port 4202 --type remote --skip-confirmation
npm install chart.js
2. Host Application – Estrutura e Componentes
O host será responsável por integrar os módulos remotos e gerenciar a navegação entre eles.
2.1 Componente Home
home.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-home',
standalone: true,
templateUrl: './home.component.html',
styleUrls: ['./home.component.css'],
})
export class HomeComponent {}
home.component.html
<h1>Home</h1>
<p>Bem-vindo ao Host Application!</p>
2.2 Componente Navbar
navbar.component.ts
import { Component } from '@angular/core';
import { RouterLink } from '@angular/router';
@Component({
selector: 'app-navbar',
standalone: true,
imports: [RouterLink],
templateUrl: './navbar.component.html',
styleUrls: ['./navbar.component.css'],
})
export class NavbarComponent {}
navbar.component.html
<nav class="navbar">
<div class="logo">
<a href="#home">MFE</a>
</div>
<div class="nav-links">
<a routerLink="/home">Home</a>
<a routerLink="/mfe-dashboard-one">Dashboard One</a>
<a routerLink="/mfe-dashboard-two">Dashboard Two</a>
</div>
</nav>
navbar.component.css
.navbar {
background-color: #333;
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 20px;
}
.navbar a {
color: white;
text-decoration: none;
padding: 14px 16px;
}
.navbar a:hover {
background-color: #ddd;
color: black;
}
.logo {
font-size: 24px;
font-weight: bold;
}
.nav-links {
display: flex;
}
@media screen and (max-width: 600px) {
.navbar {
flex-direction: column;
}
.nav-links {
flex-direction: column;
width: 100%;
}
.navbar a {
text-align: center;
}
}
2.3 App Component
app.component.ts
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { NavbarComponent } from './navbar/navbar.component';
@Component({
selector: 'app-root',
standalone: true,
imports: [RouterOutlet, NavbarComponent],
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {}
app.component.html
<app-navbar></app-navbar>
<router-outlet></router-outlet>
2.4 Rotas
O host precisa carregar dinamicamente os módulos remotos usando loadRemoteModule da biblioteca @angular-architects/module-federation.
app.routes.ts
import { Routes } from '@angular/router';
import { loadRemoteModule } from '@angular-architects/module-federation';
import { HomeComponent } from './home/home.component';
export const routes: Routes = [
{
path: 'mfe-dashboard-one',
loadComponent: () =>
loadRemoteModule({
type: 'module',
remoteEntry: 'http://localhost:4201/remoteEntry.js',
exposedModule: './Component',
}).then((m) => m.AppComponent),
},
{
path: 'mfe-dashboard-two',
loadComponent: () =>
loadRemoteModule({
type: 'module',
remoteEntry: 'http://localhost:4202/remoteEntry.js',
exposedModule: './Component',
}).then((m) => m.AppComponent),
},
{ path: 'home', component: HomeComponent },
{ path: '', redirectTo: '/home', pathMatch: 'full' },
];
2.5 Configuração do Webpack
webpack.config.js
const { shareAll, withModuleFederationPlugin } = require('@angular-architects/module-federation/webpack');
module.exports = withModuleFederationPlugin({
remotes: {
mfeDashboardOne: 'http://localhost:4201/remoteEntry.js',
mfeDashboardTwo: 'http://localhost:4202/remoteEntry.js',
},
shared: {
...shareAll({ singleton: true, strictVersion: true, requiredVersion: 'auto' }),
},
});
remotes: Lista de micro front-ends que serão carregados.shared: Dependências compartilhadas entre host e remotes.
3. Remote Application Dashboard One
O Dashboard One será um micro front-end independente, com um gráfico de barras usando Chart.js.
3.1 App Component
app.component.ts
import { Component, OnInit } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { Chart } from 'chart.js/auto';
@Component({
selector: 'app-root',
standalone: true,
imports: [RouterOutlet],
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit {
ngOnInit() {
this.createBarChart();
}
createBarChart() {
new Chart('barChart', {
type: 'bar',
data: {
labels: ['Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho'],
datasets: [
{
label: 'Vendas',
data: [12, 19, 3, 5, 2, 3],
backgroundColor: 'rgba(75, 192, 192, 0.6)',
},
],
},
options: { responsive: true, scales: { y: { beginAtZero: true } } },
});
}
}
app.component.html
<div class="dashboard">
<h1>Dashboard One</h1>
<div class="chart-container">
<canvas id="barChart"></canvas>
</div>
</div>
app.component.css
.dashboard { padding: 20px; }
.chart-container { width: 100%; max-width: 600px; margin-bottom: 20px; }
3.2 Webpack Configuration
const { shareAll, withModuleFederationPlugin } = require('@angular-architects/module-federation/webpack');
module.exports = withModuleFederationPlugin({
name: 'mfe-dashboard-one',
exposes: { './Component': './src/app/app.component.ts' },
shared: { ...shareAll({ singleton: true, strictVersion: true, requiredVersion: 'auto' }) },
});
4. Remote Application Dashboard Two
O Dashboard Two será um gráfico de pizza, também carregado dinamicamente pelo host.
4.1 App Component
app.component.ts
import { Component, OnInit } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { Chart } from 'chart.js/auto';
@Component({
selector: 'app-root',
standalone: true,
imports: [RouterOutlet],
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit {
ngOnInit() {
this.createPieChart();
}
createPieChart() {
new Chart('pieChart', {
type: 'pie',
data: {
labels: ['Vermelho', 'Azul', 'Amarelo'],
datasets: [
{ label: 'Cores Favoritas', data: [300, 50, 100], backgroundColor: ['rgb(255, 99, 132)','rgb(54, 162, 235)','rgb(255, 205, 86)'] }
]
},
options: { responsive: true }
});
}
}
app.component.html
<div class="dashboard">
<h1>Dashboard Two</h1>
<div class="chart-container">
<canvas id="pieChart"></canvas>
</div>
</div>
4.2 Webpack Configuration
const { shareAll, withModuleFederationPlugin } = require('@angular-architects/module-federation/webpack');
module.exports = withModuleFederationPlugin({
name: 'mfe-dashboard-two',
exposes: { './Component': './src/app/app.component.ts' },
shared: { ...shareAll({ singleton: true, strictVersion: true, requiredVersion: 'auto' }) },
});
5. Comunicação entre Host e Remotes
Para compartilhar estado, podemos criar um BehaviorSubject em um pacote compartilhado.
5.1 Shared State
// shared-state.ts
import { BehaviorSubject } from 'rxjs';
export const userState = new BehaviorSubject<{ name: string }>({ name: '' });
- Host e Remotes importam
userState. - Qualquer alteração no BehaviorSubject é refletida em tempo real em todos os micro front-ends.
6. Testando a Aplicação
- Rodar os três projetos simultaneamente:
ng serve mfe-app-host
ng serve mfe-dashboard-one
ng serve mfe-dashboard-two
- Abrir
http://localhost:4200. - Navegar entre Home, Dashboard One e Dashboard Two.
- Confirmar que gráficos são renderizados corretamente e que não há duplicação de dependências.
7. Boas Práticas
- Single Version de bibliotecas compartilhadas para evitar bugs.
- Componentes standalone para fácil integração.
- Lazy Loading de módulos para performance.
- Documentar remotes: URLs, módulos expostos, dependências.
- Testes de integração entre host e remotes.
Conclusão
Nesta parte, construímos uma aplicação Angular com host e dois remotes, usando Module Federation. Aprendemos:
- Configuração do webpack e Module Federation.
- Rotas dinâmicas e carregamento assíncrono.
- Criação de dashboards interativos com Chart.js.
- Compartilhamento de estado e boas práticas para micro front-ends.
Na Parte 4, vamos abordar estratégias avançadas, incluindo deploys independentes, versionamento, troubleshooting e integração com CI/CD.