DEV Community

Hernani Almeida
Hernani Almeida

Posted on

Desacoplando Frontend com Module Federation no Angular 21 — Parte 1

Neste artigo vamos atualizar o conceito apresentado no artigo original "Desacoplando frontend com module-federation Angular - Parte 1", adaptando o projeto para o Angular 21 e para a arquitetura moderna de Micro Frontends.

Nota: no Angular moderno, a abordagem recomendada para manter o conceito de Module Federation sem depender do Webpack é utilizar o Native Federation. Ele utiliza ES Modules, Import Maps e integra-se ao Application Builder baseado em esbuild do Angular.

O objetivo continua sendo o mesmo:

  • Criar uma aplicação Shell/Host;
  • Criar aplicações Remote/Micro Frontends;
  • Permitir que o Shell carregue os Micro Frontends em runtime;
  • Manter cada aplicação com seu próprio código e deploy;
  • Reduzir o acoplamento entre as aplicações.

O que são Micro Frontends?

O conceito de Micro Frontends é semelhante ao conceito de Microservices.

Em vez de termos uma única aplicação frontend grande, podemos dividir a aplicação em partes menores, cada uma responsável por uma determinada área funcional.

Por exemplo:

                    ┌─────────────────────┐
                    │      SHELL          │
                    │     Angular 21      │
                    └──────────┬──────────┘
                               │
              ┌────────────────┼────────────────┐
              │                │                │
              ▼                ▼                ▼
        ┌───────────┐    ┌───────────┐    ┌───────────┐
        │   MFE 1   │    │   MFE 2   │    │   MFE 3   │
        │  Crédito  │    │   Conta   │    │   Growth  │
        └───────────┘    └───────────┘    └───────────┘
Enter fullscreen mode Exit fullscreen mode

Cada Micro Frontend pode possuir:

  • seu próprio código;
  • seu próprio pipeline;
  • seu próprio deploy;
  • sua própria equipe;
  • seu próprio ciclo de desenvolvimento.

Para o usuário final, entretanto, tudo pode aparecer como uma única aplicação.


O que mudou desde o Angular utilizado no artigo original?

No artigo original utilizamos:

Angular
   +
Webpack
   +
Module Federation
   +
AppModule
   +
AppRoutingModule
Enter fullscreen mode Exit fullscreen mode

No Angular 21, temos uma arquitetura mais moderna:

Angular 21
   +
Standalone Components
   +
Application Builder / esbuild
   +
Native Federation
   +
ES Modules
   +
Import Maps
Enter fullscreen mode Exit fullscreen mode

O Native Federation mantém a mesma ideia conceitual do Module Federation, mas não depende do Webpack. A implementação utiliza padrões nativos do navegador, como ES Modules e Import Maps.


Ferramentas necessárias

Para acompanhar este exemplo, recomendo:

  • Node.js
  • Angular CLI
  • VS Code
  • npm

Verifique as versões:

node -v

npm -v

ng version
Enter fullscreen mode Exit fullscreen mode

Neste exemplo vamos utilizar:

Angular 21
Angular CLI 21
TypeScript compatível com Angular 21
Enter fullscreen mode Exit fullscreen mode

1. Criando o workspace

Vamos criar uma pasta para nosso exemplo:

mkdir artigo-mfe

cd artigo-mfe
Enter fullscreen mode Exit fullscreen mode

Agora vamos criar nossa aplicação Shell:

ng new mfe-host
Enter fullscreen mode Exit fullscreen mode

Durante a criação, podemos utilizar:

Routing: Yes
Stylesheet: CSS
Enter fullscreen mode Exit fullscreen mode

Entre no projeto:

cd mfe-host
Enter fullscreen mode Exit fullscreen mode

Abra o projeto no VS Code:

code .
Enter fullscreen mode Exit fullscreen mode

2. Criando os Micro Frontends

Vamos voltar para a pasta principal:

cd ..
Enter fullscreen mode Exit fullscreen mode

Agora criaremos dois Micro Frontends:

ng new mfe-1
Enter fullscreen mode Exit fullscreen mode

e:

ng new mfe-2
Enter fullscreen mode Exit fullscreen mode

Ao final teremos:

artigo-mfe/
│
├── mfe-host/
│
├── mfe-1/
│
└── mfe-2/
Enter fullscreen mode Exit fullscreen mode

Nosso objetivo será:

mfe-host
   │
   ├── /mfe-1 → mfe-1
   │
   └── /mfe-2 → mfe-2
Enter fullscreen mode Exit fullscreen mode

3. Configurando o MFE-1

Entre no projeto:

cd mfe-1
Enter fullscreen mode Exit fullscreen mode

Agora vamos adicionar o Native Federation:

ng add @angular-architects/native-federation --project mfe-1 --port 4201 --type remote
Enter fullscreen mode Exit fullscreen mode

O ng add configura automaticamente a aplicação para atuar como um Remote.

O pacote fornece integração com o Angular CLI e com o Application Builder baseado em esbuild.


4. Configurando o MFE-2

Volte para a raiz:

cd ..
Enter fullscreen mode Exit fullscreen mode

Entre no segundo Micro Frontend:

cd mfe-2
Enter fullscreen mode Exit fullscreen mode

Execute:

ng add @angular-architects/native-federation --project mfe-2 --port 4202 --type remote
Enter fullscreen mode Exit fullscreen mode

Agora temos:

mfe-1 → http://localhost:4201

mfe-2 → http://localhost:4202
Enter fullscreen mode Exit fullscreen mode

5. Configurando o Shell

Volte para a raiz:

cd ..
Enter fullscreen mode Exit fullscreen mode

Entre no Shell:

cd mfe-host
Enter fullscreen mode Exit fullscreen mode

Agora configuraremos o projeto como um Dynamic Host:

ng add @angular-architects/native-federation --project mfe-host --port 4200 --type dynamic-host
Enter fullscreen mode Exit fullscreen mode

O dynamic-host é importante porque permite que os Micro Frontends sejam definidos através de um manifesto.

Essa abordagem também permite alterar os endpoints dos Micro Frontends durante o deploy sem precisar recompilar o Shell.


6. Estrutura do projeto

Depois da configuração teremos aproximadamente:

mfe-host/
│
├── src/
│   ├── app/
│   ├── assets/
│   │   └── federation.manifest.json
│   │
│   ├── main.ts
│   └── bootstrap.ts
│
├── federation.config.js
└── package.json
Enter fullscreen mode Exit fullscreen mode

A configuração de federation ficará separada da configuração normal do Angular.


7. Configurando o MFE-1

No projeto mfe-1, teremos um arquivo:

federation.config.js
Enter fullscreen mode Exit fullscreen mode

Uma configuração semelhante a:

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

module.exports = withNativeFederation({

  name: 'mfe-1',

  exposes: {
    './Component': './src/app/app.component.ts',
  },

  shared: {
    ...shareAll({
      singleton: true,
      strictVersion: true,
      requiredVersion: 'auto',
    }),
  },

  skip: [
    'rxjs/ajax',
    'rxjs/fetch',
    'rxjs/testing',
    'rxjs/webSocket',
  ],

});
Enter fullscreen mode Exit fullscreen mode

O ponto mais importante aqui é:

exposes: {
  './Component': './src/app/app.component.ts',
}
Enter fullscreen mode Exit fullscreen mode

Estamos dizendo:

Quando outro aplicativo solicitar ./Component, entregue o AppComponent deste Micro Frontend.

O host não precisa conhecer o caminho físico do arquivo.

Ele conhece apenas:

./Component
Enter fullscreen mode Exit fullscreen mode

Essa é uma das ideias fundamentais da Federation.


8. Configurando o MFE-2

No projeto mfe-2, faça a mesma configuração:

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

module.exports = withNativeFederation({

  name: 'mfe-2',

  exposes: {
    './Component': './src/app/app.component.ts',
  },

  shared: {
    ...shareAll({
      singleton: true,
      strictVersion: true,
      requiredVersion: 'auto',
    }),
  },

  skip: [
    'rxjs/ajax',
    'rxjs/fetch',
    'rxjs/testing',
    'rxjs/webSocket',
  ],

});
Enter fullscreen mode Exit fullscreen mode

Agora temos dois Remotes:

mfe-1
  └── ./Component

mfe-2
  └── ./Component
Enter fullscreen mode Exit fullscreen mode

9. Configurando o Manifest

Agora vamos para o projeto:

mfe-host
Enter fullscreen mode Exit fullscreen mode

Procure:

src/assets/federation.manifest.json
Enter fullscreen mode Exit fullscreen mode

Configure:

{
  "mfe-1": "http://localhost:4201/remoteEntry.json",
  "mfe-2": "http://localhost:4202/remoteEntry.json"
}
Enter fullscreen mode Exit fullscreen mode

O Manifest funciona como um mapa:

mfe-1 → http://localhost:4201/remoteEntry.json

mfe-2 → http://localhost:4202/remoteEntry.json
Enter fullscreen mode Exit fullscreen mode

Uma diferença importante em relação ao artigo original é que agora não trabalhamos diretamente com:

remoteEntry.js
Enter fullscreen mode Exit fullscreen mode

como acontecia no Module Federation baseado em Webpack.

O Native Federation utiliza metadados e módulos ES, sendo o remoteEntry.json utilizado pelo mecanismo para descobrir os recursos publicados pelo Remote.


10. Como o Manifest funciona?

O fluxo é aproximadamente:

                  Browser
                     │
                     ▼
                federation
                 manifest
                     │
          ┌──────────┴──────────┐
          │                     │
          ▼                     ▼
       mfe-1                 mfe-2
          │                     │
          ▼                     ▼
 remoteEntry.json        remoteEntry.json
          │                     │
          ▼                     ▼
    Component              Component
Enter fullscreen mode Exit fullscreen mode

O Shell não precisa conhecer previamente todo o código dos Micro Frontends.

Ele conhece apenas:

nome do remote
        +
endereço do remote
        +
nome do recurso exposto
Enter fullscreen mode Exit fullscreen mode

11. Inicialização do Federation

O ng add também configura o processo de inicialização.

O main.ts terá uma estrutura semelhante a:

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));
Enter fullscreen mode Exit fullscreen mode

O processo é:

main.ts
   │
   ▼
initFederation()
   │
   ▼
federation.manifest.json
   │
   ├── mfe-1
   │
   └── mfe-2
   │
   ▼
bootstrap.ts
   │
   ▼
Angular Application
Enter fullscreen mode Exit fullscreen mode

A inicialização do Federation acontece antes do bootstrap da aplicação Angular.


12. Configurando as rotas do Shell

Agora vamos configurar o carregamento dos Micro Frontends.

No Angular 21 podemos utilizar Standalone APIs.

Crie ou altere:

src/app/app.routes.ts
Enter fullscreen mode Exit fullscreen mode

Utilize:

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

export const routes: Routes = [

  {
    path: 'mfe-1',
    loadComponent: () =>
      loadRemoteModule('mfe-1', './Component')
        .then((m) => m.AppComponent),
  },

  {
    path: 'mfe-2',
    loadComponent: () =>
      loadRemoteModule('mfe-2', './Component')
        .then((m) => m.AppComponent),
  },

];
Enter fullscreen mode Exit fullscreen mode

Observe a diferença em relação ao artigo original.

Antes tínhamos:

loadChildren()
Enter fullscreen mode Exit fullscreen mode

e:

AppModule
Enter fullscreen mode Exit fullscreen mode

Agora podemos trabalhar diretamente com:

loadComponent()
Enter fullscreen mode Exit fullscreen mode

e:

AppComponent
Enter fullscreen mode Exit fullscreen mode

Isso acontece porque o Angular moderno utiliza Standalone Components como abordagem principal.

O Native Federation suporta esse modelo diretamente.


13. Configurando o AppComponent do Shell

No:

mfe-host/src/app/app.component.html
Enter fullscreen mode Exit fullscreen mode

podemos utilizar:

<div>
  <h1>Angular 21 - Micro Frontends</h1>

  <nav>
    <a routerLink="/mfe-1">
      Acesse MFE-1
    </a>

    <br />

    <a routerLink="/mfe-2">
      Acesse MFE-2
    </a>
  </nav>
</div>

<hr />

<router-outlet></router-outlet>
Enter fullscreen mode Exit fullscreen mode

Agora teremos:

Angular 21 - Micro Frontends

Acesse MFE-1

Acesse MFE-2
Enter fullscreen mode Exit fullscreen mode

14. Configurando o MFE-1

Vamos alterar o componente do mfe-1.

Por exemplo:

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  standalone: true,
  template: `
    <div>
      <h2>MFE-1</h2>

      <p>
        Este conteúdo foi carregado remotamente.
      </p>
    </div>
  `,
})
export class AppComponent {
}
Enter fullscreen mode Exit fullscreen mode

15. Configurando o MFE-2

No mfe-2:

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  standalone: true,
  template: `
    <div>
      <h2>MFE-2</h2>

      <p>
        Este conteúdo também foi carregado remotamente.
      </p>
    </div>
  `,
})
export class AppComponent {
}
Enter fullscreen mode Exit fullscreen mode

16. Subindo os projetos

Agora precisamos executar os três projetos.

Terminal 1 — MFE-1

cd mfe-1

ng serve
Enter fullscreen mode Exit fullscreen mode

Aplicação:

http://localhost:4201
Enter fullscreen mode Exit fullscreen mode

Terminal 2 — MFE-2

cd mfe-2

ng serve
Enter fullscreen mode Exit fullscreen mode

Aplicação:

http://localhost:4202
Enter fullscreen mode Exit fullscreen mode

Terminal 3 — Shell

cd mfe-host

ng serve
Enter fullscreen mode Exit fullscreen mode

Aplicação:

http://localhost:4200
Enter fullscreen mode Exit fullscreen mode

17. Testando

Abra:

http://localhost:4200
Enter fullscreen mode Exit fullscreen mode

Clique:

Acesse MFE-1
Enter fullscreen mode Exit fullscreen mode

O Shell irá executar:

loadRemoteModule('mfe-1', './Component')
Enter fullscreen mode Exit fullscreen mode

O Native Federation irá localizar:

mfe-1
Enter fullscreen mode Exit fullscreen mode

no:

federation.manifest.json
Enter fullscreen mode Exit fullscreen mode

e descobrir:

http://localhost:4201/remoteEntry.json
Enter fullscreen mode Exit fullscreen mode

Depois carregará:

./Component
Enter fullscreen mode Exit fullscreen mode

que aponta para:

mfe-1/src/app/app.component.ts
Enter fullscreen mode Exit fullscreen mode

O resultado será:

┌──────────────────────────────────┐
│          MFE-HOST                │
│                                  │
│  Acesse MFE-1                    │
│  Acesse MFE-2                    │
│                                  │
│  ┌────────────────────────────┐  │
│  │           MFE-1            │  │
│  │                            │  │
│  │ Conteúdo carregado         │  │
│  │ remotamente                │  │
│  └────────────────────────────┘  │
│                                  │
└──────────────────────────────────┘
Enter fullscreen mode Exit fullscreen mode

18. O que está acontecendo por baixo?

Quando acessamos:

http://localhost:4200/mfe-1
Enter fullscreen mode Exit fullscreen mode

o Angular Shell não possui necessariamente o código do mfe-1 no bundle inicial.

O fluxo é:

Browser
   │
   ▼
Angular Shell
   │
   ▼
Router
   │
   ▼
loadRemoteModule()
   │
   ▼
federation.manifest.json
   │
   ▼
mfe-1
   │
   ▼
remoteEntry.json
   │
   ▼
./Component
   │
   ▼
AppComponent
Enter fullscreen mode Exit fullscreen mode

Isso permite que o Micro Frontend seja desenvolvido e publicado separadamente.


19. Compartilhamento de dependências

Outro ponto importante da Federation é o compartilhamento de dependências.

Nossa configuração possui:

shared: {
  ...shareAll({
    singleton: true,
    strictVersion: true,
    requiredVersion: 'auto',
  }),
}
Enter fullscreen mode Exit fullscreen mode

Isso permite compartilhar bibliotecas entre o Shell e os Micro Frontends.

Por exemplo:

Shell
 └── Angular

MFE-1
 └── Angular

MFE-2
 └── Angular
Enter fullscreen mode Exit fullscreen mode

Em vez de necessariamente carregar múltiplas cópias das mesmas dependências, o Federation pode compartilhar essas bibliotecas.

O singleton: true é especialmente importante para bibliotecas que devem possuir uma única instância no runtime, como as principais bibliotecas do Angular.


20. Por que utilizar Native Federation no Angular 21?

No artigo original utilizamos:

Webpack Module Federation
Enter fullscreen mode Exit fullscreen mode

Essa abordagem continua sendo importante e o ecossistema de Module Federation continua evoluindo.

Porém, para um projeto novo utilizando Angular 21, o Native Federation é uma opção muito interessante porque:

  • integra-se ao Application Builder do Angular;
  • utiliza esbuild;
  • trabalha com ES Modules;
  • utiliza Import Maps;
  • não depende diretamente do Webpack;
  • mantém o modelo mental do Module Federation;
  • suporta Standalone Components;
  • suporta SSR;
  • possui versões alinhadas às versões do Angular.

21. Estrutura final

Ao final desta primeira parte teremos:

artigo-mfe/
│
├── mfe-host/
│   │
│   ├── src/
│   │   ├── app/
│   │   │   ├── app.component.ts
│   │   │   └── app.routes.ts
│   │   │
│   │   ├── assets/
│   │   │   └── federation.manifest.json
│   │   │
│   │   ├── main.ts
│   │   └── bootstrap.ts
│   │
│   ├── federation.config.js
│   └── package.json
│
├── mfe-1/
│   │
│   ├── src/
│   │   └── app/
│   │       └── app.component.ts
│   │
│   ├── federation.config.js
│   └── package.json
│
└── mfe-2/
    │
    ├── src/
    │   └── app/
    │       └── app.component.ts
    │
    ├── federation.config.js
    └── package.json
Enter fullscreen mode Exit fullscreen mode

Conclusão

Neste artigo configuramos uma arquitetura de Micro Frontends utilizando Angular 21 + Native Federation.

Criamos:

                 Angular 21
                     │
                     ▼
              ┌─────────────┐
              │    HOST     │
              │    :4200    │
              └──────┬──────┘
                     │
          ┌──────────┴──────────┐
          │                     │
          ▼                     ▼
   ┌─────────────┐       ┌─────────────┐
   │    MFE-1    │       │    MFE-2    │
   │    :4201    │       │    :4202    │
   └─────────────┘       └─────────────┘
Enter fullscreen mode Exit fullscreen mode

O Shell é responsável pela experiência principal da aplicação, enquanto os Micro Frontends podem ser desenvolvidos e publicados de forma independente.

Na próxima parte podemos avançar para uma arquitetura mais próxima de um cenário real, trabalhando com:

  • múltiplas páginas dentro de cada Micro Frontend;
  • loadChildren() com rotas remotas;
  • comunicação entre Shell e Micro Frontends;
  • compartilhamento de serviços;
  • autenticação;
  • Angular Material;
  • gerenciamento de estado;
  • deploy independente;
  • ambientes DEV, HML e PROD;
  • versionamento dos Micro Frontends;
  • tratamento de indisponibilidade de um Remote;
  • arquitetura recomendada para projetos corporativos.

Troubleshooting — Problemas na instalação do Native Federation

Durante a configuração do Native Federation, o comando apresentado no artigo pode apresentar erro dependendo da versão do Angular instalada no ambiente.

O comando inicial utilizado no artigo é:

ng add @angular-architects/native-federation --project mfe-remote-2 --port 4201 --type remote
Enter fullscreen mode Exit fullscreen mode

Em alguns ambientes, o Angular CLI pode não conseguir encontrar automaticamente uma versão compatível do pacote.

Um exemplo de erro é:

Could not find a compatible version with `latest`.
Searching for a compatible version.

Cannot read properties of undefined (reading 'latest')

An unhandled exception occurred:
Cannot read properties of undefined (reading 'latest')
Enter fullscreen mode Exit fullscreen mode

Esse problema está relacionado à resolução automática da versão do pacote e não necessariamente a um problema no projeto Angular.

1. Verifique a versão do Angular

Antes de corrigir o problema, execute:

ng version
Enter fullscreen mode Exit fullscreen mode

Por exemplo:

Angular CLI       : 21.2.25
Angular           : 21.2.25
Node.js           : 24.15.0
Package Manager   : npm 12.2.0
Enter fullscreen mode Exit fullscreen mode

A versão do Angular deve ser utilizada para escolher uma versão compatível do Native Federation.


2. Instale uma versão compatível manualmente

Caso o ng add apresente o erro descrito acima, em vez de utilizar o latest, instale explicitamente uma versão compatível.

Para um projeto utilizando Angular 21.2.x, por exemplo:

npm install @angular-architects/native-federation@21.2.6 --save-dev
Enter fullscreen mode Exit fullscreen mode

Depois execute o schematic:

ng generate @angular-architects/native-federation:init \
  --project mfe-remote-2 \
  --port 4201 \
  --type remote
Enter fullscreen mode Exit fullscreen mode

No Windows/Git Bash, o comando também pode ser executado em uma única linha:

ng generate @angular-architects/native-federation:init --project mfe-remote-2 --port 4201 --type remote
Enter fullscreen mode Exit fullscreen mode

3. Regra geral

A ideia é utilizar uma versão do Native Federation compatível com a versão principal do Angular do projeto.

Por exemplo:

Angular 21.x
     ↓
Native Federation 21.x
Enter fullscreen mode Exit fullscreen mode

Portanto, se estiver utilizando outra versão do Angular, primeiro verifique:

ng version
Enter fullscreen mode Exit fullscreen mode

e então consulte a versão do @angular-architects/native-federation compatível com essa versão.

Evite simplesmente instalar a versão latest quando o Angular CLI não conseguir determinar automaticamente uma versão compatível.


4. Caso tenha instalado uma versão incorreta

Se uma tentativa anterior instalou uma versão incompatível, remova o pacote:

npm uninstall @angular-architects/native-federation
Enter fullscreen mode Exit fullscreen mode

Limpe a instalação:

rm -rf node_modules package-lock.json
Enter fullscreen mode Exit fullscreen mode

No Windows PowerShell, utilize:

Remove-Item -Recurse -Force node_modules
Remove-Item package-lock.json
Enter fullscreen mode Exit fullscreen mode

Depois reinstale as dependências:

npm install
Enter fullscreen mode Exit fullscreen mode

E instale novamente a versão compatível:

npm install @angular-architects/native-federation@21.2.6 --save-dev
Enter fullscreen mode Exit fullscreen mode

Por fim:

ng generate @angular-architects/native-federation:init --project mfe-remote-2 --port 4201 --type remote
Enter fullscreen mode Exit fullscreen mode

5. Resumo

Se o comando original funcionar:

ng add @angular-architects/native-federation --project mfe-remote-2 --port 4201 --type remote
Enter fullscreen mode Exit fullscreen mode

continue normalmente com o tutorial.

Caso apareça:

Could not find a compatible version with `latest`
Enter fullscreen mode Exit fullscreen mode

faça:

ng version
Enter fullscreen mode Exit fullscreen mode

identifique a versão do Angular e instale manualmente uma versão compatível do Native Federation:

npm install @angular-architects/native-federation@<versao-compativel> --save-dev
Enter fullscreen mode Exit fullscreen mode

e execute o schematic:

ng generate @angular-architects/native-federation:init \
  --project mfe-remote-2 \
  --port 4201 \
  --type remote
Enter fullscreen mode Exit fullscreen mode

Importante: as versões dos pacotes podem mudar ao longo do tempo. Portanto, sempre verifique a compatibilidade entre a versão do Angular instalada no projeto e a versão do Native Federation utilizada.

Link parte 2

Referências

  • Artigo original: Desacoplando frontend com module-federation Angular - Parte 1.
  • Angular Architects — Micro Frontends with Modern Angular.
  • Angular Architects — Native Federation.
  • Documentação do @angular-architects/native-federation.

Top comments (0)