Frontend Development

Créer des Micro-Frontends évolutifs grâce à Module Federation dans Webpack 5

Dans le paysage en évolution du développement frontend, les applications monolithiques deviennent souvent des goulets d'étranglement pour les grandes équipes d'ingénierie. À mesure que les applications grossissent, la complexité de la gestion des dépendances, des cycles de déploiement et de la propriété du code augmente également. C'est ici que l'architecture Micro-Frontend brille, permettant aux équipes de construire, tester et déployer des applications frontend indépendantes. Alors que les premières implémentations s'appuyaient sur des shims iframe complexes ou des solutions de regroupement au moment de l'exécution, Webpack 5 a introduit une solution native et robuste : Module Federation.

Cet article explore comment tirer parti du Module Federation Plugin de Webpack 5 pour créer des micro-frontends véritablement évolutifs et indépendants, qui peuvent être partagés et consommés entre différentes applications sans la surcharge traditionnelle.

Qu'est-ce que Module Federation ?

Module Federation est un concept qui permet aux applications JavaScript d'importer dynamiquement du code depuis d'autres environnements d'exécution (navigateurs, serveurs ou Web Workers) au moment de l'exécution. Contrairement aux bundlers traditionnels qui résolvent les dépendances au moment de la construction, Module Federation les résout au moment de l'exécution. Cela signifie que l'Application A peut exécuter du code écrit dans l'Application B, comme s'il était local, à condition que les deux applications soient en cours d'exécution.

Les principaux avantages sont les suivants :

  • Déploiements indépendants : Les équipes peuvent mettre à jour et déployer leur micro-frontend spécifique sans toucher à l'application hôte.
  • Dépendances partagées : Des bibliothèques critiques comme React ou Redux peuvent être partagées entre les applications pour réduire la taille du bundle et assurer la cohérence.
  • Agnosticisme technologique : Bien que Webpack soit l'outil principal, le protocole permet l'intégration avec d'autres systèmes de construction, bien que Webpack offre l'implémentation la plus mature.

Configuration des applications Hôte et Distante

Pour illustrer Module Federation, supposons un scénario avec deux applications :

  1. App Hôte : L'application shell principale qui orchestre l'interface utilisateur.
  2. App Distante : Un module spécifique à une fonctionnalité (par exemple, un tableau de bord utilisateur ou un composant de chat) qui sera consommé par l'Hôte.

Étape 1 : Exposition des modules dans l'App Distante

D'abord, nous devons configurer l'App Distante pour exposer ses composants. Dans le fichier webpack.config.js de l'application distante, nous importons ModuleFederationPlugin et définissons le champ exposes.

const HtmlWebpackPlugin = require('html-webpack-plugin');
const { ModuleFederationPlugin } = require('webpack').container;

module.exports = {
  // ... autres configurations
  plugins: [
    new ModuleFederationPlugin({
      name: 'remoteApp',
      filename: 'remoteEntry.js',
      exposes: {
        './UserProfile': './src/components/UserProfile',
      },
      shared: {
        react: { singleton: true, requiredVersion: '^18.0.0' },
        'react-dom': { singleton: true, requiredVersion: '^18.0.0' }
      }
    }),
    new HtmlWebpackPlugin({
      template: './public/index.html'
    })
  ]
};

Ici, nous exposons ./UserProfile. Nous configurons également les dépendances shared. En définissant singleton: true, nous nous assurons qu'une seule instance de React est chargée entre les deux applications, évitant ainsi les incohérences d'état et réduisant la taille du payload.

Étape 2 : Consommation des modules dans l'App Hôte

Ensuite, nous configurons l'App Hôte pour consommer le module exposé. Nous ajoutons la configuration remote dans le ModuleFederationPlugin de l'application hôte.

new ModuleFederationPlugin({
  name: 'hostApp',
  remotes: {
    remoteApp: 'remoteApp@http://localhost:3001/remoteEntry.js',
  },
  shared: {
    react: { singleton: true, requiredVersion: '^18.0.0' },
    'react-dom': { singleton: true, requiredVersion: '^18.0.0' }
  }
})

Le champ remotes indique à Webpack où trouver le fichier d'entrée distant. Vous pouvez utiliser une URL statique ou un point de terminaison dynamique qui renvoie la configuration en fonction de l'environnement. Notez que la configuration shared doit correspondre à celle de l'application distante pour garantir la compatibilité.

Importation dynamique dans React

Avec la configuration en place, vous pouvez importer dynamiquement le composant distant en utilisant l'API System.import (polyfillisée par Webpack) ou les importations dynamiques standard. Voici un exemple dans un composant React :

import React, { lazy, Suspense } from 'react';

// Chargement paresseux du composant distant
const UserProfile = lazy(() => import('remoteApp/UserProfile'));

const HostComponent = () => {
  return (
    
Chargement...
}>
); }; export default HostComponent;

L'utilisation de lazy et Suspense est cruciale ici. Elle garantit que le code distant n'est téléchargé que lorsque cela est nécessaire et fournit une interface utilisateur de repli pendant la requête réseau.

Meilleures pratiques et défis

Bien que Module Federation simplifie l'architecture des micro-frontends, elle introduit de nouveaux défis :

Compatibilité des versions

Les dépendances partagées doivent avoir des versions compatibles. Si l'Hôte utilise React 18 et la Distante utilise React 17, l'application échouera probablement. Utilisez toujours le versionnement sémantique et documentez clairement les contraintes des dépendances partagées.

Limites d'erreur (Error Boundaries)

Si une application distante plante, elle ne doit pas faire planter l'ensemble du shell hôte. Enveloppez les composants distants dans des limites d'erreur React pour intercepter et afficher des messages d'erreur gracieux.

Communication entre les applications

Les micro-frontends sont faiblement couplés. La communication doit se faire via des événements personnalisés, des bibliothèques de gestion d'état (comme Redux ou Zustand) ou des composants web. Évitez la manipulation directe du DOM entre les limites des applications.

Conclusion

Module Federation de Webpack 5 est un changement majeur pour l'architecture frontend. Il démocratise le concept de micro-frontend en fournissant une solution standardisée, intégrée au moment de la construction, qui ne nécessite pas de démarrage complexe au moment de l'exécution. En permettant des déploiements indépendants et le partage de dépendances, il permet aux grandes organisations de faire évoluer efficacement leurs équipes d'ingénierie frontend.

Que vous migriez un monolithe hérité ou que vous construisiez une nouvelle plateforme à partir de zéro, Module Federation offre un ensemble d'outils puissant pour atteindre agilité, résilience et évolutivité dans vos applications JavaScript.

Share: