Module Federation & ReactJS
Nessa artigo iremos implementar uma arquitetura de micro-frontends, utilizando um plugin fornecido pelo Webpack, o Module Federation. A ideia aqui é construir algumas aplicações que irão ser executadas de forma autônoma, porem com o objetivo de produzir algo único no final.
Para que esse artigo não fique muito longo e cansativo, é importante que você já tenha alguma familiaridade com a arquitetura de micro-frontends e também conheça, mesmo que de forma básica e conceitual, a forma como funciona o Module Federation. Conhecimentos sobre ReactJS podem ser úteis ^^.
Se ainda não tiver essas skills, não tem problema. Vou deixar uns links para consultas e qualquer duvida só deixar nos comentário.
- Arquitetura de Micro-Frontends: https://www.youtube.com/watch?v=SZseAzddtyo
- Introdução ao Module Federation: https://www.youtube.com/watch?v=D3XYAx30CNc&t=1s
- Module Federation Oficial Doc: https://webpack.js.org/concepts/module-federation/
Tecnologias utilizadas
- Module Federation
- Webpack >5
- ReactJS
- Tailwind
Entendendo o senário
Como já comentei, iremos focar mais na prática, no código para implementar a solução proposta pelo Module Federation. Pra isso precisamos primeiro ter em mente o nosso “Senário”, ou seja, precisamos entender e definir as aplicações que compõe nosso ambiente e de que forma elas irão interagir para criar algo único no final.
Vejamos como funcionará nosso exemplo:
- ComponentsLibrary — aplicação que ira exportar componentes que são comuns entre todas as aplicações. Dessa forma padronizamos algumas estilizações e funcionalidades. No nosso exemplo iremos exportar dois componentes: Footer e Header.
- ApplicationA — Nessa aplicação iremos ter uma navegação para duas telas. Teremos uma tela inicial com dois cards que irão redirecionar para as ScreenA ou ScreenB.
- ApplicatiomB — Aplicação simples que terá apenas uma tela inicial.
- Application “X” — Esse item é apenas uma referência a outras aplicações qque podem ser adicionadas no workspace.
- CommonWorkspace — É por essa aplicação que nosso Usuário ira acessar o sistema. Nela teremos uma tela inicial contendo cards que redirecionam o usuário para a ApplicationA ou ApplicationB. Dessa forma sua interação ficará centralizada em uma aplicação que referencia, por sua vez, os outros micro-frontends de nosso ambiente.
Ta certo, agora que alinhamos essa parte, bora pro código! XD
Criando as aplicações
Para nos auxiliar na criação dos projetos iremos utilizar a biblioteca create-mf-app.
Rode o comando npx create-mf-app
para cada aplicação e siga os passos do CLI. Exemplo:
Ao final você deve ter uma estrutura similar a imagem para cada aplicação e a direita o exemplo da estrutura de aplicações:
Criando components Header e Footer
Na aplicação components-library criaremos esses dois componentes e iremos exportar seus conteúdos utilizando Module Federation, e assim as aplicações do nosso workspace poderão utiliza-los.
- Para isso criaremos o componente Header.tsx e o model header-model.ts.
2. Agora vamos para o Footer.tsx.
3. Para que possamos testar nossos componentes antes de exporta-los iremos criar uma pasta chamada views e nela adicionaremos o arquivo HomeView.tsx com o seguinte conteúdo:
4. Por fim iremos chamar nosso componente HomeView no aquivo App.tsx. Ficará dessa forma:
5. Agora basta executar o script npm run start
. Se estiver tudo correto, você terá um resultado como esse:
6. Agora que já testamos e está tudo certo, precisamos exportar esses componentes (Header e Footer). No arquivo webpack.config.js, nas configurações do plugin Module Federation, exporte os dois componentes, como no exemplo abaixo.
Utilizando os componentes exportados
Agora que já criamos nossos dois componentes, vamos até a applicationA e vamos importar esses componentes.
- Para importar os componentes, vá até o arquivo webpack.config.js (applicationA) e adicione a referencia (remote) para a nossa aplicação components-library.
2. Como estamos usando TypeScript precisamos adicionar as informações referentes a importação do modulo components-library na nossa aplicação. Na pasta @types adicione o arquivo components-library.d.ts com o seguinte conteúdo:
3. Agora vamos criar uma pasta components e adicionar o arquivo ScreensCasds.tsx. Nesse componente teremos os cards que irão direcionar o usuários para a tela de sua escolha.
4. Vamos criar uma pasta views e adicionar os arquivos HomeView.tsx, ScreenA.tsx e ScreenB.tsx.
5. Por fim, ajuste o arquivo App.tsx.
6. Basta executar npm run start
e você terá uma tela essa:
💡 Importante! Lembre-se que agora na applicationA estamos referenciando o common-workspace, então ambos precisam estar executando para que nosso exemplo funcione corretamente. :)
7. Na applicationB será muito similar. Vá até o projeto e adicione o código abaixo.
8. Basta rodar npm run start
e terá a seguinte tela:
Exportando e utilizando applicationA e applicationB
Com nossas três aplicações já preparadas e funcionando de forma isolada (applicationA, applicationB e components-library), queremos centralizar sua execução e interação em apenas uma aplicação.
1. Da mesma forma como exportamos componentes no common-workspace, iremos agora exportar as aplicações A e B. Veja como irá ficar o arquivo webpack.config.js:
Adicione também na applicationB o item expose: {"./AppB": "./src/App.tsx}
para expoortar o seu conteúdo.
2. Agora iremos fazer algumas alterações no common-workspace. Primeiro vamos adicionar a importação das aplicações A e B no arquivo webpack.config.js, como o exemplo abaixo. Veja que também estamos importando o components-library, pois usaremos o Header e o Footer.
3. Ainda no common-workspace, vamos criar o componente ApplicationsCards.tsx com o seguinte conteúdo:
4. Agora na pasta views, crie o componente HomeViews.tsx com o seguinte conteúdo:
5. Por fim ajuste o arquivo App.tsx.
Pronto! Temos nossas 4 aplicações criadas e configuradas. Agora basta executar npm run start
no projeto common-workspace e ver nossas aplicações independentes coexistindo em um mesmo workspace.
Ufa, chegamos ao fim. :P Com certeza há muitos detalhes e muitos conceitos importantes que não nos aprofundamos aqui. Porém agora com esse senário que criamos você poderá praticar e entender passo a passo o que esta acontecendo nessas aplicações. Então explore o arquivo webpack.config.ts e perceba a forma como exportamos nossos componentes através do exposes e como importamos as aplicações através do remote, crie novos componentes com inputs, eventos e … bons estudos! 😃
Alguns desafios para você:
- [ ] entender como estamos trocando informações entre os componentes e aplicações (props, event binding, etc)
- [ ] adicionar uma nova aplicação
- [ ] adicionar um novo componente no components-library e utiliza-lo em outra aplicação
- [ ] subir arquitetura do workspace no vercel
Projetos completos:
- https://github.com/dev-mauricioAB/components-library
- https://github.com/dev-mauricioAB/applicationA
- https://github.com/dev-mauricioAB/applicationB
- https://github.com/dev-mauricioAB/common-workspace
Links úteis: