Module Federation e as principais propriedades do Share
Tags: javascript, programming, microfrontends, webpack
Published: 2022-04-14 16:40:01

O [Module Federation](https://webpack.js.org/plugins/module-federation-plugin) é um plugin do webpack que permite trabalhar com microfrontends removendo uma carga de complexidade e com algum ganho de performance que iremos descrever nesse breve artigo. 

> Disclaimer: 

- Esse artigo não é um tutorial! é apenas um artigo de referência para descrever as opções da propriedade Share do plugin
- Teremos o termo shell mais usado pela comunidade como a definição de um container que abriga ali vários microfrontends, e microfrontend chamaremos de MF ou MFs(plural) até o final do artigo.

Existem hoje algumas possibilidades de se trabalhar com MFs, algumas delas usando outros frameworks como single-spa, estratégias com monorepo como NX ou Angular Worskpace e até mesmo alguma proposta de compiler que tenta resolver o problema de duplicação de código que as abordagens citadas anteriormente não se propõem a fazer “meados de maio de 2022".

## Mas o que seria a duplicação de código?

Tenha o seguinte cenário em mente, temos uma aplicação chamada de shell com a versão 17 do react e um MF utilizando a mesma versão, quando geramos o bundle final que vai para a produção temos a duplicação do core da biblioteca, pois mesmo que essas aplicações estejam utilizando a mesma versão da biblioteca ela não é compartilhada entre as mesmas, e esse cenário pode ser o mesmo utilizando frameworks como angular, então imagina uma aplicação com vários MFs, considere o tamanho do bundle que será consumido pelo client/browser, e existem algumas abordagens para resolver esse problema no processo de build, mas requer alguma complexidade.

## E o que muda com o Module Federation

É exatamente nesse ponto que o module federation entra, ele não vem apenas para ser mais uma solução de MFs e sim para resolver o problema de duplicação de código.

Voltando para o mesmo cenário citado, as duas aplicações com a mesma dependência do React na versão 17, que agora utilizando module federation conseguirmos através da propriedade share criar estratégias que forneçam a possibilidade de ter o core da biblioteca compartilhado entre o Shell e os MFs gerando um ganho de performance considerável já que o cliente/browser vai consumir apenas o bundle necessário para a execução da aplicação.

### Agora vamos entender as Opções do plugin

**name: string** é o nome que definimos para o nosso MF, e é uma boa prática que ela seja a mesma que o nome da aplicação.

**filename: string** é o nome dado ao entrypoint que o webpack vai gerar para que possa ser consumido pela aplicação shell ex:  “meuModuleRemoteEntry.js". 

**library: object** é um objeto com opções que ajudam descrever como um código/chunck gerado que foi exposto será armazenado e recuperado, essa propriedade tem seu próprio leque de configurações, como a proposta desse artigo é falar um pouco mais sobre a propriedade share vou deixar o [link para documentação](https://webpack.js.org/configuration/output/#outputlibrary).

Mas no geral você pode configurar como consumir esse MF que vai expor, como uma variável ou módulo etc...

**share: object** -> É onde declaramos todas as bibliotecas que podem ser compartilhadas entre os MFs, quando o shell compartilha uma determinada lib com os MFs e os MFs tem a mesma lib compatível com o shell os MFs consomem a lib compartilhada pelo shell do contrário acabam utilizando a sua própria versão lib na aplicação, sendo assim teremos duas libs iguais mais que podem estar versões diferentes.

#### Entendo isso temos 3 formas de declarar as bibliotecas compartilhadas.

 1. **Array:**   

```javascript
shared: ['react']
```
 2. **objeto**

```javascript
shared: {
        // Será utilizado a maior versão do React
        // que pode se >= 17.0 and < 18
          react: '^17.0.2',
        },
```
 3. **Objeto da biblioteca com algumas opções de compartilhamento:**

```javascript
shared: {
         // adiciona o react como módulo compartilhado
         // e configura mais algumas opções
         react: {
           requiredVersion: '^17.0.2',
           singleton: true,
          },
        },
```
#### E essas opções de compartilhamento podem ser:
**eager: boolean** -> essa opção vai permitir fornecer um um módulo inicial no chunck da aplicação sendo ele o módulo principal ou um fallback, o módulo vai ser compilado junto com seu MF em vez de ser solicitado de forma assíncrona.

**import: false | string** -> fornece o módulo que deve ser adicionado ao Shared Scope, se o módulo compartilhado no Shared Scope não for encontrado ele vai usar o módulo fornecido no import como fallback

**shareKey: string** -> O módulo compartilhado é pesquisado através dessa chave do escopo compartilhado.

**shareScope: string** -> O nome do escopo compartilhado.
**Exemplo da utilização do import, shareKey e shareScope**

```javascript
shared: {
        'my-extension-lib': {
          import: 'lib', // O pacote "lib" será usado como pacote fornecido e um substituto
          shareKey: 'shared-lib', // Nome dado ao módulo que será colocado no Share Scope
          shareScope: 'default', // Nome dado ao Share Scope
          version: '1.2.3', // A versão da lib
          requiredVersion: '^1.0.0', // A versão minima solicitada pela lib
        },
      },
```
**packageName: string** -> Necessário APENAS para quando precisamos determinar uma versão de biblioteca que não pode ser determinada automaticamente.

**requiredVersion: string** -> Usado para declarar a versão especifica de uma biblioteca.

**singleton: boolean** ->Essa opção permite ter uma única versão do módulo que foi compartilhado no escopo de compartilhamento o que seria o shell.

Usar mais do que uma versão de biblioteca não é uma escolha muito interessante, pois quando falamos de bibliotecas que mantém o estado, você utilizar mais de uma versão fornece automaticamente a duplicidade de um Estado Principal para a aplicação. 

Por esse motivo o Module Federation permite definir bibliotecas como singletons, se temos versões da biblioteca compatíveis considerando a Minor version o Module Federation vai decidir pela versão mais recente pela lib.

É possível usar versões diferentes de uma lib usando um range no requiredVersion, mesmo optando pelo `singleton: true` e `strictVersion true`.

**strictVersion: boolean** -> Essa opção deve rejeitar o módulo compartilhado e emitir um erro se a versão não é válida, por default ela é true quando um módulo de fallback está disponível e não estamos utilizando a opção singleton, a outra opção é false mas ele não tem efeito se houver declarado a versão obrigatória da biblioteca.

**version: false | string** -> A versão do módulo fornecido, permite que o webpack substitua uma versão correspondente Minor version, mas não a Major version.

Em resumo falando sobre Share e o compartilhamento de libs, o Shell sempre vai assumir a responsabilidade de manter a versão mais atual da biblioteca compartilhada com os MFs, mas quando o carregamento dos MFs não for feito de forma estática em suma quando for feito de forma dinâmica, e o Shell tenha uma versão menor do que o MF cada um vai ficar responsável por subir sua própria versão da biblioteca.

Ainda podemos através do compartilhamento dos MFs de forma dinâmica carregar dinamicamente apenas o ponto de entrada remoto no início do programa e carregar o micro frontend posteriormente sob demanda. Ao dividir isso em dois processos de carregamento, o comportamento é exatamente o mesmo do compartilhamento de forma estática ("clássica"). A razão é que neste caso os metadados da entrada remota estão disponíveis com antecedência suficiente para serem considerados durante a negociação das versões.

Caso eles sejam estáticos essas libs vão ser conhecidas no tempo de build tanto do shell quanto do microfrontend e com isso será carregado a versão mais atual da lib em questão.

Bom é isso, Module Federation trás um cenário bem interessante e com muitas possibilidades para se trabalhar com Microfrontends.

Referências:
[Documentação Webpack](https://webpack.js.org/plugins/module-federation-plugin)
[Angular Architects](https://www.angulararchitects.io/aktuelles/the-microfrontend-revolution-module-federation-in-webpack-5/)