Architecture micro-frontends scalable avec Module Federation : host/remote apps, partage de dépendances, routing fédéré et bonnes pratiques.
Introduction
Module Federation est une technologie Webpack qui permet de charger des applications Angular indépendantes dans une application hôte. C'est parfait pour les équipes distribuées travaillant sur des modules isolés tout en partageant les dépendances communes.
Concept fondamental
Module Federation repose sur une architecture Host-Remote :
- Host App : Application principale qui orchestre le chargement des remote apps
- Remote Apps : Applications indépendantes exposant des modules réutilisables
- Partage de dépendances : Angular, RxJS et autres libs chargés une seule fois
Configuration Host App
La host app configure ModuleFederationPlugin en spécifiant les remotes — c'est-à-dire, où charger les modules distants :
// webpack.config.js (Host App)
import { ModuleFederationPlugin } from '@angular-architects/module-federation/webpack';
import { share } from '@angular-architects/module-federation/build-tools';
export const config = {
output: {
uniqueName: 'host', // Nom unique pour la host
publicPath: 'auto', // URLs relatives pour dev/prod
},
plugins: [
new ModuleFederationPlugin({
name: 'host',
filename: 'remoteEntry.js', // Fichier d'entrée
remotes: {
// Chemin vers les remote apps et leur module exposé
userModule: 'user_module@http://localhost:4201/remoteEntry.js',
productModule: 'product_module@http://localhost:4202/remoteEntry.js',
},
shared: share({ // Dépendances partagées
'@angular/core': { singleton: true, strictVersion: true },
'@angular/common': { singleton: true, strictVersion: true },
'rxjs': { singleton: true, strictVersion: true },
}),
}),
],
};
Explication : Quand la host démarre, elle charge les fichiers remoteEntry.js des remotes. Ces fichiers indiquent quel code exposer et quelles dépendances partager.
Configuration Remote App
Chaque remote expose ses modules via exposes dans sa configuration Webpack :
// webpack.config.js (Remote App : user-module)
import { ModuleFederationPlugin } from '@angular-architects/module-federation/webpack';
export const config = {
output: {
uniqueName: 'user_module', // Doit être unique
publicPath: 'auto',
},
plugins: [
new ModuleFederationPlugin({
name: 'user_module',
filename: 'remoteEntry.js', // Généré à la racine du build
exposes: {
// Chemin interne → nom exporté
'./UserModule': './src/app/user/user.module.ts',
'./UserService': './src/app/user/user.service.ts',
},
shared: { // Même dépendances que la host
'@angular/core': { singleton: true, strictVersion: true },
'@angular/common': { singleton: true, strictVersion: true },
'rxjs': { singleton: true, strictVersion: true },
},
}),
],
};
À retenir : L'URL doit pointer vers le remoteEntry.js généré. En production, ce sera l'URL CDN ou du serveur Nginx de la remote app.
Stratégie de partage des dépendances
L'intérêt majeur de Module Federation est d'éviter les téléchargements multiples. La host et les remotes partagent Angular, RxJS et autres libs :
// Configuration partagée optimale
shared: {
'@angular/core': {
singleton: true, // Une seule instance dans le navigateur
strictVersion: true, // Même version partout
requiredVersion: '18.0.0', // Version minimale requise
},
'@angular/common': { singleton: true, strictVersion: true },
'@angular/forms': { singleton: true, strictVersion: true },
'rxjs': {
singleton: true,
strictVersion: false, // RxJS tolère les versions mineures différentes
},
'axios': { singleton: true }, // Pour les services HTTP personnalisés
}
strictVersion: false avec prudence.
Intégration du routeur
Chargez les modules remotes via le routeur Angular :
// app.routes.ts (Host App)
import { loadRemoteModule } from '@angular-architects/module-federation-runtime';
export const routes: Routes = [
{
path: 'users',
loadChildren: () =>
loadRemoteModule({
type: 'module',
remoteEntry: 'http://localhost:4201/remoteEntry.js',
exposedModule: './UserModule',
}).then(m => m.UserModule),
},
{
path: 'products',
loadChildren: () =>
loadRemoteModule({
type: 'module',
remoteEntry: 'http://localhost:4202/remoteEntry.js',
exposedModule: './ProductModule',
}).then(m => m.ProductModule),
},
];
Avantage : Chaque module remote se charge dynamiquement quand l'utilisateur navigue vers sa route. Zéro impact au démarrage initial.
Conclusion
Module Federation transforme la façon de développer les grandes applications Angular. Les équipes travaillent indépendamment, déploient en parallèle et partagent les ressources intelligemment.
- Utilisez
@angular-architects/module-federationpour simplifier la configuration - Documentez les contrats entre host et remotes (versions, modules exposés)
- Mettez en place un système de versionning pour les remotes exposés
- Testez les fallbacks en cas d'absence d'une remote (loading states)