PARTE 1 - Meta-Repos e Micro-frontends uma arquitetura alternativa a Mono-repos e multi-repos
Hoje em dia as pessoas parecem amar complicar a vida.
Hoje em dia não se desenvolve software profissional sem utilizar algum framework de front end como React, Angular ou View.
Outro dia, afim de me livrar dessas complicações andei brincando com o javascript e desenvoli pelo menos três bibliotecas reativas minimalista.
Uma delas vale a pena destacar antes de entrar no assunto de Meta-repo.
- Conheça a simplicidade - Terezzu JS
Terezzu JS é uma biblioteca para construção de aplicações SPA com suporte para desenvolvimento de MFE (Micro Front End).
Desenvolvi com Terezzu uma POC (Prova de conceito) onde demonstro a criação de um sistema baseado na arquitetura Micro Front End.
Aprenda mais sobre MFE clique aqui.
Porque fiz toda essa introdução?
Bem, a resposta é curta e simples:
Para demonstrar como podemos simplificar a estrutura de desenvolvimento de projetos baseados em MFE.
Mono-Repo
Mono-repos à primeira vista parecem lindos, ainda mais se você incluir Lerna ou NX para gerenciar o repositório. Porém, a medida que o sistema cresce a complexidade de gerenciar os repositórios também cresce apesar da propaganda dessas ferramentas tentar mostrar o contrário disso.
Multi-repos
Os multi-repos são o padrão tradicional de desenvolvimento de software.
Com multi-repo, cada repositório tem uma base exclusiva de código sendo versionada.
O problema dos multi-repos começa a ficar evidente quando você precisa atuar em vários repositórios ao mesmo tempo para desenvolver uma feature. Nesses casos você precisa clonar 3 ou quatro repositórios e abrir cada um em uma instância do terminal e editor de código.
Para cada mudança nas diversas bases de código um novo commit é necessário. Muito trabalho né!?
Meta-repo
Com meta-repos temos uma mistura de Mono e Multi repositórios. Isso significa obter os benefícios oferecidos pelas duas arquiteturas.
Os meta-repos oferecem uma forma fácil de gerenciar o histórico do git com ferramentas/plugins simples.
A partir de agora vou demonstrar como criar uma estrutura de meta-repo.
O primeiro passo é criar no github, bitbucket, gitlab ou azure 3 repositórios.
Para o primeiro repositório darei o nome de meta-repo-root, afim de destacar que esse repositório pode conter outros.
O segundo repo será nomeado como meta-repo-main, afim de demonstrar que é a base da aplicação e que pode carregar outras partes através de lazyloading por exemplo.
Por fim, o terceiro repositório será identificado como meta-repo-message e nesse repositório desenvolveremos uma app simples que exibe uma mensagem.
Desenvolveremos esse sistema utilizando a arquitetura de meta-repo para gerenciamento do histórico de versionamento do git e aplicaremos MFE (Micro Front End) como arquitetura do software.
Como prefiro simplificar ao complicar, utilizarei Terezzu JS para desenvolver as aplicações, mas, você pode optar por utilizar qualquer estrutura de desenvolvimento javascript.
Você pode usar Angular, React, Vue, Svelte, Remix, Astro, ou qualquer outra. Não faz diferença.
Os repositórios criados ficaram assim:
1 - meta-repo-root
2 - meta-repo-main
3 - meta-repo-message
Em todos os repos as opções facultativas ficaram assim:
Após criar os repositórios precisamos clonar cada um deles, mas, para facilitar a vida, mais uma vez farei um caminho diferente.
Primeiro, vou criar pastas via terminal com o mesmo nome dos repositórios criados a pouco.
Observe que meta-repo-main e meta-repo-message foram criados dentro de meta-repo-root.
Agora criaremos dentro de meta-repo-main e meta-repo-message os arquivos de cada um dos sistemas MFE.
Utilizeremos um template para construir os projetos e faremos uso da ferramenta degit para clonar o template sem vinculação com o repositório original do template.
Também podemos relacionar os repositórios locais e remotos através dos comandos abaixo:
Agora que o template foi devidamente clonado para cada repositório, seguiremos criando a estrutura de componentes de cada aplicação.
Começando por meta-repo-message, onde serão necessários dois componentes para criar a aplicação.
Dentro da pasta src/components trocamos o nome do componente app-hello para app-message conforme na imagem a seguir:
Agora já podemos abrir o projeto meta-repo-message no VSCode para seguir desenvolvendo a aplicação.
Abra o arquivo view.js do componente appMessage localizado em src/components/appMessage e modifique-o para que esteja como na imagem acima.
Também será necessário alterar o nome do componente no arquivo index.js garantindo a exportação correta do módulo.
Não abordarei os conceitos de Terezzu, mas, se você quiser aprender sobre Terezzu para adotá-lo e simplificar o ecossistema de seus projetos, apenas clique aqui.
Por fim, vamos definir no componente appMessage a mensagem que deve ser exibida ao carregar a aplicação. Faça como na imagem a seguir:
Perceba que no arquivo model.js a mensagem a ser exibida na view foi alterada. Você deve seguir aplicando essa alteração também.
Com essas modificações realizadas seguiremos para o componente appMain onde faremos um pequeno refactory.
Agora você deve alterar o componente appMain para incluir a tag HTML que hospedará o componente appMessage que alteramos a poucos instantes. Faça como na imagem acima.
Também é necessário exportar o componente corretamente. Siga o que é apresentado na imagem abaixo para completar as alterações necessárias no componente appMain.
Chegou a hora de instalar as dependências do projeto e inicializar a aplicação.
Antes de tudo, atualize a dependência terezzu presente no arquivo package.json para a versão 0.1.8.
Após aplicar a alteração o arquivo package.json ficará assim:
Volte ao terminal e faça como na image abaixo para instalar todas as dependências necessárias para inicializar a aplicação:
Se tudo correu bem, as dependências do projeto foram instaladas na pasta node_modules e algo como na imagem a seguir deve estar sendo exibido através do seu terminal.
Agora basta executar no terminal o comando logo abaixo e a aplicação será inicializada e a mensgem definida no componente appMessage será exibida através do navegador.
pnpm start
Após executar o comando acesse http://localhost:8080 em um navegador.
Apesar da imagem abaixo demonstar o carregamento correto da aplicação no navegador, deve ficar claro, que para a arquitetura MFE ser aplicada, a aplicação precisa disponibilizar no app principal e em seus componentes os métodos mount, unmount e setup.
Utilizar os métodos mount, unmount e setup é uma boa prática do micro-frontend que facilita a implantação dessa arquitetura.
Novamente, não abordarei a fundo a arquitetura MFE, mas, você pode aprender mais sobre ela se desejar. Apenas clique aqui para aprender mais.
Para realizar o ajuste necessário e prover os métodos relatados acima, será necessário atualizar os arquivo index.html e main.js.
Com a alteração abaixo, estamos criando uma aplicação em que todos os seus componentes possuem os métodos necessários para aplicar a arquitetura MFE.
Através do módulo createApp importado no arquivo main.js estamos construindo um módulo MFE que é composto pelos métodos mount e unmount entre outros.
Agora seguiremos para o arquivo index.html em que instanciaremos o módulo principal da aplicação e o inicializaremos.
Com essas alterações devemos obter um resultado semelhante ao que é apresentado na imagem que segue logo abaixo:
Na aplicação meta-repo-message cobrimos todos os requisitos para uma aplicação MFE.
Agora precisamos aplicar os mesmos recursos na amplicação meta-repo-main que deve consumir a aplicação meta-repo-message como um serviço.
Para o processo não ficar tedioso, vou apenas expor abaixo em ordem as modificações necessários em meta-repo-main. Portato, siga as imagens para fazer as alterações corretamente.
1 - Acesse no terminal o diretorio meta-repo-main, abra o repo no VSCode e modifique o arquivo package.json
package.json
2 - Instale as dependências do projeto.
Execute o comando abaixo no terminal para instalar as dependências.
pnpm i
Se tudo correu bem, algo como a imagem abaixo deve ter sido apresentado no terminal.
3 - Remova o componente appHello em src/components e elimine sua importação em src/main.js
- Removendo appHello
- Eliminando a importação de appHello em src/main.js
4 - Configure um sistema de rotas com carregamento assíncrono.
- Agora prepararemos meta-repo-main para consumir meta-repo-message como um serviço.
Ainda precisamos configurar adequadamente as rotas.
Na imagem que segue as rotas foram corrigidas, porém, o componente appNotFound não existe e precisa ser criado.
Para criar o componente appNotFound vamos apenas duplicar o diretório appMain e renomear o componente.
Agora vamos observar alguns detalhes interessates nesse sistema de rotas.
Nesse sistema de rotas, o componente appNotFound é importado como um módulo. No entanto, precisa ficar claro, que esse componente faz parte da aplicação meta-repo-main, portanto, é um modulo local. Por esse motivo, não precisa necessáriamente ser carregado com lazyloading.
Veja como fica a importação do componente local:
Na próxima rota o componente appRoot é importado e renomeado para component. Esse módulo representa a micro aplicação meta-repo-message que é um micro serviço disponibilizado em ambiente de desenvolvimento no endereço http://localhost:8081.
Precisamos modificar um pouco mais o arquivo main.js para iniciar a aplicação.
Note que agora além de imporatar as rotas, carregamos o router module e o iniciamos. Isso, faz com que a aplicação meta-repo-main tente carregar todos os componentes fornecidos para o sistema de rotas e tente montá-los no aquivo index.html como está demonstrado abaixo:
Vamos iniciar a aplicação meta-repo-main via terminal para ver os resultados das implementações.
Veja que houve um erro ao tentar carregar o micro-serviço em localhost:8081. Esse erro já era esperado.
O serviço em localhost:8081 está desligado. Precisamos levantar o serviço na porta 8081. Por isso, acesse uma nova instancia do terminal meta-repo-message e faça as devidas configurações abrindo o projeto no VSCode.
Primeiro vamos configurar a porta e o host do serviço MFE.
Note na imagem acima que no arquivo esbuild.config.js as configurações de porta 8081 e o host localhost foram definidos. Então resta apenas iniciar a aplicação e testar novamente para garantir que o erro foi de fato corrigido.
Volte ao terminal e execute o comando abaixo:
pnpm start
O primeiro erro foi eliminado, mas, agora um novo erro assumiu o lugar. Um erro requisiçãao de origin cruzada está acontecendo.
Para resolver esse erro, basta realizar a configuração a seguir no arquivo esbuild.config.json
Os trechos de código inseridos seguem abaixo:
const liveServerCors = (req, res, next) => {
res.setHeader('Access-control-allow-origin', '*')
next()
}
liveServer.start({
// Opens the local server on start.
open: false,
// Uses `PORT=...` or 8080 as a fallback.
port: 8080,
//Host
host: 'localhost',
// Uses `public` as the local server folder.
root: 'dist',
middleware: [liveServerCors]
})
Será necessário reiniciar as aplicações meta-repo-main e meta-repo-message já que modificamos as configurações de build das aplicações.
Após reiniciar cada aplicação, você vai se deparar com o erro abaixo:
Esse erro também é comum, mas, basta inserir o element host do componente de rotas na view do componente appMain do repositório meta-repo-main para solucionar o problema.
E assim solucionamos todos os problemas que normalmente surgem na configuração inicial dessa arquitetura MFE simplificada.
Nesse momento, temos apenas duas aplicações MFE funcionando como micro-serviços e estou com duas instâncias do VSCode abertas para tratar cada uma das aplicações. Se fossem dez aplicações,como ficaria complexo gerenciar tudo isso!
Meta-Repo em ação
Vamos finalmente configurar o meta-repo para reduzir a complexidade do projeto.
O primeiro passo é entender o que é de fato um meta repo.
Saiba que um meta repo é apenas uma arquitetura de versionamento de projetos que disponibiliza um forma de centralizar atualizações de diversos repositórios através de um único comando e evita o exagero da troca de contexto.
Através de plugins meta é possível simplificar drasticamente o gerenciamento de verionamento de repositórios.
O versionamento dos repositórios permanece independente, mas, pode ser centralizado evitando diversas complexidades encontradas em mono-repos e multi-repos.
Instale a ferramenta meta para auxiliar no versionamento.
pnpm add -g meta
Combinando pnpm-workspaces com meta-repos.
Fazer essa combinação extende ainda mais o poder dos meta-repos. Pois, permite que um projeto seja compartilhado com outro no mesmo workspace.
Crie os arquivos pnpm-workspace.yaml e package.json na raiz do repositório meta-repo-root.
Agora basta abrir o diretório no VSCode para seguirmos com as configurações.
Observe que em uma única instância do terminal já temos acesso a todos os repositórios do meta-repo. O mesmo vai acontecer ao abrir o diretório no VSCode.
Já resolvemos a complexidade de troca contexto em instâncias do terminal e do VSCode.
Perceba que outra ganho importante foi deixar mais memória livre no ambiente de desenvolvimento já que apenas uma instância do VSCode será consumida para desenvolvimento.
Pare as instâncias dos serviços MFE para fazer algumas mudanças estruturais no diretório meta-repo-root.
Acesse via terminal cada repositório e pressione CTRL + C para derrubar os micro-serviços.
Em seguida aproveite e remova a pasta node_modules de cada repositóro com o comando abaixo.
rm -rf node_modules
Crie a pasta apps e a pasta packages dentro do diretório meta-repo-root. Crie também nesse repositório os arquivos .gitignore e .meta.
Agora mova para a pasta apps os repositórios meta-repo-main e meta-repo-message.
Para maior comodidade use o comando abaixo e mova os repositórios:
mv meta-repo-main meta-repo-message /apps
Após as alterações a árvore de diretórios deve ficar assim:
Aqui no TabNews os posts tem um limite total de 2 Mil Caracteres, por isso, continuo o artigo na parte 2.