Iniciando com Micro front-end (module federation)
Alison Rodrigues
Posted on March 23, 2023
Hoje em dia existem várias formas de se construir aplicações front end distribuídas. Também existem inúmeros frameworks para facilitar a vida de quem está construindo um ambiente de componentes distribuídos e diferentes formas de gerenciar dependências e orquestrar os componentes visíveis no browser.
Neste artigo vou utilizar o "module federation", um modelo arquitetural proposto por Zack Jackson e outros Core Developers do Webpack. Como o module federation é uma especificação, existem implementações em diferentes Module bundlers como o Rollup. Porém a que está com a api mais avançada é mesmo o Webpack. Então os exemplos desse artigo são escritos utilizando do plugin ModuleFederation do Webpack.
A forma mais fácil de iniciar um projeto com suporte ao module federation é através da cli create-mf-app
desenvolvida pelo Jack Herrington (o canal do youtube dele tem bastante coisa sobre micro front-end lá, vale a pena dar uma olhada https://www.youtube.com/c/jackherrington ).
Para utilizar a cli basta executar o comando
npx create-mf-app
Siga as instruções da cli. Ela vai te perguntar algumas informações como nome da app, framework, porta para localhost e etc.
? Pick the name of your app: host
? Project Type: Application
? Port number: 8080
? Framework: vanilla
? Language: javascript
? CSS: CSS
Your 'host' project is ready to go.
Next steps:
▶️ cd host
▶️ npm install
▶️ npm start
Após executar esses passos podemos avaliar alguns arquivos importantes.
Veja o arquivo webpack.config.js
é nele que vai estar as configurações do nosso micro front-end. Vá a propriedade de plugins desse arquivo. Lá você deve ver a configuração de um plugin chamado ModuleFederationPlugin
e ele deve ser parecido com isso:
//...
plugins: [
//...
new ModuleFederationPlugin({
name: "host",
filename: "remoteEntry.js",
remotes: {},
exposes: {},
shared: {
...require("./package.json").dependencies,
},
}),
//...
]
Nesse plugin é onde vamos fazer toda a configuração e federação dos nossos módulos remotos (micro front-ends).
Dentro da literatura do Module Federation eles chamam os micro front-ends de Remote modules (Módulos remotos). E a partir daqui, eu também vou utilizar essa nomenclatura de módulo ou módulo remoto.
Uma grande vantagem da estratégia do Module Federation é que os módulos remotos são verdadeiramente módulos nativos do javascript. Módulos que você utiliza normalmente com import pack from package
ou com require('package')
. Diferente de outras estratégias de micro front-end como o Single-SPA que utilizam um pacote como dependência para garantir a integração entre os componentes, o Module Federation utiliza apenas javascript para isso. E isso nos leva ao arquivo package.json
.
Se você selecionou como um projeto vanilla, verá que não há nenhuma dependência externa. Apenas o Babel
que irá transpilar o código para garantir compatibilidade com todos os browsers. Se você selecionou algum framework como React ou Vue, vai ver que eles são a única dependência do seu projeto. E isso é sensacional! 🤩🤩🤩
Configurando o projeto para que seu componente possa ser utilizado em outro projeto
Como comentado anteriormente é no arquivo webpack.config.js
que vamos fazer toda a configuração.
Entendendo as propriedades principais do ModuleFederationPlugin
- Propriedade name: É o nome do seu módulo. É também como ele será chamado em outros projetos como em
import x from name
- Propriedade filename: É o nome do arquivo que será gerado no build onde irá conter o "contrato" do seu componente.
- Propriedade shared: É aqui que você pode declarar quais pacotes você tem como dependência e que podem ser compartilhados. Por exemplo, se você tem dois componentes remotos em tela e os dois utilizam React, não é necessário importar o React duas vezes, essa é uma dependência que pode ser compartilhada entre todos os componentes em tela.
- Propriedade exposes: É aqui que declaramos quais partes do nosso projeto queremos expor como um micro front-end. Podemos expor um único arquivo ou vários. E a declaração é algo muito simples. A chave é o nome do módulo e o valor é o caminho do arquivo.
....
plugins: [
new VueLoaderPlugin(),
new ModuleFederationPlugin({
name: "YourPackageName",
filename: "remoteEntry.js",
remotes: {},
exposes: {
"yourModuleName": "./src/yourModule/index.js",
},
shared: require("./package.json").dependencies,
}),
Apenas com essas configurações quando dermos o build na aplicação será criado o arquivo remoteEntry.js
que contém todo o manifesto do seu módulo, quais dependências ele tem, quais funções, outros arquivos e etc.
Agora que tudo está confgurado pode dar um build no projeto e exponha a pasta dos artefatos do build (geralemtne é a pasta 'dist') em um servidor http. Caso você não tenha nenhum servidor rodando, você pode inicar um com o pacote http-server disponível no npm (https://www.npmjs.com/package/http-server).
Conforme a documentação do pacote, você pode instalar ele globalmente com
npm install --global http-server
E para utilizar basta executa-lo na sua pasta de artefatos do build, como por exemplo:
http-server ./dist
Pronto! seu arquivo de manifesto do seu modulo remoto está acessível via http. 🥳🎉🎉
Utilizando seu módulo em outro projeto
Em outro terminal crie um novo projeto utilizando o 'create-mf-app' igual para o primeiro.
Após seu projeto criado, você pode importar o módulo exportado do primeiro projeto como se fosse um pacote do npm. O seu projeto número dois terá como depência remota o projeto número um.
E para isso você precisa referenciar o projeto número um na propriedade "remotes" da configuração do plugin do webpack, conforme já descrito anteriormente.
a declaração da dependência remota é um pouquinho diferente da declaração de um pacote npm. Veja as diferenças:
package.json
{
//...
"dependencies": {
"axios": "^0.27.2",
}
}
webpack.config.js
//...
plugins: [
new ModuleFederationPlugin({
// ...
remotes: {
"App1": "http://localhost:8080/remoteEntry.js",
},
// ...
}),
//...
]
Para declarar nosso módulo remoto nós damos um nome a ele e referenciamos o seu endereço da internet. Se você está executando o projeto um em localhost com o http-server a porta deve ser a que o http-server está rodando. nesse caso do exemplo é a 8080.
É só isso gente! Basta uma configuração muito simples no plugin para que um projeto referencie o outro e eles possam compartilhar funcionalidades!✨🌟🤩✨🌟🤩
Para mais informações sobre o Module Federation, exemplos de aplicações, documentação e etc. Vou deixar alguns links.
- https://webpack.js.org/concepts/module-federation/
- https://github.com/module-federation
- https://github.com/module-federation/module-federation-examples
Também um artigo de um case bem legal da Localiza
Posted on March 23, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.