Publicado em

- 4 minutos de leitura

Micro Frontends no Angular: Native Federation e Web Components

img of Micro Frontends no Angular: Native Federation e Web Components

Quem trabalha com Micro Frontends no Angular enfrentou uma mudança importante com a chegada do novo pipeline de build do Angular CLI. O framework trocou o Webpack pelo ApplicationBuilder, que junta esbuild para gerar o bundle de produção e Vite para o servidor de desenvolvimento.

O tempo de build caiu bastante, mas surgiu um problema prático: o Webpack Module Federation clássico parou de funcionar de forma nativa. Para resolver isso, duas opções se destacam hoje: o Native Federation e os Web Components com Angular Elements. Neste artigo, vamos ver o funcionamento de cada uma, o código de setup e quando escolher cada caminho.

O problema do Webpack no Angular moderno

Durante muito tempo, o Module Federation do Webpack foi a escolha padrão para carregar remotes em tempo de execução. Ele cuidava de carregar o código sob demanda e evitava baixar bibliotecas repetidas entre times diferentes.

O detalhe é que essa solução depende de plugins internos do Webpack. Quando o Angular adotou o ApplicationBuilder com esbuild, manter o Webpack passou a exigir builders customizados, como o @angular-builders/custom-webpack.

Na prática, isso traz dores de cabeça reais:

  • O build fica bem mais lento do que com esbuild.
  • Recursos novos do Angular, como hidratação parcial e SSR moderno, ficam difíceis de configurar.
  • Você fica preso a ferramentas antigas só para manter o roteamento de Micro Frontends funcionando.

Por isso, buscar uma alternativa que funcione direto com esbuild se tornou prioridade.

Como funciona o Native Federation

Criado por Manfred Steyer e mantido pela comunidade, o Native Federation resolve esse problema usando padrões nativos da web. Em vez de depender de código gerado por um bundler específico, ele usa ECMAScript Modules (ESM) e Import Maps do próprio navegador.

Isso significa que o Native Federation funciona tanto com esbuild quanto com Vite, Rollup ou qualquer outra ferramenta moderna.

O fluxo de funcionamento é bem simples:

  1. O Shell lê o arquivo remoteEntry.json de cada aplicação remote para saber quais módulos e versões estão disponíveis.
  2. O Native Federation processa as dependências e monta um Import Map no navegador para não baixar pacotes como @angular/core e rxjs duas vezes.
  3. O Angular Router carrega o componente remoto com loadComponent ou loadChildren, exatamente como faz com lazy loading comum.

Como usa ESM puro, o Native Federation funciona sem problemas com blocos @defer e SSR.

Imagem com o texto: Curso Dominando Agentes de IA como um robô a frente da logo do Angular. Logo abaixo existe um botão com o texto "Eu quero!"

Configurando Shell e Remote com Native Federation

Para configurar o projeto, usamos o pacote @angular-architects/native-federation. No Shell, o arquivo federation.config.js define quais dependências devem ser tratadas como singletons compartilhados:

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

module.exports = withNativeFederation({
	shared: {
		...shareAll({
			singleton: true,
			strictVersion: true,
			requiredVersion: 'auto'
		})
	}
})

No roteamento do Shell, usamos a função loadRemoteModule para carregar a tela remota:

   // app.routes.ts (Shell)
import { Routes } from '@angular/router'
import { loadRemoteModule } from '@angular-architects/native-federation'

export const routes: Routes = [
	{
		path: 'checkout',
		loadComponent: () =>
			loadRemoteModule({
				remoteEntry: 'http://localhost:4201/remoteEntry.json',
				exposedModule: './Component'
			}).then((m) => m.CheckoutComponent)
	}
]

Já no Remote, expomos o componente que o Shell vai carregar:

   // federation.config.js (Remote - Checkout)
const { withNativeFederation, shareAll } = require('@angular-architects/native-federation/config')

module.exports = withNativeFederation({
	name: 'checkout',
	exposes: {
		'./Component': './src/app/checkout/checkout.component.ts'
	},
	shared: {
		...shareAll({
			singleton: true,
			strictVersion: true,
			requiredVersion: 'auto'
		})
	}
})

Com o handshake de versões ativado, se o Shell e o Remote usarem a mesma versão do Angular, apenas uma cópia do runtime fica na memória.

Quando usar Web Components com Angular Elements

O Native Federation funciona muito bem quando todos os times usam Angular e mantêm versões próximas do framework. Mas existem cenários onde isso não acontece: times trabalhando com versões incompatíveis do Angular ou até misturando Angular com React.

Nesses casos, os Web Components com @angular/elements são a melhor opção de blindagem. O Angular Elements transforma um componente comum em um Custom Element nativo do navegador, isolado com Shadow DOM.

   // bootstrap-element.ts
import { createCustomElement } from '@angular/elements'
import { createApplication } from '@angular/platform-browser'
import { ProductCardComponent } from './product-card.component'

createApplication().then((appRef) => {
	const cardElement = createCustomElement(ProductCardComponent, {
		injector: appRef.injector
	})
	customElements.define('app-product-card', cardElement)
})

A grande vantagem é o isolamento de CSS via Shadow DOM e a liberdade de rodar qualquer versão sem conflitos de variáveis globais. O tradeoff principal é o tamanho final do bundle: cada Custom Element traz seu próprio runtime, o que aumenta o volume de dados baixados pelo usuário.

Comparativo de decisão técnica

A tabela abaixo resume as principais características de cada abordagem:

CritérioWebpack Module FederationNative FederationAngular Elements
Compatível com esbuild e Vite—✓✓
Compartilha Singletons na memória✓✓—
Isolamento de estilos com Shadow DOM——✓
Suporte a múltiplos frameworks——✓
Funciona com SSR e @defer—✓—
Sem plugins customizados de build—✓✓

Guia rápido para o dia a dia

Para decidir o caminho no seu projeto, siga este roteiro prático:

  1. Escolha Native Federation para projetos Angular padronizados: Se os times compartilham a mesma versão do Angular, o Native Federation dá o melhor resultado em velocidade de build e uso eficiente de memória.
  2. Use Web Components para legados e exceções: Se uma funcionalidade precisa ficar em uma versão antiga do Angular ou em outro framework, encapsule essa parte específica como Custom Element.
  3. Mantenha controle de versões com Monorepo: Ferramentas como o Nx ajudam a garantir que bibliotecas compartilhadas e design systems fiquem alinhados entre o Shell e os Remotes.

Conclusão

O ecossistema de Micro Frontends no Angular não depende mais de soluções presas ao Webpack. Com o Native Federation, você aproveita a velocidade do esbuild usando padrões abertos como Import Maps e ESM.

Ao mesmo tempo, os Web Components continuam sendo a ferramenta certa quando o foco principal é o isolamento total entre equipes. Entender esses tradeoffs ajuda a escolher a arquitetura mais simples e sustentável para o seu time.

Entre na nossa comunidade!

Receba novos posts, novidades do ecossistema Angular e muito mais.

Sobre o autor

Author's photo
Henrique Custódia Arquiteto Frontend, entusiasta Angular, cat lover, criador de conteúdo e fundador da Code Dimension!