DEV Community

Alison Rodrigues
Alison Rodrigues

Posted on

Iniciando com Micro front-end (module federation)

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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,
    },
  }),

  //...
]

Enter fullscreen mode Exit fullscreen mode

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,
        }),
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

E para utilizar basta executa-lo na sua pasta de artefatos do build, como por exemplo:

 http-server ./dist
Enter fullscreen mode Exit fullscreen mode

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",
 }
}
Enter fullscreen mode Exit fullscreen mode

webpack.config.js

  //...
  plugins: [
        new ModuleFederationPlugin({
            // ...
            remotes: {
                 "App1": "http://localhost:8080/remoteEntry.js",
            },
            // ...
        }),
  //...
  ]
Enter fullscreen mode Exit fullscreen mode

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.

Também um artigo de um case bem legal da Localiza

Top comments (17)

Collapse
 
brunonovais profile image
Bruno Rezende Novais

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 !

Collapse
 
alisonjr profile image
Alison Rodrigues

é isso mesmo!!

Collapse
 
lliw profile image
William Rodrigues

Artigo muito bom, primo!

Collapse
 
leonardorafaeldev profile image
Leonardo Rafael Dev

parabens pelo artigo!

Collapse
 
danielhe4rt profile image
Daniel Reis

Regaçou, primo!

Continue escrevendo pra gente <3

Collapse
 
artenlf profile image
Luís Felipe Arten

Muito legal! Parabéns!!

Collapse
 
ilonavarro profile image
Ilo Navarro

Usar o pnpm muda algo?

Collapse
 
renanvidal profile image
Renan Vidal Rodrigues

Ótimo, post e boa escolha de tema

Collapse
 
cherryramatis profile image
Cherry Ramatis

Otimo artigo primo!

Collapse
 
foxgeeek profile image
Foxgeeek

Post mt bom!!! Só vai!!

Collapse
 
pdrolucas profile image
Pedro Lucas

Boa primo

Collapse
 
guidev115 profile image
Guilherme Fabrício

Muito bom primo

Collapse
 
codefriendship profile image
Augusto Cesar

Artigo muito bem explicado, primo! Parabens!

Collapse
 
ivandragonv2 profile image
Ivan Dragon

Ótimo conteúdo e ótimo post!

Collapse
 
dimas7dev profile image
Dimas F.

Ótimo artigo!!

Collapse
 
brunofndes profile image
Bruno Fernandes

Mto bom, continua escrevendo primo!