Padrões de Micro Frontends
A indústria de software através da disciplina da Engenharia de Software apresenta o conceito de padrão (pattern) inspirado no que outras áreas mais maduras já faziam, como a Engenharia Civil ou de Hardware. Havia a necessidade de documentar práticas de sucesso, identificar problemas recorrentes e suas soluções. Um padrão, de forma simples, é uma forma de documentar esses cenários para possibilitar, principalmente, o reúso de decisões estratégicas que envolvem os elementos de um sistema. Os padrões não são construções teóricas mas artefatos descobertos em mais de um sistema existente. Nas últimas décadas, vários autores fizeram grandes esforços para catalogar os padrões, que antes habitavam apenas nas mentes dos desenvolvedores experientes. Dessa forma, foram lançados os Design Patterns, e muitos softwares e sistemas do mundo todo puderam se beneficiar desse conhecimento [Rising 1998].
[Jackson 2019] catalogou como abordagens cinco possibilidades de implementação da arquitetura de MFEs. Essas abordagens já são observadas em prática no mercado de software e podem se enquadrar como padrões de Micro Frontend dada sua definição. O autor também observa que, para todas essas abordagens, há a necessidade de existir uma aplicação contêiner que se encarregue de:
- Exibir elementos em comum da página, como cabeçalho e rodapé;
- Tratar questões que atravessam as fronteiras das “micro aplicações”, como autenticação e navegação;
- Reunir as N aplicações MFEs em uma única página e indicar onde cada uma deve ser exibida.
![Aplicação contêiner em destaque azul que exibe a navegação e o micro frontend “busca” em destaque verde. Fonte: [Jackson 2019].](figuras/container-front.png)
As cinco abordagens catalogadas por [Jackson 2019] são descritas na sequência.
- Server-side template composition
- Build-time integration
- Run-time integration via iframes
- Run-time integration via JavaScript
- Run-time integration via Web Components
- Federação de Módulos
Server-side template composition
O padrão de composição de templates no lado servidor é a forma mais
clássica de fazer MFEs, que vem sido praticada antes mesmo desse
conceito ser formalizado. Neste padrão, existe uma página principal que
carrega a aplicação contêiner no documento index.html
.
Além dos elementos em comum, como cabeçalho, menu de navegação e rodapé, a aplicação contêiner contém instruções para inclusão de conteúdo dinamicamente por meio de variáveis do servidor. No servidor Web, é possível definir que uma variável seja preenchida com um valor informado por meio da URL solicitada. Assim, a variável é preenchida com um bloco de HTML entregue pela aplicação micro frontend solicitada, formando para o usuário final uma página completa (como ilustrado pela Figura 1).
O bloco de HTML pode pertencer a uma equipe dedicada, que o trata de forma distinta de outras partes do sistema completo, podendo ter seu próprio processo de construção, testes e implantação e, assim, não afetar outras áreas. Neste padrão, ainda é sugerida a possibilidade de a equipe ter seu próprio servidor, com um cache cuidadoso das respostas para evitar que a latência seja afetada. A Figura 2 ilustra múltiplos servidores.

Build-time integration
O padrão de integração no momento de construção é utilizado quando cada micro frontend é entregue como um pacote (package) para ser incluído como dependência na configuração da aplicação contêiner. Com isto, será produzido um único pacote JavaScript para implantação, o que traz benefícios caso os MFEs compartilhem das mesmas dependências. Porém, com esta abordagem, para que as mudanças em um único micro frontend sejam publicadas, é necessário que a aplicação contêiner seja reconstruída, assim exigindo a reconstrução dos outros MFEs que estão compondo o todo de maneira sincronizada e coordenada, processo também conhecido como (lockstep) e sujeito à falhas, no lançamento (release) da aplicação.
A abordagem de integração no momento de construção é a menos recomendada. Apesar de a composição em pacotes ser benéfica em alguns outros contextos, para o contexto de MFEs ela introduz problemas de acoplamento entre as diferentes aplicações no processo final de implantação e lançamento, impactando a autonomia dos times especializados em produtos.
Run-time integration via iframes
O padrão de integração em tempo de execução via iframes, assim como o
padrão de composição de templates no lado servidor, não é uma
técnica nova. O iframe (abreviação para inline frame)
é um recurso antigo para as páginas Web, foi introduzido em 1997 com
HTML 4.01 pelo navegador Internet Explorer da Microsoft através do
elemento <iframe>
. Este recurso permite incorporar um
documento HTML dentro de outro documento HTML. Esta opção é a abordagem
mais simples para iniciar a divisão de um monólito em pequenas
aplicações, porém muitas pessoas e equipes que desenvolvem aplicativos
não se interessam em adota-lá.
Considerando as principais característicos dos MFEs listadas anteriormente, os iframes são em sua maioria adequados para implementá-las, desde que haja cuidado em como dividir o aplicativo e estruturar as equipes. Por sua natureza, os iframes facilitam a construção de uma página a partir de subpáginas independentes. Eles também oferecem um bom grau de isolamento em termos de estilo e variáveis globais que não interferem entre si. Porém, esse fácil isolamento tende a torná-los menos flexíveis do que as outras opções. Pode ser difícil construir integrações entre os diferentes MFEs, por isso, com iframes, o roteamento, o histórico e os links diretos (deep-linking) ficam mais complicados. Além disso, os iframes apresentam alguns desafios extras para tornar uma página totalmente compatível com dispositivos móveis.
Run-time integration via JavaScript
O padrão de integração em tempo de execução via JavaScript, é utilizado
quando cada micro frontend é incluído na página da aplicação
contêiner usando uma tag <script>
e que,
após o carregamento da página, expõe uma função global como ponto de
entrada. A aplicação contêiner determina então qual micro
frontend deve ser montado e chama a função relevante para informar
ao micro frontend quando e onde deve ser exibido. Ao contrário
do padrão de integração no momento de construção, é possível implantar
cada um dos arquivos JavaScript de cada micro frontend de forma
independente. E, ao contrário dos padrão com iframes, tem-se
total flexibilidade para construir integrações entre os MFEs da maneira
desejada. Por exemplo, baixar apenas cada pacote JavaScript conforme
necessário ou passar dados para dentro ou para fora das aplicações ao
exibir um micro frontend. A flexibilidade desta abordagem,
combinada à capacidade de implementação independente, tem feito ela ser
adotada pelas equipes com mais frequência que as demais.
Run-time integration via Web Components
O padrão de integração em tempo de execução via Web Components é uma variação da abordagem de integração via JavaScript. Web Components é um padrão consolidado para criação de componentes customizados sem o uso de frameworks de frontend [Taibi e Mezzalira 2022]. Nesta abordagem, cada micro frontend define e cria um elemento HTML personalizado para a aplicação contêiner exibir, em vez de definir uma função global para a contêiner chamar. O resultado final é bastante semelhante ao padrão via JavaScript, a principal diferença é a equipe pode combinar com o padrão Web Components na composição de MFEs. Aqui a equipe deve decidir, de acordo com a preferência e domínio das técnicas, se prefere usar as especificações de Web Components e usar os recursos que o navegador oferece, ou definir sua própria interface entre o aplicativo contêiner e os MFEs através do padrão via JavaScript.
Os cinco padrões descritos acima foram mapeados por [Jackson 2019]. Porém, em 2020, um grande evento impactou a cena do desenvolvimento de frontend: o lançamento de uma tecnologia que também propôs um novo padrão para aplicações com arquitetura Micro Frontend. Zack Jackson e Tobias Koppers, criadores do Webpack – ferramenta de ampla adoção pelas equipes para o processo de empacotamento — anunciaram o lançamento do padrão Federação de Módulos (Module Federation). Na indústria de software, “federado” significa uma abordagem colaborativa, porém descentralizada e interoperável, para a construção de sistemas ou aplicativos.
Federação de Módulos
Este padrão permite que uma aplicação JavaScript carregue dinamicamente o código de outra aplicação menor. É um mix do melhor das integrações build-time e run-time via JavaScript, porém com o apoio ferramental do recurso para federação de módulos do Webpack. Por meio desse recurso, é possível associar várias aplicações separadas que agem como contêineres, com a possibilidade de expôr e consumir código de outras aplicações (como ilustrado na Figura 3), resultando em uma aplicação unificada para o usuário final.

Alguns conceitos gerais formam o padrão federação de módulos. As aplicações separadas poder ser distinguidas em módulos locais e módulos remotos, como ilustrado na Figura 4. Módulos locais são módulos regulares que fazem parte de uma mesma aplicação e são construídos (built) juntos. Módulos remotos são aqueles que não fazem parte da aplicação, portanto são construídos e empacotados em outro processo, porém são carregados em tempo de execução a partir de um contêiner remoto. Um contêiner é criado por meio de uma entrada (container entry), que expõe o acesso assíncrono aos módulos específicos. Os contêineres podem ser aninhados e também usar módulos de outros contêineres. Dependências circulares entre contêineres também são possíveis. Cada aplicação que tem seu próprio processo de construção (build) atua como um contêiner e também consome outras builds como contêineres. Dessa forma, cada build é capaz de acessar qualquer outro módulo exposto carregando-o de seu contêiner.

Módulos compartilhados são módulos substituíveis e fornecidos como substituições para contêineres aninhados. Eles geralmente apontam para o mesmo módulo em cada compilação, por exemplo, a mesma biblioteca.
O uso da ferramenta Webpack para implementar a arquitetura federação de módulos auxilia com a entrega de todos os benefícios dos MFEs e resolve alguns problemas conhecidos, como o de redundância de dependência, que é tratado com os módulos compartilhados. Ao mesmo tempo, a ferramenta cria a dependência tecnológica da mesma, forçando que todas as equipes utilizem o Webpack para o processo de build de suas aplicações [Webpack 2023], [Zack Jackson 2020], [Zack Jackson and Tobias Koppers 2020] .