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
Top comments (17)
Module federation é uma ótima estratégia em casos em que temos uma plataforma maior e queremos colocar esses pequenos módulos para integrar partes distintas, achei bem didática a forma que vc passou o conceito. Parabéns !
é isso mesmo!!
Artigo muito bom, primo!
parabens pelo artigo!
Regaçou, primo!
Continue escrevendo pra gente <3
Muito legal! Parabéns!!
Usar o pnpm muda algo?
Ótimo, post e boa escolha de tema
Otimo artigo primo!
Post mt bom!!! Só vai!!
Boa primo