Iniciando com Micro front-end (module federation)

alisonjr

Alison Rodrigues

Posted on March 23, 2023

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

💖 💪 🙅 🚩
alisonjr
Alison Rodrigues

Posted on March 23, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Angular + Webpack: An Overview
angular Angular + Webpack: An Overview

September 22, 2023