Web Components - Distribuindo funcionalidade com Micro-Frontends
Há pouco tempo atrás, postei aqui no Tabnews sobre uma forma (não convencional) de compartilhar funcionalidade a partir de Web Components. A problemática era não só a distribuição, mas como reutilizar lógica sem necessáriamente reutilizar o html.
Ao reutilizar o html você precisa assumir que seu componente será um pouco mais complexo, já que além da lógica inerente contido nele, haverá uma lógica adicional para torná-lo minimamente dinâmico no que diz respeito à UI.
Naquele post, quis mostrar uma forma de desacoplar o html do js para que você possibilite compartilhar comportamentos complexos injetando dependências diminuindo drásticamente o bundle do seu Web Component e tornando-o mais flexível.
O Caso de Microfrontends
O caso dos microfrontends é um caso particular de distribuição de funcionalidade. Não é de escopo desse post explicar a motivação e o que é Microfrontends, deixo para um artigo que faz isso melhor que eu faria.
Meu objetivo é mostrar formas diferentes das conhecidas. Hoje, é possível fazer isso utilizando algum framework que automatize o processo, ou mesmo, utilizando a feature de module federation que alguns bundlers como o Webpack disponibilizam.
Diferentemente da necessidade do post anterior, onde a idéia era compartilhar comportamento mais genérico, no caso de Microfrontends a necessidade vai além, incluindo regras de negócio, chamadas de api's e integrações mais complexas, onde o objetivo não é a flexibilidade mas o reuso de uma experiência.
Nesse caso, carregar esta experiência em Runtime tem um grande benefício. Sua aplicação não precisa ser buildada toda vez que esta experiência atualiza. Isso favorece a reutilização e a rápida atualização, muito útil em momentos onde precisa evoluir e possui N aplicações utilizando sua experiência.
A estrutura
No post passado eu usei o meu repositório de mfes, onde eu utilizo o Parceljs como bundler para criar várias pastas de mfe's e gerar estáticos a partir dos seus arquivos.
A estrutura para o exmplo do swiper era essa:
mfes/
├── mfe-a
├── mfe-b
└── mfe-swiper/
├── app.ts
├── index.ts
├── index.css
├── index.pug
└── page.pug
O parcel dá o output nestes arquivos:
https://mfe-jails.netlify.app/mfe-swiper/index.js
https://mfe-jails.netlify.app/mfe-swiper/index.css
https://mfe-jails.netlify.app/mfe-swiper/index.html
https://mfe-jails.netlify.app/mfe-swiper/page.html
No post passado eu dei ênfase apenas nos arquivos index.js
e o index.css
para reutilização de código no contexto de Web Components, eu reaproveitei esse repositório para o exemplo do post sobre Web Component.
Agora o meu foco é o link gerado que contém toda a funcionalidade standalone deste Web Component, ou seja, funcionando numa estrutura de página html convencional. Portanto se navegar neste último link, verá o funcionamento do Web Component em sua totalidade.
O Problema
Eu não costumo utilizar frameworks nos meus projetos pessoais. Acho inclusive super complexo a maneira como se contrói micro-frontends utilizando os frameworks e além disso, são casos muito específicos onde utilizo.
Uma das minhas maiores queixas com relação ao mundo front-end hoje é com relação ao over-engineering, muita complexidade desnecessária.
Reclamar é fácil, mas qual a sugestão?
O jeito mais simples de se reutilizar funcionalidades é o uso de <iframe />
. O iframe não é em si uma solução ruim, ele apenas possui algumas limitações. Uma delas é a limitação de altura automática. As maneiras de se contornar isso via iframe são desastrosas.
O browser funciona da mesma maneira para qualquer tipo de aplicação web. Ele depende de um html, scripts carregados / executados, e css. Essa tríade, simples, é o que compõe a aplicação Web, não importa o quão complexo o framework é. Tem assets inclusos nessa dinâmica também como: Fontes, Imagens, Svg's, mas no final, são arquivos externos carregados utilizando elementos html no DOM.
Com isso, tenho utilizado uma técnica mais simples. Eu carrego a página contendo minha aplicação externa via javascript, que contém todo o html e as tags que apontam para os assets dependentes, e monto na minha aplicação atual.
Eu queria algo como o iframe, onde eu apontasse um endereço html e ele embedasse na minha aplicação.
A Solução
Construí essa interface agnóstica que faz algo parecido com o Iframe. Ele faz o fetch de uma página e internamente algumas mágicas para resgatar o script, css e adicionar na minha página atual.
O código fica mais ou menos assim:
import { mfe } from 'jails.std/mfe'
const helloworld = document.querySelector('#hello-world')
const microfrontend = mfe()
microfrontend.render(
helloworld,
'https://mfe-jails.netlify.app/mfe-hello-world/page.html'
)
É possível ver o uso e funcionamento aqui: https://stackblitz.com/edit/jails-mfe-xkf9e5at?file=index.ts
Conclusão
Tem funcionado muito bem para mim especialmente se não utilizo nenhum framework que acaba fazendo mágica demais na aplicação, ou de alguma forma sequestra a DOM tree.
Essa interface está nesse repo: https://github.com/jails-org/Std
Que é um repo de funcionalidades mais vanilla, bibliotecas padrão que utilizo nos meus projetos.
Conforme vai pesquisando, vai aprendendo que não foi a única pessoa que usa certas técnicas. O Turbolinks da galera do Rails utilizava há um tempo atrás, mas para a aplicação inteira, para construir páginas no modelo multi-pages, mas com sensação de Single Page Apps.
No meu caso, acabei utilizando uma idéia similiar em escopo menor.
Importante: É preciso habilitar o CORS para os endereços que você deseja compartilhar. Por questões de segurança, via javascript, você não consegue carregar conteúdos html de domínios diferentes.
É isso, no futuro posso trazer casos um pouco mais complexos que este se for de interesse para alguém como este abaixo:
Até o próximo!
Obrigado