Accueil / Articles / Micro-frontends React avec Webpack Module Federation

Micro-frontends React avec Webpack Module Federation

Remplacez les solutions de contournement avec iframe par Webpack 5 Module Federation afin que les applications React hébergées et distantes partagent un environnement de exécution, puissent être déployées indépendamment tout en restant perçues comme un seul produit.

1148 mots

Les grandes surfaces de produit ne forment que rarement un seul frontend. Les processus de paiement, les tableaux de bord, les paramètres ainsi que l’interface qui les entoure appartiennent souvent à des équipes différentes, chacune ayant son propre backlog, ses dettes techniques et son calendrier de livraison. Cette structure est généralement appelée micro-frontends : des fragments d’interface gérés de manière indépendante mais qui se présentent néanmoins comme un seul produit, l’équivalent côté client des microservices.

Pendant longtemps, les outils React adaptés à ce modèle étaient peu pratiques. Les organisations soit utilisaient un seul gros bundle SPA, soit intégraient des applications distinctes dans des iframes en acceptant les inconvénients associés. Module Federation de Webpack 5 a rendu possible une troisième approche : des applications JavaScript développées et déployées de manière indépendante, qui se combinent en temps de exécution au sein d’un même document navigateur. Comprendre ce que cette fonctionnalité permet — et pourquoi elle a remplacé les anciennes solutions — est essentiel pour quiconque conçoit des systèmes React multi-équipes.

Le problème avant Module Federation

Au moment où Federation a été lancé, les équipes souhaitant une livraison indépendante de l’interface utilisateur disposaient de peu de choix.

La solution par défaut était l’SPA monolithique : un seul répertoire, une seule chaîne de traitement, un seul déploiement. Ce modèle convient bien à un petit groupe. Mais à mesure que les responsabilités se répartissent, les frictions augmentent. Chaque fonctionnalité partage la même compilation. Les temps de compilation augmentent avec l’ampleur du code. Une régression dans un domaine peut bloquer le processus de déploiement d’une autre équipe. Aligner les déploiements entre de nombreux groupes devient alors une tâche de gestion de projet à part entière.

Les iframes constituaient l’autre solution couramment utilisée. En intégrant une application enfant complète à l’intérieur d’une page parente, on obtenait une véritable indépendance de déploiement, c’est pourquoi de nombreuses entreprises les utilisaient. Cependant, les inconvénients s’accumulaient rapidement :

  • L’isolation est absolue. Les styles, le DOM et les contextes JavaScript ne se mélangent pas. Partager des états, coordonner des données ou imposer un langage de conception unique entre éléments parents et enfants devient une tâche technique complexe au lieu d’un simple transfert de propriétés.
  • Les dépendances se dupliquent. Chaque frame charge souvent son propre React, ses bibliothèques partagées et son CSS. Les utilisateurs téléchargent donc les mêmes données à plusieurs reprises.
  • L’expérience utilisateur se détériore. Le défilement, le ciblage, la modification de taille, les liens profonds et l’historique entre les frames nécessitent des solutions personnalisées, ce qui rend l’expérience globale moins fluide.
  • Le SEO et l’accessibilité en pâtissent. Le contenu présent dans les frames est plus difficile à indexer et moins compatible avec les technologies d’assistance.
  • La communication se limite aux messages. Les échanges de données entre frames s’effectuent via postMessage et des protocoles personnalisés — sans mémoire partagée, sans contexte React commun.

Les iframes ont résolu le problème de déploiement indépendant mais ont créé un problème encore plus grave de intégration propre. Ce qui manquait, c’était une indépendance lors de la construction et du déploiement sans pour autant abandonner une expérience utilisateur basée sur un seul document.

Qu’est-ce que la Module Federation ?

La Module Federation, introduite avec Webpack 5, permet aux applications JavaScript développées et déployées séparément de partager du code en temps de exécution plutôt qu’au moment de la compilation.

En pratique, vous pouvez exécuter plusieurs applications — provenant de différentes équipes, processus de développement et versions — qui se combinent néanmoins dans le navigateur en un seul produit. Une application expose un composant, une route ou un outil d’aide ; une autre l’utilise comme s’il faisait partie du même package, sans devoir reconstruire l’application consommatrice lorsque le fournisseur change.

Cette composition en temps de exécution constitue aujourd’hui la base technique habituelle des micro-frontends React.

Fonctionnement : hôtes, éléments distants et dépendances partagées

La fédération définit deux rôles :

  • hôte charge du code publié ailleurs. Il s’agit souvent de l’environnement qui monte l’interface utilisateur d’autres équipes.
  • élément distant publie des modules pour les autres : pages, composants, hooks ou utilitaires.

Une application peut être les deux à la fois : exposer certains modules tout en en consommant d’autres.

Les éléments distants déclarent leurs exportations dans la configuration de Webpack ; les hôtes indiquent quels éléments distants charger et quels symboles importer. Le chargement a lieu dans le navigateur en utilisant une URL d’entrée distante. La compilation de l’hôte n’a pas besoin du code source de l’élément distant — seulement un point d’entrée stable qu’il peut récupérer lorsque l’application s’exécute.

Les dépendances partagées complètent l’image. Lorsque le hôte et le serveur distant ont tous deux besoin de React, Federation peut être configuré pour partager une seule instance de React au lieu d’en envoyer deux. Cela élimine la duplication de type iframe tout en permettant aux équipes de choisir des versions différentes lorsque c’est nécessaire.

Federation de modules vs. Iframes

C’est cette comparaison qui explique pourquoi de nombreuses équipes ont abandonné les iframes une fois Federation mature. On conserve l’indépendance de déploiement qui rendait les iframes attrayants, sans pour autant sacrifier la qualité d’intégration. Les composants distants s’insèrent dans le DOM du hôte, partagent un même environnement JavaScript et peuvent réutiliser des fournisseurs, des états et des paquets de systèmes de conception — tâches qui étaient difficiles ou impossibles à réaliser à travers les limites d’un iframe.

Pourquoi les grandes équipes l’utilisent

Les petits produits ont rarement besoin de ce type de mécanisme. Les organisations disposant de nombreuses équipes frontend utilisent Federation pour résoudre des goulots d’étranglement structurels :

  • Déploiement indépendant. Un serveur distant peut déployer une correction sans devoir recompiler les artefacts de tous les autres groupes.
  • Autonomie des équipes. Chaque groupe conserve son propre rythme de travail, ses outils d’intégration continue et, dans certaines limites, le choix de ses outils.
  • Compilations plus rapides. Des serveurs distants séparés permettent à de petites modifications de ne pas entraîner la recompilation du tout.
  • Modernisation progressive. Les systèmes anciens peuvent intégrer progressivement de nouveaux serveurs distants plutôt que de procéder à un changement complet d’un seul coup.
  • Flexibilité de la stack technique. Partager un framework est le plus simple, mais les équipes peuvent parfois relier des versions majeures – ou, avec plus d’efforts, différents frameworks – à travers les frontières de la Federation.

Cas d’usage dans le monde réel

Les sites e-commerce permettent souvent aux équipes chargées du catalogue, du paiement et des comptes d’utiliser des outils distants séparés. Les produits SaaS fournissent des widgets de tableau de bord ou des panneaux de configuration développés par les équipes fonctionnelles, sans avoir à modifier l’interface principale pour chaque changement. Les migrations permettent de séparer progressivement des parties d’une application SPA existante en outils distants, tout en laissant fonctionner l’interface ancienne.

Résumé des avantages principaux

Les avantages de la fédération sont peu nombreux : une capacité de déploiement réellement indépendante, un environnement d’exécution partagé qui évite les bibliothèques redondantes et les communications fragiles entre applications, ainsi qu’une expérience utilisateur qui reste celle d’une seule application. Elle offre l’autonomie promise par les iframes, sans les coûts liés à l’intégration et aux performances.

Conclusion

Le passage des iframes à Module Federation s’inscrit dans une maturité accrue de l’architecture frontend : l’indépendance des déploiements et une expérience utilisateur cohérente n’ont plus besoin d’être opposées. Webpack 5 a rendu cette combinaison possible pour les organisations axées sur React qui avaient dépassé les limites d’un seul bundle. À mesure que son adoption augmente et que des outils tels que Rspack et Module Federation 2.0 développent ces mêmes idées de partage de runtime, comprendre les raisons de ce changement aide quiconque conçoit de grands systèmes React à définir intentionnellement les limites de responsabilité, plutôt que de recourir par défaut aux iframes ou à un monolithe en constante expansion.

Essayez-le vous-même

Un exemple minimal d’hôte/éloigné est disponible à react_module_federation.

Clonez-le localement :

git clone https://github.com/ModithaM/react_module_federation.git
cd react_module_federation

Démarrez d’abord l’éloigné afin que son point d’accès soit disponible avant que l’hôte ne demande des modules :

cd remote
npm install
npm start

Dans un deuxième terminal, démarrez l’hôte :

cd host
npm install
npm start

Ouvrez l’hôte dans le navigateur ; il doit charger les composants distants en temps de exécution et démontrer la relation décrite ci-dessus. L’ordre est important : un hôte lancé seul n’a rien à récupérer tant que le composant distant n’est pas opérationnel, ce qui rappelle utilement que l’indépendance de Federation dépend toujours du fait que les composants distants soient accessibles au démarrage de la shell.