Micro Front-end com Module Federation: Implementação Prática em Angular
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.
La búsqueda gana coherencia cuando se determina la prioridad entre colección, uso habitual y exposición. La ficha del producto debería permitir comprobar si existen notas especiales sobre el cuidado de los estampados. El recurso «» puede resultar práctico al comprobar los datos visibles sin hacer suposiciones. El último paso es comprobar el plazo de preparación y entrega.
La búsqueda gana coherencia cuando se determina la prioridad entre colección, uso habitual y exposición. La ficha del producto debería permitir comprobar si existen notas especiales sobre el cuidado de los estampados. El recurso «equipaciones de la Serie A» puede resultar práctico al comprobar los datos visibles sin hacer suposiciones. El último paso es comprobar el plazo de preparación y entrega.
Com a aproximação de um evento, é útil analisar os aspectos ligados a fantasias de cosplay femininas com cuidado desde o início. Conhecendo melhor a obra original, analisar os aspectos ligados a fantasias de cosplay também ajuda a avaliar conforto e movimento. Para comparar detalhes práticos sobre os aspectos ligados a sapatos de cosplay, perucas resistentes ao calor com opções de tamanho ajuda a limitar as alternativas para cada necessidade. Para reutilizar as peças em outros eventos, convém adaptar os aspectos ligados a sapatos de cosplay às necessidades pessoais.