DEV Community

Wanderson Alves Rodrigues
Wanderson Alves Rodrigues

Posted on • Edited on

6

Micro front-end module federation: Aplicação extensível

A arquitetura de micro front-end é uma abordagem que visa trazer os princípios de microserviços para o desenvolvimento de front-ends, permitindo que grandes aplicações web sejam divididas em unidades menores e independentes. Uma das tecnologias-chave que possibilita essa abordagem é o Module Federation, um recurso poderoso do Webpack 5. Vamos exploraremos o que é o Module Federation, como ele funciona e como pode ser utilizado para construir aplicações modernas e escaláveis.

O que é Module Federation?

O Module Federation é um recurso do Webpack 5 que permite a execução de módulos JavaScript compartilhados entre diferentes aplicações ou diferentes partes de uma mesma aplicação. Ele facilita a criação de aplicações distribuídas, onde diferentes equipes podem desenvolver e implantar partes distintas da aplicação de forma independente.

Com o Module Federation, você pode:

  • Compartilhar Módulos: Permite que módulos sejam compartilhados entre diferentes aplicações sem a necessidade de duplicação.
  • Carregar Módulos Dinamicamente: Carregar módulos de forma dinâmica a partir de diferentes origens, o que é ideal para aplicações que utilizam uma arquitetura de micro front-end.
  • Atualizar Módulos Independentemente: Atualizar uma parte da aplicação sem precisar republicar toda a aplicação.

Como Funciona o Module Federation?

O funcionamento do Module Federation baseia-se em dois conceitos principais:

  • Host Application: É a aplicação que consome módulos de outras aplicações. Pode ser vista como a aplicação principal que integra outros módulos.
  • Remote Application: São as aplicações ou partes de aplicações que expõem módulos para outras aplicações. Eles fornecem seus módulos de forma que podem ser consumidos por aplicações host.

Vamos colocar a mão na massa!

Vamos desenvolver a aplicação com Angular onde teremos uma aplicação host e duas aplicações remotas isolad.

Requisitos:

  • Angular 18
  • Node 20.17.0

Bibliotecas:

Image description

No nosso caso teremos uma aplicação Host e duas outras que será os plugins das aplicações remotas

1 - Host Application

Para criar om mfe-host execute o comando:

ng new mfe-app-host
ng add @angular-architects/module-federation --project mfe-app-host --port 4200 --type host --skip-confirmation
Enter fullscreen mode Exit fullscreen mode

a - app/home

home.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-home',
  standalone: true,
  imports: [],
  templateUrl: './home.component.html',
  styleUrl: './home.component.css',
})
export class HomeComponent {}
Enter fullscreen mode Exit fullscreen mode

home.component.html

<h1>Home</h1>
Enter fullscreen mode Exit fullscreen mode

b - app/navbar

nabbar.component.ts

import { Component } from '@angular/core';
import { RouterLink } from '@angular/router';

@Component({
  selector: 'app-navbar',
  standalone: true,
  imports: [RouterLink],
  templateUrl: './nabbar.component.html',
  styleUrl: './nabbar.component.css',
})
export class NavbarComponent {}
Enter fullscreen mode Exit fullscreen mode

nabbar.component.html

<nav class="navbar">
  <div class="logo">
    <a href="#home">MFE</a>
  </div>
  <div class="nav-links">
    <a routerLink="/home">Home</a>
    <a routerLink="/dashboard-one">Dashboard One</a>
    <a routerLink="/dashboard-two">Dashboard Two</a>
  </div>
</nav>
Enter fullscreen mode Exit fullscreen mode

nabbar.component.css

.navbar {
  background-color: #333;
  overflow: hidden;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px 20px;
}

.navbar a {
  color: white;
  text-decoration: none;
  padding: 14px 16px;
}

.navbar a:hover {
  background-color: #ddd;
  color: black;
}

.logo {
  font-size: 24px;
  font-weight: bold;
}

.nav-links {
  display: flex;
}

@media screen and (max-width: 600px) {
  .navbar {
    flex-direction: column;
  }

  .nav-links {
    flex-direction: column;
    width: 100%;
  }

  .navbar a {
    text-align: center;
  }
}
Enter fullscreen mode Exit fullscreen mode

c) App Component

app.component.ts

import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { NavbarComponent } from './navbar/nabbar.component';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [RouterOutlet, NavbarComponent],
  templateUrl: './app.component.html',
  styleUrl: './app.component.css',
})
export class AppComponent {
  title = 'mfe-app-host';
}
Enter fullscreen mode Exit fullscreen mode

app.component.html

<app-navbar></app-navbar>
<router-outlet />
Enter fullscreen mode Exit fullscreen mode

d) Routes

app.routes.ts

import { Routes } from '@angular/router';
import { loadRemoteModule } from '@angular-architects/module-federation';
import { HomeComponent } from './home/home.component';

export const routes: Routes = [
  {
    path: 'mfe-dashboard-one',
    loadComponent: () =>
      loadRemoteModule({
        type: 'module',
        remoteEntry: 'http://localhost:4201/remoteEntry.js',
        exposedModule: './Component',
      }).then((m) => m.AppComponent),
  },
  {
    path: 'mfe-dashboard-two',
    loadComponent: () =>
      loadRemoteModule({
        type: 'module',
        remoteEntry: 'http://localhost:4202/remoteEntry.js',
        exposedModule: './Component',
      }).then((m) => m.AppComponent),
  },
  { path: 'home', component: HomeComponent },
  { path: '', redirectTo: '/home', pathMatch: 'full' },
];
Enter fullscreen mode Exit fullscreen mode

Detalhes:

Este código é uma configuração de rotas em um projeto Angular que utiliza a Federação de Módulos para carregar dinamicamente componentes de micro front-end remotos. Vamos detalhar cada parte do código:

Importações

import { Routes } from '@angular/router';
import { loadRemoteModule } from '@angular-architects/module-federation';
import { HomeComponent } from './home/home.component';
Enter fullscreen mode Exit fullscreen mode
  • Routes: É a interface do Angular usada para definir as rotas da aplicação. Uma rota associa um caminho (URL) a um componente ou módulo específico.
  • loadRemoteModule: Função fornecida pela biblioteca @angular-architects/module-federation. Ela é usada para carregar dinamicamente módulos ou componentes expostos por microfrontends remotos, permitindo que a aplicação principal consuma esses componentes sem carregá-los no início.
  • HomeComponent: O componente local que será renderizado quando a rota /home for acessada.

Definição de Rotas

export const routes: Routes = [
  {
    path: 'dashboard-one',
    loadComponent: () =>
      loadRemoteModule({
        type: 'module',
        remoteEntry: 'http://localhost:4201/remoteEntry.js',
        exposedModule: './Component', // Expondo o componente standalone
      }).then((m) => m.AppComponent), // Nome do componente standalone
  },
  {
    path: 'dashboard-two',
    loadComponent: () =>
      loadRemoteModule({
        type: 'module',
        remoteEntry: 'http://localhost:4202/remoteEntry.js',
        exposedModule: './Component', // Expondo o componente standalone
      }).then((m) => m.AppComponent), // Nome do componente standalone
  },
  { path: 'home', component: HomeComponent },
  { path: '', redirectTo: '/home', pathMatch: 'full' },
];
Enter fullscreen mode Exit fullscreen mode

Rota dashboard-one

{
  path: 'dashboard-one',
  loadComponent: () =>
    loadRemoteModule({
      type: 'module',
      remoteEntry: 'http://localhost:4201/remoteEntry.js',
      exposedModule: './Component',
    }).then((m) => m.AppComponent),
},
Enter fullscreen mode Exit fullscreen mode
  • path: 'dashboard-one': Define o caminho da URL para esta rota. Quando o usuário acessar /dashboard-one, esta rota será ativada.

  • loadComponent: Esta chave define que o componente para esta rota será carregado dinamicamente, em vez de ser carregado logo no início da aplicação. Isso ajuda a melhorar o tempo de carregamento inicial.

  • loadRemoteModule(): Função que carrega o módulo ou componente de um micro front-end remoto. O módulo exposto é definido no remoteEntry.js da aplicação remota que está rodando em http://localhost:4201/. A função carrega o módulo remoto e expõe o componente AppComponent.

type: 'module': Especifica que o tipo de módulo a ser carregado é um JavaScript ES module.

remoteEntry: 'http://localhost:4201/remoteEntry.js': Define o local do ponto de entrada (entry point) do micro front-end remoto, que é o arquivo remoteEntry.js gerado durante o build.

exposedModule: './Component': Este caminho especifica qual módulo ou componente foi exposto no micro front-end remoto. O remoteEntry.js expõe esse componente.

then((m) => m.AppComponent): Após carregar o módulo remoto, a função .then() extrai o componente específico (neste caso, AppComponent) e o associa à rota. Esse AppComponent é o componente standalone que foi exposto pelo micro front-end.

Rota dashboard-two

{
  path: 'dashboard-two',
  loadComponent: () =>
    loadRemoteModule({
      type: 'module',
      remoteEntry: 'http://localhost:4202/remoteEntry.js',
      exposedModule: './Component',
    }).then((m) => m.AppComponent),
},
Enter fullscreen mode Exit fullscreen mode

Esta rota é semelhante à dashboard-one, mas carrega um componente de outro micro front-end, disponível em http://localhost:4202/remoteEntry.js.

Rota home

{ path: 'home', component: HomeComponent },
Enter fullscreen mode Exit fullscreen mode

Define a rota /home, que carrega o componente local HomeComponent quando acessada. Este componente já está no projeto principal, então não requer carregamento dinâmico.

Rota padrão (redirecionamento)

{ path: '', redirectTo: '/home', pathMatch: 'full' },
Enter fullscreen mode Exit fullscreen mode
  • path: '': Define a rota padrão (a rota vazia).
  • redirectTo: '/home': Redireciona qualquer usuário que acessar a raiz (/) da aplicação diretamente para a rota /home.
  • pathMatch: 'full': Garante que o redirecionamento ocorra apenas quando o caminho completo for igual a '' (raiz). Isso evita redirecionamentos em URLs parciais.

e) Webpack

webpack.config.js

const {
  shareAll,
  withModuleFederationPlugin,
} = require("@angular-architects/module-federation/webpack");

module.exports = withModuleFederationPlugin({
  remotes: {
    mfeDashboardOne: "http://localhost:4201/remoteEntry.js",
    mfeDashboardTwo: "http://localhost:4202/remoteEntry.js",
  },

  shared: {
    ...shareAll({
      singleton: true,
      strictVersion: true,
      requiredVersion: "auto",
    }),
  },
});
Enter fullscreen mode Exit fullscreen mode

Detalhes:

Este código configura a Module Federation no Webpack em um projeto Angular, permitindo que múltiplas aplicações compartilhem módulos de forma dinâmica. Vamos detalhar cada parte:

Importações

const { 
  shareAll, 
  withModuleFederationPlugin 
} = require("@angular-architects/module-federation/webpack");
Enter fullscreen mode Exit fullscreen mode
  • shareAll: Esta função faz parte do pacote @angular-architects/module-federation e é usada para compartilhar dependências entre micro front-end. Ela permite que você especifique quais bibliotecas ou módulos devem ser compartilhados entre as diferentes aplicações que estão federadas, como dependências comuns (Angular, RxJS, etc.).
  • withModuleFederationPlugin: Essa função é um wrapper em torno do ModuleFederationPlugin do Webpack. O objetivo dela é simplificar a configuração do plugin, tornando-o mais fácil de usar com Angular. Ela gera a configuração necessária para a federação de módulos e integra-se automaticamente ao processo de build do Angular.

Exportação da Configuração

module.exports = withModuleFederationPlugin({
  remotes: {
    mfeDashboardOne: "http://localhost:4201/remoteEntry.js",
    mfeDashboardTwo: "http://localhost:4202/remoteEntry.js",
  },
Enter fullscreen mode Exit fullscreen mode
  • remotes: Esta chave define quais micro front-end serão carregados remotamente.

No caso, foi definido dois micro front-end:

Cada micro front-end tem sua própria aplicação Angular rodando e exporta componentes, módulos ou serviços que podem ser consumidos por outros aplicativos.

Dependências Compartilhadas

  shared: {
    ...shareAll({
      singleton: true,
      strictVersion: true,
      requiredVersion: "auto",
    }),
  },
});
Enter fullscreen mode Exit fullscreen mode
  • shared: Esta chave especifica as dependências que serão compartilhadas entre a aplicação principal e os micro front-end. O uso de dependências compartilhadas permite que você evite carregar múltiplas cópias de bibliotecas (como Angular ou outras bibliotecas comuns) em cada micro front-end, o que melhora o desempenho e reduz o tamanho do bundle.

O método shareAll() instrui a aplicação a compartilhar todas as dependências que já foram instaladas no node_modules, com algumas opções:

singleton: true: Esta opção garante que apenas uma instância de cada biblioteca será carregada e compartilhada entre os micro front-end. Isso é importante, especialmente no caso de bibliotecas como o Angular, que não funcionam corretamente se houver múltiplas instâncias da mesma dependência rodando.

strictVersion: true: Garante que todos os micro front-end usarão exatamente a mesma versão das bibliotecas compartilhadas. Isso previne problemas de incompatibilidade entre diferentes versões da mesma biblioteca.

requiredVersion: "auto": O Webpack irá automaticamente definir qual versão das dependências será usada, baseada no que está no arquivo package.json da aplicação.

2 - Remote Application Dashboard One

Para criar om mfe-dashboard-one execute o comando:

ng new mfe-dashboard-one
ng add @angular-architects/module-federation --project mfe-dashboard-one --port 4201 --type remote --skip-confirmation
npm install chart.js
Enter fullscreen mode Exit fullscreen mode

a - App Component

app.component.ts

import { Component, OnInit } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { Chart } from 'chart.js/auto';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [RouterOutlet],
  templateUrl: './app.component.html',
  styleUrl: './app.component.css',
})
export class AppComponent implements OnInit {
  ngOnInit() {
    this.createBarChart();
  }

  createBarChart() {
    new Chart('barChart', {
      type: 'bar',
      data: {
        labels: ['Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho'],
        datasets: [
          {
            label: 'Vendas',
            data: [12, 19, 3, 5, 2, 3],
            backgroundColor: 'rgba(75, 192, 192, 0.6)',
          },
        ],
      },
      options: {
        responsive: true,
        scales: {
          y: {
            beginAtZero: true,
          },
        },
      },
    });
  }
}
Enter fullscreen mode Exit fullscreen mode

app.component.html

<div class="dashboard">
  <h1>Dashboard</h1>
  <div class="chart-container">
    <canvas id="barChart"></canvas>
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

app.component.css

.dashboard {
  padding: 20px;
}
.chart-container {
  width: 100%;
  max-width: 600px;
  margin-bottom: 20px;
}
Enter fullscreen mode Exit fullscreen mode

b - Webpack

webpack.config.js

const {
  shareAll,
  withModuleFederationPlugin,
} = require("@angular-architects/module-federation/webpack");

module.exports = withModuleFederationPlugin({
  name: "mfe-dashboard-one",

  exposes: {
    "./Component": "./src/app/app.component.ts",
  },

  shared: {
    ...shareAll({
      singleton: true,
      strictVersion: true,
      requiredVersion: "auto",
    }),
  },
});
Enter fullscreen mode Exit fullscreen mode

Este código configura o Module Federation no Webpack para expor um componente de um micro front-end Angular chamado mfe-dashboard-one. Esse micro front-end poderá ser consumido por outras aplicações remotas. Vamos explicar cada parte em detalhes:

const { 
  shareAll, 
  withModuleFederationPlugin 
} = require("@angular-architects/module-federation/webpack");
Enter fullscreen mode Exit fullscreen mode
  • shareAll: Função que facilita o compartilhamento de dependências entre a aplicação principal e os micro front-end. Ela configura o que será compartilhado, como bibliotecas de terceiros ou módulos Angular comuns.
  • withModuleFederationPlugin: Função usada para configurar o Module Federation Plugin no Webpack de uma forma simplificada para projetos Angular. Ela ajuda a integrar as configurações necessárias da federação de módulos com o processo de build do Angular.

Exportação da Configuração

module.exports = withModuleFederationPlugin({
  name: "mfe-dashboard-one",

  exposes: {
    "./Component": "./src/app/app.component.ts",
  },
Enter fullscreen mode Exit fullscreen mode
  • name: "mfe-dashboard-one": Define o nome da aplicação federada. Esse nome é utilizado internamente no Webpack e também quando outras aplicações querem consumir os módulos ou componentes expostos por este micro front-end. No caso, o nome do micro front-end é "mfe-dashboard-one".

  • exposes: Esta chave define quais módulos ou componentes do micro front-end estarão disponíveis para outras aplicações consumirem. No caso:

"./Component": Esse é o nome do módulo ou caminho pelo qual o componente será acessado externamente. Quando outra aplicação precisar usar esse componente, ela o referenciará como mfe-dashboard-one/Component.

"./src/app/app.component.ts": Especifica o arquivo onde o componente está localizado no projeto. Neste caso, o componente a ser exposto é o AppComponent, que está definido no arquivo app.component.ts **dentro do diretório **src/app.

Isso significa que o componente AppComponent será exportado e poderá ser carregado dinamicamente por outras aplicações usando o caminho exposto (./Component).

Dependências Compartilhadas

  shared: {
    ...shareAll({
      singleton: true,
      strictVersion: true,
      requiredVersion: "auto",
    }),
  },
});
Enter fullscreen mode Exit fullscreen mode
  • shared: Esta chave é usada para definir as dependências que serão compartilhadas entre o micro front-end e outras aplicações que consomem este micro front-end. O objetivo é evitar carregar múltiplas instâncias das mesmas dependências, o que otimiza a performance e reduz o tamanho do bundle.

shareAll: A função shareAll compartilha todas as bibliotecas instaladas no node_modules, configurando as opções para controlar o compartilhamento.

singleton: true: Esta opção garante que somente uma instância de cada biblioteca seja carregada e utilizada em toda a aplicação e nos micro front-end. Isso é crucial, especialmente para bibliotecas que não funcionam corretamente com múltiplas instâncias, como o Angular.

strictVersion: true: Assegura que as versões das bibliotecas compartilhadas sejam exatamente as mesmas entre as diferentes aplicações e micro front-end. Isso evita problemas de compatibilidade de versões.

requiredVersion: "auto": Permite ao Webpack determinar automaticamente a versão correta das bibliotecas a serem compartilhadas, com base nas versões definidas no package.json.

3 - Remote Application Dashboard two

Para criar **mfe-dashboard-two **execute o comando:

ng new mfe-dashboard-one
ng add @angular-architects/module-federation --project mfe-dashboard-two --port 4202 --type remote --skip-confirmation
npm install chart.js
Enter fullscreen mode Exit fullscreen mode

a - App Component

app.component.ts

import { Component, OnInit } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { Chart } from 'chart.js/auto';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [RouterOutlet],
  templateUrl: './app.component.html',
  styleUrl: './app.component.css',
})
export class AppComponent implements OnInit {
  ngOnInit() {
    this.createPieChart();
  }

  createPieChart() {
    new Chart('pieChart', {
      type: 'pie',
      data: {
        labels: ['Vermelho', 'Azul', 'Amarelo'],
        datasets: [
          {
            label: 'Cores Favoritas',
            data: [300, 50, 100],
            backgroundColor: [
              'rgb(255, 99, 132)',
              'rgb(54, 162, 235)',
              'rgb(255, 205, 86)',
            ],
          },
        ],
      },
      options: {
        responsive: true,
      },
    });
  }
}
Enter fullscreen mode Exit fullscreen mode

app.component.html

<div class="dashboard">
  <h1>Dashboard</h1>
  <div class="chart-container">
    <canvas id="pieChart"></canvas>
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

app.component.css

.dashboard {
  padding: 20px;
}
.chart-container {
  width: 100%;
  max-width: 600px;
  margin-bottom: 20px;
}
Enter fullscreen mode Exit fullscreen mode

b - Webpack

webpack.config

const {
  shareAll,
  withModuleFederationPlugin,
} = require("@angular-architects/module-federation/webpack");

module.exports = withModuleFederationPlugin({
  name: "mfe-dashboard-two",

  exposes: {
    "./Component": "./src/app/app.component.ts",
  },

  shared: {
    ...shareAll({
      singleton: true,
      strictVersion: true,
      requiredVersion: "auto",
    }),
  },
});
Enter fullscreen mode Exit fullscreen mode

4 - Testar

Para testar execute cada aplicação com o comando:

npm start
Enter fullscreen mode Exit fullscreen mode

Acesse o link http://localhost:4200/, ao abrir será apresentado a tela:

Image description

Ao acessar no menu Dashboard Barra ou Dashboard Pizza, será apresentada as aplicações remotas que estão sendo executadas nas portas 4201 e 4202.

O código completo: https://github.com/wandealves/arquitetura-microfront-end

5 - Rotas Dinâmicas

Podemos usar rotas dinâmicas para acessar as aplicações remotas. Neste exemplo, teremos o HOST, que é a aplicação principal, e outras aplicações remotas que serão renderizadas dentro dela. Para disponibilizar essas aplicações, utilizaremos uma aplicação responsável por fornecê-las.

Image description

*5.1 - Aplicação HOST *

A criação é a mesma que já foi apresentada; o que muda é a forma como vamos obter as rotas de maneira dinâmica.

No app.config.ts, foi adicionado withHashLocation e provideHttpClient():

import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
import { provideRouter, withHashLocation } from '@angular/router';

import { routes } from './app.routes';
import { provideHttpClient } from '@angular/common/http';

export const appConfig: ApplicationConfig = {
  providers: [
    provideZoneChangeDetection({ eventCoalescing: true }),
    provideHttpClient(),
    provideRouter(routes, withHashLocation()),
  ],
};
Enter fullscreen mode Exit fullscreen mode

Foi criado o route-loader.service.ts, responsável por obter as rotas:

import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Routes } from '@angular/router';
import { map, Observable } from 'rxjs';

import { loadRemoteModule } from '@angular-architects/module-federation';

@Injectable({ providedIn: 'root' })
export class RouteLoaderService {
  private http = inject(HttpClient);

loadRoutes(): Observable<Routes> {
  return this.http.get<any[]>('http://localhost:3000/routes.json').pipe(
    map((routes) =>{
      return routes.map(route =>({
        path: route.path,
        loadComponent: () =>
          loadRemoteModule({
            type: route.type,
            remoteEntry: route.remoteEntry,
            exposedModule: route.exposedModule,
          }).then((m) => m.AppComponent),
      }));
    }
    )
  );
}
}
Enter fullscreen mode Exit fullscreen mode

No app.component.ts foi adicionado a chamada ao serviço e atualização das rotas:

import { Component, OnInit } from '@angular/core';
import { Router, RouterOutlet } from '@angular/router';
import { RouteLoaderService } from './services/route-loader.service';
import { NavbarComponent } from './navbar/navbar.component';

@Component({
  selector: 'app-root',
  imports: [RouterOutlet, NavbarComponent],
  templateUrl: './app.component.html',
  styleUrl: './app.component.css'
})
export class AppComponent implements OnInit {
  title = 'host';

  constructor(private routeLoader: RouteLoaderService, private router: Router) {}

  ngOnInit() {
    this.routeLoader.loadRoutes().subscribe({
      next: (routes) => {
       this.router.config = [...this.router.config, ...routes];
      },
      error: (err) => {
        console.error('Failed to load routes:', err);
      },
    });
  }
}
Enter fullscreen mode Exit fullscreen mode

5.2 - Provedora das apps

Nessa aplicação vai prover as aplicações, dentro da pasta public temos o arquivo routes.json com as rotas.

[
  {
    "path":"mfe-app-01",
    "type": "module",
    "remoteEntry": "http://localhost:3000/extensions/mfe-app-01/remoteEntry.js",
    "exposedModule":"./Component"
  },
  {
    "path":"mfe-app-02",
    "type": "module",
    "remoteEntry": "http://localhost:3000/extensions/mfe-app-02/remoteEntry.js",
    "exposedModule":"./Component"
  }
]
Enter fullscreen mode Exit fullscreen mode

dentro de public/extensions/mfe-app-01 e public/extensions/mfe-app-02 temos as aplicações compiladas e são providas nas rotas:

http://localhost:3000/extensions/mfe-app-01/remoteEntry.js
http://localhost:3000/extensions/mfe-app-02/remoteEntry.js

O projeto completo https://github.com/wandealves/arquitetura-microfront-end-rotas-dinamicas

6 - Conclusão

O Module Federation é uma ferramenta poderosa que pode transformar a forma como desenvolvemos aplicações web complexas. Ao permitir a integração e compartilhamento de módulos entre diferentes aplicações, ele facilita a construção de sistemas escaláveis e modulares, alinhados com os princípios de micro front-end. No entanto, é essencial considerar os desafios e gerenciar cuidadosamente as dependências e a performance para tirar o máximo proveito dessa tecnologia.

Referências:

Module Federation

Speedy emails, satisfied customers

Postmark Image

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

Top comments (2)

Collapse
 
paulo_csarsimpliciocor profile image
Paulo César Simplicio Correia

Caso o meu MFE possua mais de uma rota interna, como faço para que a aplicação host consiga acessar essas rotas. Por exemplo, tenho a aplicação host que carrega o MFE, que rodando sozinho, possui 3 rotas, como fazer para essas rotas continuarem funcionando ao carregar o MFE na aplicação host?

Collapse
 
wandealves profile image
Wanderson Alves Rodrigues

Opa vai ser algo semelhante, o maior problema será sincronizar as rotas no router-outlet, talvez tenha que adotar alguma forma além do que coloquei de exemplo:

Para que o MFE mantenha suas rotas internas funcionando quando carregado na aplicação host, você precisa configurar adequadamente o roteamento tanto no MFE quanto na aplicação host. Aqui está como fazer isso:

  1. Configurar o roteamento no MFE

Certifique-se de que o MFE possui um módulo de roteamento configurado corretamente, incluindo suas rotas internas. Por exemplo:

// mfe-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { AboutComponent } from './about/about.component';

const routes: Routes = [
  { path: '', component: HomeComponent },
  { path: 'about', component: AboutComponent },
];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule],
})
export class MfeRoutingModule {}
Enter fullscreen mode Exit fullscreen mode
  1. Expor o módulo de rota no Module Federation

No webpack.config.js do MFE, exponha o módulo principal que contém as rotas:

module.exports = {
  name: 'mfeApp',
  filename: 'remoteEntry.js',
  exposes: {
    './Module': './src/app/mfe-routing.module.ts',
  },
  shared: shareAll({ singleton: true, strictVersion: true, requiredVersion: 'auto' }),
};
Enter fullscreen mode Exit fullscreen mode
  1. Carregar o módulo de rota no host

No AppRoutingModule do host, carregue as rotas do MFE dinamicamente usando loadRemoteModule (parte do pacote @angular-architects/module-federation):

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { loadRemoteModule } from '@angular-architects/module-federation';

const routes: Routes = [
  {
    path: 'mfe',
    loadChildren: () =>
      loadRemoteModule({
        type: 'module',
        remoteEntry: 'http://localhost:4201/remoteEntry.js',
        exposedModule: './Module',
      }).then((m) => m.MfeRoutingModule),
  },
  { path: '', redirectTo: '', pathMatch: 'full' },
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
})
export class AppRoutingModule {}
Enter fullscreen mode Exit fullscreen mode
  1. Configurar rota base no MFE

Para garantir que o roteador do MFE funcione corretamente no contexto do host, configure a rota base no arquivo AppModule ou no main.ts do MFE:

import { APP_BASE_HREF } from '@angular/common';

@NgModule({
  providers: [{ provide: APP_BASE_HREF, useValue: '/' }],
})
export class AppModule {}
Enter fullscreen mode Exit fullscreen mode

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs