Micro-frontends: Integração Estável de Múltiplos SPAs - Parte 2

Micro-frontends: Integração Estável de Múltiplos SPAs - Parte 2

Explore técnicas avançadas para compartilhar e isolar bibliotecas, implementar lazy loading e otimizar a arquitetura de micro-frontends, garantindo estabilidade e escalabilidade em aplicações web complexas.

MundiX News·01 de julho de 2026·8 min de leitura·👁 1 views

Na primeira parte, discutimos nossa abordagem para micro-frontends, federação de módulos e como as integrações são estruturadas. Nesta segunda parte, conforme prometido, abordaremos o compartilhamento e isolamento de bibliotecas, lazy loading, além de oferecer algumas dicas e recomendações.

Compartilhando Web Components

Nossas aplicações são autossuficientes, o que significa que elas não têm conhecimento direto umas das outras. Precisamos de uma maneira de compartilhar web components entre elas. Existem duas abordagens principais:

  1. Federação de Módulos com Exposes: Através da federação de módulos, podemos expor classes, módulos e outros artefatos, fornecendo as informações necessárias para o container. A desvantagem aqui é que criamos um contrato de baixo nível, estabelecendo acoplamentos desde a fase de desenvolvimento. Qualquer alteração futura exigirá a recompilação da aplicação.
  2. Arquivo JSON Estático: Podemos gerar um arquivo JSON estático, semelhante ao nosso metafile. O cliente receberia este JSON contendo informações sobre os web elements da aplicação. A desvantagem é que este arquivo é estático e sua modificação em tempo de execução pode ser problemática.

Optamos por utilizar os recursos da federação de módulos para o compartilhamento de bibliotecas. É crucial entender que isso vai além de simplesmente evitar a duplicação de versões de bibliotecas. Graças ao compartilhamento, podemos configurar bibliotecas como singletons em nossa configuração, garantindo que sejam carregadas apenas uma vez no sistema. Elas atuam como registradores ou barramentos, facilitando a comunicação entre os micro-frontends.

Dessa forma, formamos uma biblioteca widget registry, onde diferentes micro-frontends registram suas informações. Nossa plataforma ou outro componente pode então ler essa configuração e obter os dados necessários. Isso reduz significativamente o acoplamento, criando um ponto de interação unificado entre as aplicações. Se um produto decidir remover um widget ou web element, essa informação será refletida no registro atualizado, aumentando a estabilidade geral.

Lazy Load e Seus Benefícios

Discutimos web components como widgets, onde o dashboard principal é composto por eles. No entanto, um web component também pode servir como uma porta de entrada para uma aplicação web completa. Por exemplo, o módulo de monitoramento, como um produto separado, possui sua própria roteirização, módulos internos e múltiplas páginas. Carregar todo esse conjunto de uma vez não é uma abordagem eficiente.

Portanto, faz sentido utilizar o carregamento preguiçoso (lazy loading) de micro-frontends. Uma boa prática é ter múltiplos containers na aplicação. Criamos um container pequeno e leve que é carregado na inicialização, obtendo configurações específicas ou reagindo a eventos. O container maior e mais pesado, com a aplicação completa, é carregado sob demanda, apenas quando o usuário acessa a página correspondente. Todas as ferramentas necessárias para isso já estão disponíveis: router, element container, load remote.

Formamos outra biblioteca singleton, menu registry, semelhante aos nossos registradores. Diferentes micro-frontends registrarão suas informações, especialmente o segmento de URL e o web component que eles servirão. A plataforma lerá esses dados, formará um roteador dinâmico. O que acontece a seguir?

Quando o usuário navega para a seção "Monitoramento", verificamos se há algum registro para esse segmento. Em seguida, renderizamos o element container para o usuário e passamos todas as informações necessárias. O processo continua com:

  1. A função load remote é executada, carregando o container.
  2. O container inicializa e inicia a aplicação web.
  3. A aplicação web define e identifica o web element.
  4. Este web element é então montado na página.

É importante lembrar que cada web element possui seu próprio roteador e eles não têm conhecimento um do outro. É necessário configurá-los dinamicamente para evitar conflitos. Por exemplo, se definirmos que o segmento de responsabilidade da plataforma é "monitoramento", o roteador correspondente cuidará dessa seção. Tudo o que estiver fora dela já pertence ao roteador do produto.

No entanto, os roteadores também precisam ser sincronizados. Quando acessamos a seção "Monitoramento" e montamos um web element, a aplicação "Monitoramento" e seu roteador não têm conhecimento disso. Precisamos notificá-los que um determinado tag está sendo montado. A aplicação de monitoramento ouvirá isso e poderá iniciar a inicialização ou o roteador apropriado para renderizar o componente correspondente.

Por sua vez, a aplicação de monitoramento executa sua própria navegação ou escreve parâmetros de URL, tudo isso ocorrendo dentro do roteador da aplicação "Monitoramento". Ao sair para qualquer outra seção, perdemos essa informação e o estado é destruído (a navegação "Voltar/Avançar" do navegador também não tem conhecimento disso). Portanto, a cada mudança em seu roteador, os micro-frontends executam um sync, notificando uns aos outros sobre as alterações. As aplicações ao redor simplesmente ouvem esses eventos, e o URL atua como a fonte da verdade, permitindo que elas atualizem o estado de seus roteadores.

Podemos configurar essas interações através de dispatchEvents clássicos. Anteriormente, mencionamos que podemos descrever eventos de ciclo de vida para web components. Estamos nos movendo em direção a bibliotecas singleton, que oferecem bons pontos de extensão (tanto para sync quanto para mount, podemos adicionar novas funcionalidades, como navigate para transições entre micro-frontends).

Otimizando a Arquitetura

Discutimos web components e aplicações. Agora, vamos falar sobre compartilhamento e como otimizar tudo isso.

Possuímos as bibliotecas widget e menu, que atuam como registradores em nosso contexto. Precisamos de apenas uma cópia, portanto, as marcamos explicitamente como singleton: true.

javascript
new ModuleFederationPlugin({
  shared: {
    '@platform/widget-registry': { requiredVersion: '>=1.0.0', version: '1.0.0', singleton: true },
    '@platform/menu-registry': { requiredVersion: '>=1.0.0', version: '1.0.0', singleton: true },
    '@angular/*': { requiredVersion: '19.2.0', version: '19.2.0' },
    '@platform/buttons': { requiredVersion: '2.0.0', version: '2.0.0' } // ???
  }
});

Frameworks e Compartilhamento

Em relação a frameworks, especialmente Angular: não podemos impor nada rigidamente, mas podemos declarar que "Se as suas versões do Angular forem estritamente idênticas, a mesma aplicação pode reutilizar o Angular sem problemas." No entanto, bibliotecas escritas sobre nossos frameworks exigem atenção especial. Por exemplo, a biblioteca platform/buttons, parte do nosso UI kit, escrita sobre Angular. Pode parecer que, como sua versão 2.0 coincide com a da aplicação, podemos compartilhá-la.

Não podemos. Observe a imagem. Versões diferentes do Angular significam compiladores diferentes. Se pegarmos a mesma versão de botões, diferentes aplicações a compilarão de maneiras distintas, resultando em artefatos diferentes. Distribuir tal biblioteca não é possível. Mas se realmente quisermos, há uma solução.

Sabemos que o principal requisito da biblioteca buttons é a versão do Angular (seu principal peerDeps). Portanto, nossa aplicação "Monitoramento" é o fornecedor do framework que compilará e fornecerá essa biblioteca. Podemos também criar uma pequena utilidade auxiliar que receberá nossas necessidades: queremos compartilhar a biblioteca platform/buttons; seus peerDeps são Angular; então, precisamos consultar o JSON da aplicação "Monitoramento"; encontrar a versão do Angular; e com base nisso, criar uma versão sintética para a biblioteca. O resultado não será apenas a biblioteca 2.0, mas também uma menção com um sufixo indicando que é a versão 2.0 que vem com Angular 19.2.0.

Isso nos permite compartilhar a biblioteca de botões, mas apenas se a versão do Angular dessas bibliotecas coincidir (ou seja, se foram compiladas pelo mesmo compilador). Essa nuance é mais sensível em aplicações que incorporam instruções internas. Mas, tecnicamente, problemas podem surgir com bibliotecas comuns: se pegarmos a mesma biblioteca e diferentes aplicações fornecerem versões diferentes de peerDeps chave, isso pode criar conflitos.

Portanto, lembre-se: se uma biblioteca tem um peerDeps importante para seu funcionamento, ele também deve coincidir e ser compartilhado entre as aplicações.

Isolamento de Bibliotecas

Também vale mencionar bibliotecas que modificam o objeto Window (quando estendemos nossos objetos globais, e diferentes bibliotecas estendem as assinaturas de maneiras distintas). Na minha opinião, não há uma solução perfeita aqui, então restam medidas organizacionais. Por exemplo, simplesmente parar de fazer modificações e permanecer com uma das bibliotecas anteriores, ou aplicar um patch. Em resumo, garantir que tais bibliotecas possam coexistir em uma única página.

Quando se trata de uma abordagem arquitetônica que requer múltiplas versões, é comum encontrar um anti-padrão: "Menções são um dependency hell, nunca faça isso, é impossível trabalhar." E, em geral, sim, se você tiver um grande número de bibliotecas, elas entrarão em conflito. Imagine um zoológico de bibliotecas, onde você mesmo não entende completamente como (e por que) tudo funciona. Sim, é um dependency hell e é desagradável. Mas se você tiver um bom entendimento de como tudo funciona, não haverá problemas.

Algumas Conclusões sobre Bibliotecas Singleton:

  • Escreva-as como agnósticas de framework (ou TypeScript puro, ou JavaScript puro).
  • Lembre-se que não podemos expor a implementação. Por exemplo, ao escrever widget registry, não podemos expor um método público para todos. Se você decidir atualizá-lo no futuro, a assinatura mudará, as aplicações em produção não saberão disso e tudo quebrará. A API deve ser estável: aberta para extensões, mas fechada para modificações.

Design System e Consistência de UI

Por um lado, nossas aplicações são independentes e os produtos têm a liberdade de escrever seus próprios componentes customizados. Por outro lado, precisamos criar uma experiência de usuário unificada. Estamos nos movendo em direção a um design system unificado; a própria plataforma carrega um conjunto global de variáveis CSS, e todas as aplicações as utilizam. Mas, assim como com bibliotecas singleton, é preciso lembrar da retrocompatibilidade e controlar rigorosamente quaisquer divergências. Afinal, se você começar a editar ou remover esses CSS sem critério, sempre haverá um produto em produção que os utiliza ativamente e que não ficará satisfeito com suas ações.

Algumas Recomendações:

  • Crie seu próprio serviço de distribuição de estáticos: Esta é uma boa solução por si só, e também útil para implementar um mecanismo de fallback. Por exemplo, se você carregar um micro-frontend e ele derrubar tudo, ele pode ser simplesmente isolado. Na prática, isso resolve o problema em 99% dos casos.
  • Desenvolva seus próprios serviços de monitoramento e logging: Para rastrear quais micro-frontends foram carregados, em que sequência e em quais combinações. Tudo isso ajudará a melhorar a qualidade do debug.
  • Documentação: Quanto melhor você descrever suas soluções, mais confortável será para as equipes de produto trabalhar com a arquitetura.

Complexidades:

A variedade de micro-frontends descrita no artigo aumentará a complexidade da depuração. Um desenvolvedor pode dizer: "Ótimos interfaces, excelente documentação, mas nada funciona". E você não poderá simplesmente responder: "Temos 8 produtos assim e todos funcionam, mas o seu não". Será necessário ir e analisar o código dele. E lá, por exemplo, pode não estar o seu stack. E pronto. E não é só o stack – divergências em tabulações e linters também podem causar problemas.

Bugs de Integração: O obstáculo mais sutil. As aplicações parecem independentes, vivem e evoluem, mas estamos interessados em uma classe de erros que ocorre quando conectamos tudo em uma arquitetura unificada. Chamamos esses erros de "vazamentos" – vazamento de implementação, vazamento de Angular, vazamento de bibliotecas, etc.

Custos de Carregamento: Com mãos não muito habilidosas, pode-se criar um bundle muito desajeitado e grande. Sim, carregaremos vários frameworks e várias versões do Angular, mas nosso objetivo não é manter 10 aplicações, cada uma com seu próprio Angular, mas sim não bloquear a entrega de funcionalidades aos nossos clientes. Dizemos a todos: instalem, atualizem, tragam suas funcionalidades, e o débito técnico será resolvido quando for conveniente e houver tempo.

Ferramentas Comuns: A história em que é preciso ir além do trabalho habitual, pois será necessário escrever ferramentas, сборщики (build tools) e plugins para federação de módulos, além de se comunicar com engenheiros de DevOps. Nem todos estão preparados para esse tipo de trabalho.

Conclusão

Essa abordagem arquitetônica nos proporciona lançamentos verdadeiramente independentes: equipes, produtos e a plataforma dependem minimamente uns dos outros. Existem pontos unificados com contratos compartilhados, através dos quais o sistema é escalado.

Pessoalmente, encontro um benefício na flexibilidade: não impomos nada a ninguém e, na prática, trabalhamos sob o paradigma "Faça o que quiser, escolha a ferramenta conveniente". O preço disso é a complexidade da arquitetura, manutenção e depuração, além da necessidade de se comunicar com um grande número de equipes.

Na minha opinião, toda essa complexidade é justificada, pois nos ajudou a superar todos os desafios arquitetônicos que enfrentamos. E estamos prontos para novos.

🛡️⚡

Pare de pesquisar. Comece a hackear.

O MundiX é seu copiloto de pentest com IA: comandos exatos, análise de outputs e próximo passo na kill chain — em segundos.

Testar grátis por 7 dias →

Sem cartão para começar · Planos a partir de R$49/mês

📤 Compartilhar & Baixar

🧰 Ferramentas recomendadas

Divulgação: alguns links são patrocinados. Podemos receber comissão se você comprar — sem custo extra para você. Só indicamos o que faz sentido para a comunidade.

Aprendendo Kali Linux: Teste de segurança, pentest e hacking ético

Aprendendo Kali Linux: Teste de segurança, pentest e hacking ético

Com centenas de ferramentas pré-instaladas, a distribuição Kali Linux facilita o trabalho de os profissionais de segurança começarem a fazer testes de segurança rapidamente. No entanto, com mais de 600 ferramentas em seu arsenal, o Kali Linux também pode ser desafiador. A nova edição deste prático livro abrange as atualizações nas ferramentas e inclui uma melhor abordagem da análise forense e da engenharia reversa. Ric Messier, autor, não fica apenas no teste de segurança, mas também faz uma abordagem sobre a execução de análise forense, incluindo a análise em disco e na memória, assim como alguma análise básica de malware. • Explore as diversas ferramentas disponíveis no Kali Linux • Entenda o valor do teste de segurança e examine os tipos de teste disponíveis • Aprenda os aspectos básicos do pentest em todo o ciclo de vida do ataque • Instale o Kali Linux em vários sistemas, tanto físicos quanto virtuais • Descubra como usar diferentes ferramentas destinadas à segurança • Estruture um teste de segurança baseado nas ferramentas do Kali Linux • Estenda as ferramentas do Kali para criar técnicas de ataque avançadas • Use o Kali Linux para ajudar a criar relatórios quando o teste terminar “A abordagem concisa, clara e baseada na experiência adotada por Ric Messier para a introdução do Kali Linux e dos testes de cibersegurança é incomparável. Este livro é uma leitura excelente e acessível para iniciantes e um recurso valioso para qualquer pessoa.” —Alexander Arlt, Consultor sênior de segurança, Google

Ver na Amazon
Gshield 2 em 1 Hub Extensor Conector USB-C + USB-A e Adaptador de Rede Ethernet LAN RJ45 com 3 Entradas USB 3.0 até 5 Gbps em Liga de Alumínio para Computador e Notebook, Cinza

Gshield 2 em 1 Hub Extensor Conector USB-C + USB-A e Adaptador de Rede Ethernet LAN RJ45 com 3 Entradas USB 3.0 até 5 Gbps em Liga de Alumínio para Computador e Notebook, Cinza

Compatível com portas USB-C e USB-A, ideal para ampliar a conectividade de dispositivos como MacBook Pro e outros com portas USB-C. Inclui um adaptador USB-A extra, proporcionando uma conexão Ethernet estável e veloz de até 1 Gbps, perfeita para filmes, jogos online e videoconferências. Oferece três portas USB 3.0 com velocidades de transferência de até 5 Gbps, permitindo conectar mouse, teclado, discos rígidos e outros periféricos. Fabricado em alumínio durável, garantindo longa vida útil e resistência ao uso diário. Design compacto e leve, ideal para viagens de negócios e uso diário, facilitando o transporte e armazenamento. Funciona com Windows 10/8.1/8, Mac OS e Chrome OS, oferecendo versatilidade incomparável para diversas necessidades de conectividade. Assegura uma conectividade estável e rápida, perfeita para tarefas exigentes como transferência de dados, streaming e mais.

Ver na Amazon
Hacking APIs: Breaking Web Application Programming Interfaces

Hacking APIs: Breaking Web Application Programming Interfaces

Hacking APIs is a crash course on web API security testing that will prepare you to penetration-test APIs, reap high rewards on bug bounty programs, and make your own APIs more secure. You'll learn how REST and GraphQL APIs work in the wild and set up a streamlined API testing lab with Burp Suite and Postman. Then you'll master tools useful for reconnaissance, endpoint analysis, and fuzzing, such as Kiterunner and OWASP Amass. Next, you'll learn to perform common attacks, like those targeting an API's authentication mechanisms and the injection vulnerabilities commonly found in web applications. You'll also learn techniques for bypassing protections against these attacks. In the book's nine guided labs, which target intentionally vulnerable APIs, you'll practice: Enumerating APIs users and endpoints using fuzzing techniques Using Postman to discover an excessive data exposure vulnerability Performing a JSON Web Token attack against an API authentication process Combining multiple API attack techniques to perform a NoSQL injection Attacking a GraphQL API to uncover a broken object level authorization vulnerability

Ver oferta
Gray Hat Hacking: The Ethical Hacker's Handbook, Sixth Edition

Gray Hat Hacking: The Ethical Hacker's Handbook, Sixth Edition

Up-to-date strategies for thwarting the latest, most insidious network attacks This fully updated, industry-standard security resource shows, step by step, how to fortify computer networks by learning and applying effective ethical hacking techniques. Based on curricula developed by the authors at major security conferences and colleges, the book features actionable planning and analysis methods as well as practical steps for identifying and combating both targeted and opportunistic attacks. Gray Hat Hacking: The Ethical Hacker's Handbook, Sixth Edition clearly explains the enemy's devious weapons, skills, and tactics and offers field-tested remedies, case studies, and testing labs. You will get complete coverage of Internet of Things, mobile, and Cloud security along with penetration testing, malware analysis, and reverse engineering techniques. State-of-the-art malware, ransomware, and system exploits are thoroughly explained. Fully revised content includes 7 new chapters covering the latest threats Includes proof-of-concept code stored on the GitHub repository Authors train attendees at major security conferences, including RSA, Black Hat, Defcon, and B-Sides

Ver na Amazon
Bloqueador USB de privacidade de porta USB para PC, notebook, bloco de laptop,

Bloqueador USB de privacidade de porta USB para PC, notebook, bloco de laptop,

Proteção de privacidade aprimorada: protege o link de transmissão de dados para evitar roubo de informações, fornecendo proteção de segurança robusta que protege a privacidade do usuário durante transferências de arquivos e garante uma conexão segura para interações de dispositivos sem preocupações em vários ambientes Uso a longo prazo: a camada protetora resistente ao desgaste, combinada com um corpo de metal resistente, oferece gerenciamento de calor confiável e qualidade duradoura durante o uso diário Entrega eficiente de energia: a tecnologia de chip inteligente garante a identificação automática dos requisitos de energia, fornecendo carregamento eficiente alinhando-se com vários protocolos de carregamento rápido para maior conveniência Proteção contra sobrecarga: evitando riscos de sobrecarga, este bloqueador de dados USB protege a vida útil da bateria e garante um desempenho estável, mantendo um fluxo estável de energia para melhorar a longevidade do dispositivo de forma eficaz Prático de transportar: com atenção à portabilidade, este bloqueador de dados USB oferece um design compacto que é leve e fácil de transportar, melhorando a conveniência do usuário e operação eficiente

Ver na Amazon

📩 Newsletter MundiX

Receba novidades de cibersegurança + um checklist de pentest grátis. Sem spam.

Ao assinar você concorda em receber e-mails. Cancele quando quiser.