Micro Frontends: Como dividir para conquistar e o poder do Module Federation
Hoje estarei falando um pouco sobre a arquitetura de Micro Frontends, um padrão que vem ganhando muita força para resolver gargalos de escalabilidade em times grandes, e dando alguns exemplos de como implementá-la na prática utilizando Module Federation, além de pontuar os desafios reais dessa abordagem.
Micro Frontends aplicam os conceitos de microsserviços no navegador, dividindo a aplicação em fatias independentes por domínio de negócio.
Eles permitem que múltiplos times trabalhem em repositórios separados, usando até tecnologias diferentes, e façam deploys de forma independente.
O Module Federation (introduzido no Webpack 5 e agora presente em bundlers modernos como Rspack e Vite) é o divisor de águas que tornou a orquestração no cliente muito mais eficiente.
O problema do front-monólito
Quem nunca trabalhou em uma aplicação SPA (Single Page Application) que começou pequena, ágil e divertida de mexer, mas com o passar dos anos virou um monstro? Em aplicações front-end monolíticas de grande porte, os problemas começam a se acumular rapidamente.
O tempo de build dispara (às vezes passando de dezenas de minutos). Qualquer mudança simples, como ajustar a cor de um botão ou corrigir um bug de CSS no carrinho de compras, exige o deploy da aplicação inteira. Além disso, os times começam a pisar no calo uns dos outros: conflitos de merge diários no package.json, testes quebrando por efeitos colaterais em outras partes do sistema e uma lentidão generalizada na entrega de valor.
Foi para curar essa dor de escala organizacional e técnica que nasceram os Micro Frontends.
O que são (fatias por domínio, não por camada)
A ideia central é simples: pegar sua aplicação gigante e quebrá-la em pedaços menores e independentes. No entanto, o grande erro de quem começa a estudar o tema é tentar fatiar por componentes genéricos (ex: criar um micro frontend só para o Header ou só para um botão).
A regra de ouro dos Micro Frontends é o fatiamento vertical por domínio de negócio, assim como fazemos em microsserviços no backend.
Por exemplo, em um e-commerce, você teria:
Um Micro Frontend para o Catálogo de Produtos (responsável pela listagem e busca).
Um Micro Frontend para o Checkout (carrinho, pagamento, frete).
Um Micro Frontend para o Perfil do Usuário (histórico de pedidos, dados pessoais).
Dessa forma, o time de Checkout pode lançar uma feature nova de pagamento PIX sem correr o risco de quebrar a página de listagem de produtos.
Onde compor: cliente, servidor ou build?
Existem várias formas de juntar esses pedaços isolados para que o usuário final veja apenas uma única aplicação coesa. A composição pode acontecer em três momentos diferentes:
No momento do Build: Publicando cada pedaço como um pacote NPM privado. Problema: Perde-se a vantagem do deploy independente. Se o time de Checkout atualizar o pacote, a aplicação "host" (casca) precisa ser recompilada e redeployada.
No Servidor (Server-side): Usando técnicas como Server Side Includes (SSI), Edge Side Includes (ESI) em CDNs, ou roteamento via Next.js/Nuxt. Ótimo para SEO, mas a configuração de infraestrutura pode ficar bem complexa.
No Cliente (Client-side): A composição acontece direto no navegador. Historicamente, isso era feito com iframes (isolamento perfeito, mas péssima usabilidade e performance) ou Web Components. Hoje, a abordagem moderna e dominante é o uso de importações dinâmicas via Module Federation.
Module Federation na prática
O Module Federation mudou o jogo da composição no cliente. Ele permite que uma aplicação JavaScript carregue dinamicamente o código de outra aplicação em tempo de execução (runtime), compartilhando dependências para não baixar a mesma biblioteca duas vezes.
Veja um exemplo simplificado de como expomos o nosso Micro Frontend de Checkout (App Remoto) configurando o webpack.config.js:
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: "checkoutApp",
filename: "remoteEntry.js", // O arquivo que o app casca vai ler
exposes: {
"./Pagamento": "./src/components/Pagamento", // Expõe o componente de pagamento
},
shared: { react: { singleton: true }, "react-dom": { singleton: true } },
}),
],
};E na nossa aplicação principal (App Host), nós consumimos esse módulo dinamicamente. Caso o React já tenha sido carregado pelo Host, o checkoutApp usa a versão em memória, economizando banda e mantendo o contexto do React intacto.
Os desafios reais (nem tudo são flores)
Adotar Micro Frontends resolve o gargalo dos times, mas transfere a complexidade para a arquitetura e operação. Antes de mergulhar de cabeça, você precisa dominar estes quatro pilares:
Dependências: O Module Federation ajuda, mas gerenciar versões de bibliotecas (como React, Lodash, ou ferramentas de UI) entre vários times exige contratos rígidos. Se um micro frontend exige React 19 e outro exige React 17, a aplicação pode quebrar ou ficar super pesada.
Consistência Visual: Como garantir que a aplicação não pareça um "Frankenstein"? É obrigatório ter um Design System forte e versionado, para que botões, tipografias e formulários tenham o mesmo visual independente de qual time os desenvolveu.
Comunicação: Micro frontends devem ser o mais isolados possível, mas às vezes eles precisam conversar (ex: o Catálogo avisa o Checkout que um item foi adicionado). A regra é usar abordagens reativas desacopladas (Custom Events do navegador ou uma camada global de pub/sub mínima), nunca passando funções complexas via propriedades inter-aplicações.
Operação e Debug: Implementar CI/CD para 10 repositórios diferentes dá trabalho. Além disso, rastrear um bug que começa na casca, passa pela rota do catálogo e quebra no checkout exige ferramentas avançadas de monitoramento, logs centralizados (como Sentry) e Error Boundaries no React para impedir que o erro de um micro frontend derrube a tela inteira.
Boas práticas e quando NÃO usar
O isolamento deve ser respeitado a todo custo. Isole seu CSS (CSS Modules, Styled Components ou Tailwind com prefixos) para que um micro frontend não sobrescreva a cor do outro. Sempre trate falhas de rede no carregamento dos remotos utilizando fallbacks visuais (como o Suspense do React).
Quando NÃO usar?
Micro Frontend não é bala de prata. Se você tem um time pequeno (menos de 30 desenvolvedores no front-end), atua num produto único ou está em uma startup ainda validando o modelo de negócios, fique no monólito. A complexidade de orquestrar repositórios, CI/CDs e rotas dinâmicas vai atrasar suas entregas em vez de acelerá-las.
Conclusões finais
A arquitetura de Micro Frontends é incrivelmente poderosa para empresas que já atingiram a barreira da escala no front-end. Com a chegada do Module Federation, a barreira técnica para orquestrar essas aplicações no cliente caiu drasticamente, oferecendo performance e excelente experiência de desenvolvimento.
Ao meu ver a principal vantagem é a autonomia dos times, permitindo que cada squad foque em seu próprio domínio de negócio com deploys ágeis e independentes.
Espero que você tenha aproveitado alguma coisa do conteúdo apresentado.
Aqui no blog tem posts falando sobre outros padrões de arquitetura e design patterns, da uma olhada.
Acho que é isso, se tiver ficado com alguma dúvida ou tenha alguma sugestão escreve aqui nos comentários.