Micro Front-end com Module Federation: Estratégias Avançadas e Deploy
Parte 4 - Micro Front-end com Module Federation: Construindo Aplicações Extensíveis
Neste artigo
1. Versionamento e Independência de Remotes
Em projetos grandes, cada Remote Application deve poder evoluir de forma independente. Para isso:
1.1 Versão de Módulos Remotos
No webpack.config.js do Remote, podemos definir versões:
module.exports = withModuleFederationPlugin({
name: 'mfe-dashboard-one',
filename: 'remoteEntry.js',
exposes: { './Component': './src/app/app.component.ts' },
shared: {
...shareAll({
singleton: true,
strictVersion: true,
requiredVersion: '^1.0.0', // versão específica do remote
}),
},
});
requiredVersiongarante que o host carrega a versão correta do remote.- Atualizações no remote podem ser liberadas sem impactar a aplicação host, desde que respeitem o contrato de versão.
1.2 Estratégia de Deploy Independente
Cada remote pode ter seu próprio pipeline de CI/CD, por exemplo:
- Build independente:
ng build mfe-dashboard-one --prod - Deploy em CDN ou servidor separado:
/extensions/mfe-dashboard-one/remoteEntry.js - Atualização de rota no host: apenas atualizar
remoteEntrynoapp.routes.tsouroutes.json.
Isso permite escalabilidade e independência entre equipes.
2. Rotas Dinâmicas Avançadas
Rotas dinâmicas permitem que o host descubra remotes em runtime, útil quando novos módulos são adicionados sem deploy do host.
2.1 Configuração de Route Loader
route-loader.service.ts
import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Routes } from '@angular/router';
import { map, Observable } from 'rxjs';
import { loadRemoteModule } from '@angular-architects/module-federation';
@Injectable({ providedIn: 'root' })
export class RouteLoaderService {
private http = inject(HttpClient);
loadRoutes(): Observable<Routes> {
return this.http.get<any[]>('/routes.json').pipe(
map((routes) => routes.map(route => ({
path: route.path,
loadComponent: () =>
loadRemoteModule({
type: route.type,
remoteEntry: route.remoteEntry,
exposedModule: route.exposedModule,
}).then((m) => m.AppComponent),
})))
);
}
}
routes.json
[
{
"path":"mfe-app-01",
"type":"module",
"remoteEntry":"http://localhost:3000/extensions/mfe-app-01/remoteEntry.js",
"exposedModule":"./Component"
},
{
"path":"mfe-app-02",
"type":"module",
"remoteEntry":"http://localhost:3000/extensions/mfe-app-02/remoteEntry.js",
"exposedModule":"./Component"
}
]
- Permite adicionar novos remotes sem rebuild do host.
- Facilita deploys independentes e versionamento de rotas.
3. Estratégias de CI/CD para Micro Front-ends
Para equipes grandes, cada MFE deve ter pipeline própria, mantendo host e remotes sincronizados:
- Build e Test Unitário: cada remote executa testes isolados.
- Lint e Code Analysis: garante consistência entre remotes.
- Deploy em CDN ou S3: remotes ficam disponíveis publicamente via URL.
- Integração do Host: host consome remotes via
remoteEntry. - Monitoramento: usar ferramentas como Sentry ou Datadog para erros em runtime.
Exemplo de fluxo de deploy em CI:
name: MFE Dashboard One CI/CD
on:
push:
branches:
- main
jobs:
build-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: '20'
- run: npm install
- run: ng build mfe-dashboard-one --prod
- run: aws s3 sync ./dist/mfe-dashboard-one s3://cdn.example.com/extensions/mfe-dashboard-one --delete
- Cada remote é deployado separadamente, garantindo independência de release.
4. Troubleshooting e Debugging
MFE adiciona complexidade. Alguns problemas comuns:
- Erro de múltiplas versões do Angular
- Use
shared: shareAll({ singleton: true })no webpack. - Verifique
ng versionepackage.json.
- Use
- Rotas do remote não funcionam no host
- Configurar
APP_BASE_HREFno módulo do remote:
- Configurar
import { APP_BASE_HREF } from '@angular/common';
@NgModule({
providers: [{ provide: APP_BASE_HREF, useValue: '/' }],
})
export class AppModule {}
- Falha no carregamento do remote
- Verifique se
remoteEntry.jsestá acessível. - Teste com navegador ou
curl.
- Verifique se
- Componentes não aparecem
- Checar
exposesno webpack do remote. - Confirmar nome do componente exposto (
AppComponentou outro).
- Checar
5. Performance e Otimizações
- Lazy Loading obrigatório – só carregue o remote quando necessário.
- Tree Shaking – Angular e Webpack removem código não usado.
- Cacheamento do remoteEntry.js – usar headers HTTP:
Cache-Controlpara evitar downloads repetidos. - Compartilhamento de dependências – evita duplicação de Angular, RxJS e bibliotecas comuns.
- Monitoramento de bundle – usar
webpack-bundle-analyzerpara identificar módulos grandes.
6. Integração com Micro Front-end Dinâmico
Em grandes plataformas SaaS:
- Cada equipe publica seu módulo remoto.
- O host consome remotes via configuração central (
routes.json). - Novos módulos podem ser adicionados sem rebuild do host.
- Permite extensibilidade infinita, alinhada com arquiteturas plugin-based.
Exemplo de fluxo:
- Nova equipe cria
mfe-new-dashboard. - Publica em CDN com
remoteEntry.js. - Adiciona entrada em
routes.jsondo host. - Usuário final acessa o novo dashboard sem atualizar o host.
7. Comunicação Entre Módulos
Além de BehaviorSubject:
- Services Singleton: compartilhados via
sharedno webpack. - Event Bus: pequenas mensagens via
SubjectouRxJS. - LocalStorage/IndexedDB: compartilhamento de dados persistentes.
- Custom Events: browser native events para módulos isolados.
Exemplo:
// shared-event-bus.ts
import { Subject } from 'rxjs';
export const eventBus = new Subject<{ type: string, payload?: any }>();
- Host e remotes podem se inscrever no
eventBus. - Permite comunicação desacoplada sem dependência direta.
Conclusão
Nesta etapa avançada, abordamos:
- Versionamento e deploy independente de remotes.
- Rotas dinâmicas e runtime discovery.
- Estratégias de CI/CD para equipes distribuídas.
- Troubleshooting e boas práticas de debugging.
- Otimização de performance e compartilhamento de dependências.
- Comunicação eficiente entre host e remotes.
Essas técnicas permitem que equipes grandes construam sistemas escaláveis, modulares e de fácil manutenção, respeitando os princípios de micro front-end e Module Federation.