Nguyen Le Phong

Les fondamentaux de l'architecture logiciellePartie 6 sur 6

Micro-Frontends : Quand Ça Vaut le Coup, et Ce Que Ça Coûte

Diviser le frontend en pièces déployables indépendamment peut libérer les équipes — ou vous noyer dans la complexité. Rédigé à partir de l'expérience de livraison d'une configuration Angular-host + modules React à grande échelle : quand les micro-frontends rapportent, et la facture qu'ils entraînent.

Imaginez un dépôt qui a démarré comme une app Angular bien rangée pour vingt développeurs et qui, trois ans plus tard, compte cinquante-plus ingénieurs qui y commitent chaque jour. Chaque pull request touche le même bundle. Un correctif de bug dans le flux de caisse casse accidentellement l'assistant d'intégration parce qu'ils importent tous deux un utilitaire partagé que quelqu'un a discrètement modifié. Le calendrier des releases ressemble à un jeu de Tetris — cinq équipes s'alignant pour faire entrer leur fonctionnalité dans l'unique fenêtre de déploiement planifiée. Tout le monde attend tout le monde, et personne ne livre aussi vite qu'il le souhaite.

C'est la douleur qui pousse les architectes frontend à chuchoter l'expression micro-frontends. L'idée semble séduisante : si les microservices ont libéré les équipes backend du monolithe, pourquoi ne pourrait-on pas faire de même pour l'interface ? Donnez à chaque équipe sa propre tranche frontend déployable indépendamment, et laissez le navigateur (ou un serveur) les assembler en un seul produit sans couture.

Mais l'analogie coupe dans les deux sens. Les microservices ont apporté une vraie liberté — et une vraie douleur opérationnelle. Les micro-frontends ne sont pas différents. Ayant livré un host Angular avec des modules de fonctionnalités React dans une entreprise multi-équipes, je veux vous donner la version honnête : ce qui a fonctionné, ce qui a fait mal, et les questions auxquelles vous devriez répondre avant de commencer à diviser.

Ce que sont les micro-frontends

Le terme a été popularisé vers 2016–2017 alors que les équipes remarquaient que la révolution des microservices n'avait pas atteint le navigateur. Dans une application monopage classique, un bundle frontend monolithique possède tout : le routage, l'état, chaque composant, les fonctionnalités de chaque équipe. Les micro-frontends appliquent la même idée de décomposition à la couche UI.

Un micro-frontend est une partie de l'interface utilisateur qui peut être construite et déployée indépendamment, possédée de bout en bout par une seule équipe. Cette équipe contrôle son propre dépôt (ou au moins son propre pipeline de build), son propre cycle de release et ses propres choix technologiques dans des limites convenues. À l'exécution, une application shell — parfois appelée le host ou container — compose ces pièces pour former le produit unifié que l'utilisateur voit.

Le changement clé est la propriété. Dans un monorepo avec du code partagé, un changement dans un utilitaire partagé peut casser la fonctionnalité de n'importe quelle équipe ; la coordination est constante. Avec les micro-frontends, le déploiement de Team A du module de caisse ne nécessite pas un accord de Team B. Le contrat entre elles est l'interface d'intégration convenue, pas du code source partagé.

Une app shell/container au sommet compose des modules frontend déployés indépendamment par l'Équipe A, l'Équipe B et l'Équipe C en une seule page dans le navigateur. Shell / Container App routing · auth · shared nav · orchestration TEAM A Checkout MFE React · own deploy TEAM B Dashboard MFE Angular · own deploy TEAM C Profile MFE Vue · own deploy v2.4.1 · deployed v1.9.0 · deployed v3.1.2 · deployed BROWSER — composed at runtime into one seamless product
L'app shell possède le routage, l'authentification et la navigation globale. Chaque équipe livre son propre micro-frontend à sa propre cadence. Le navigateur les assemble en une seule expérience — l'utilisateur voit un seul produit, même si trois équipes ont déployé indépendamment.

Approches d'intégration

« Micro-frontends » est une famille de techniques, pas une seule technologie. La façon dont vous assemblez les pièces a d'énormes conséquences sur l'autonomie des équipes, les performances et la complexité opérationnelle. Voici les cinq approches principales :

ApprocheComment ça fonctionnePrincipal compromis
Intégration au moment du build (packages npm) Chaque micro-frontend est publié comme un package npm versionné. Le shell les installe comme dépendances et bundle tout ensemble. Simple à mettre en place, mais les équipes doivent coordonner les releases — mettre à jour un remote signifie que le shell doit se re-déployer. Pas vraiment indépendant.
Composition côté serveur Un reverse proxy ou une couche edge (ex. Nginx, une edge function Next.js, Tailor de Zalando) récupère des fragments HTML de différents services et les assemble avant que la réponse n'atteigne le navigateur. Idéal pour le SEO et le premier rendu ; ajoute une complexité d'infrastructure et une nouvelle surface de latence entre services.
À l'exécution via Module Federation Webpack 5 (ou ses équivalents Rspack/Vite) permet aux builds d'exposer des modules chargés par le shell à l'exécution depuis des URLs CDN séparées, sans re-bundling. Vraie indépendance — les remotes se déploient sans toucher le shell — mais le décalage de versions, la négociation des dépendances partagées et les outils de débogage sont difficiles.
iframes Chaque micro-frontend tourne dans son propre iframe. L'isolation est quasi-parfaite ; la communication se fait via postMessage. Isolation et frontière de sécurité solides, mais UX terrible (scroll, focus, liens profonds, accessibilité — tout nécessite des tuyauteries sur mesure) ; semble dépassé.
Web Components Chaque micro-frontend expose un élément HTML personnalisé (<checkout-app>). Le shell insère l'élément dans la page ; le navigateur gère le cycle de vie. Indépendant du framework par conception, mais le support SSR est immature, et l'état partagé complexe nécessite toujours un bus d'événements global ou une solution de contexte.

En pratique, Module Federation est devenu le choix dominant pour les grandes équipes recherchant une vraie indépendance à l'exécution. Le plugin Webpack 5 qui le fournit a été porté sur Rspack et a des équivalents Vite (ex. @originjs/vite-plugin-federation). Quand quelqu'un dit aujourd'hui « on fait des micro-frontends », il parle presque toujours de Module Federation.

Conseil : commencez par la composition côté serveur si le SEO compte

Si votre app doit apparaître dans les résultats de recherche et que vous abordez les micro-frontends pour la première fois, la composition côté serveur vous donne le HTML le plus propre avant que le navigateur y touche. Module Federation est le choix puissant, mais il nécessite une histoire de déploiement plus mature avant de payer.

Pourquoi les équipes les adoptent

Les motivations pour passer aux micro-frontends sont cohérentes parmi les entreprises que j'ai vues. Elles remontent presque toujours à l'une de ces quatre pressions :

  • Déploiements indépendants. La raison la plus citée de loin. Quand quinze équipes partagent un seul build frontend, un déploiement est une taxe de coordination — tout le monde attend que le travail de tout le monde passe le QA. Les micro-frontends permettent à l'Équipe A de livrer le mardi sans attendre que la fonctionnalité à moitié finie de l'Équipe B soit prête. La fréquence des releases augmente ; le rayon d'impact par release diminue.
  • Autonomie et propriété des équipes. Une équipe qui peut construire, tester et déployer sa tranche de bout en bout avance plus vite et se sent plus responsable. La « propriété full-stack » devient réelle quand le frontend n'est pas un bien commun sur lequel tout le monde trébuche.
  • Migration technologique incrémentale. C'est sous-estimé. Si vous faites tourner une app AngularJS vieille de cinq ans et que vous voulez passer à React, vous ne pouvez pas tout réécrire d'un coup. Les micro-frontends vous permettent de remplacer une route à la fois avec un nouveau module React pendant que le reste de l'app AngularJS continue de tourner. C'est le pattern strangler fig, appliqué au frontend.
  • Isolation des pannes. Une erreur JavaScript à l'exécution dans le micro-frontend de caisse plante le module de caisse, pas toute l'app. Le shell peut attraper l'erreur boundary, afficher un fallback et laisser l'utilisateur naviguer ailleurs. Dans un monolithe, une erreur non catchée déchire souvent toute la page.

Les vrais coûts

C'est là que beaucoup de billets de blog se taisent. Les micro-frontends ont une vraie facture, et vous devriez la voir clairement avant de signer.

Duplication du bundle et des dépendances. Si trois micro-frontends bundlent chacun leur propre copie de React, l'utilisateur télécharge React trois fois. Le mécanisme de portée partagée de Module Federation peut dédupliquer à l'exécution, mais le configurer correctement entre équipes — surtout quand les versions dérivent — n'est pas trivial. Une architecture micro-frontend naïve peut en fait gonfler votre payload par rapport à un monolithe bien optimisé.

Partager un système de design. Une apparence et une sensation uniformes nécessitent une bibliothèque de composants partagée. Si cette bibliothèque est consommée au moment du build (npm), chaque micro-frontend qui la met à jour doit être re-déployé. Si elle est consommée à l'exécution via Module Federation, vous avez besoin d'une stratégie de versioning et de compatibilité. Dans les deux cas, le système de design devient un point de coordination inter-équipes — exactement ce que vous essayiez d'éliminer.

État global et communication inter-MFE. Les micro-frontends sont supposés être indépendants, mais les utilisateurs sont holistiques. Un badge de notification dans le shell a besoin de connaître une action dans le module de caisse. Un événement d'authentification dans un module doit se propager partout. Les solutions vont d'un store Redux partagé (couplage fort) à un bus d'événements personnalisé ou un objet de contexte partagé sur le window global — tous des armes à double tranchant qui nécessitent de la discipline pour être utilisées en sécurité.

Décalage de versions. Parce que les équipes déploient indépendamment, à tout moment le shell peut faire tourner une version de Module Federation qui attend le format d'entrée remote v1, tandis que le dernier déploiement de l'Équipe C émet le format v2. Ces incompatibilités se manifestent par des erreurs à l'exécution cryptiques difficiles à reproduire en local et encore plus difficiles à tracer en production. Vous avez besoin de contrats de compatibilité explicites et de stratégies de dégradation gracieuse.

Performances à l'exécution. Plusieurs chargements de bundles asynchrones, négociation de modules à l'exécution, récupérations en cascade des entrées remote — les micro-frontends introduisent une latence qu'un monolithe, avec tout statiquement bundlé, n'a tout simplement pas. Un préchargement soigneux, une stratégie CDN et HTTP/2 push aident tous, mais ils nécessitent un investissement actif.

Opérations et observabilité plus lourdes. Vous avez maintenant N pipelines de déploiement, N ensembles de règles d'invalidation du cache CDN, N configurations de build et N ensembles de logs d'erreurs à corréler quand quelque chose se passe mal à travers les frontières de modules. La surcharge DevOps est réelle. Vous voudrez du traçage distribué, des logs structurés incluant la version du micro-frontend et un tableau de bord d'alertes partagé avant de passer en production.

La complexité va toujours quelque part

Diviser un monolithe en pièces indépendantes ne réduit pas la complexité totale — elle la déplace du code source vers la couche d'intégration, les outils opérationnels et les contrats inter-équipes. Si votre organisation n'est pas prête à investir dans cette infrastructure opérationnelle, vous vous retrouverez avec un monolithe distribué : tout le couplage d'un monolithe, plus toute la surcharge opérationnelle d'un système distribué.

Livrer Angular-host + modules React : le récit honnête

Il y a quelques années, j'ai fait partie de l'équipe qui a pris une grande plateforme Angular — plusieurs centaines de milliers de lignes, cinq squads produit, une cadence de release trimestrielle qui ressemblait plus à une prise d'otages qu'à un processus produit — et l'a migrée vers une architecture Module Federation : un shell Angular hébergeant des modules de fonctionnalités React déployés indépendamment.

Voici ce qui a réellement fonctionné.

  • Les cycles de déploiement indépendants ont changé la culture. En deux mois, des squads qui livraient historiquement chaque trimestre livraient chaque semaine. La boucle de rétroaction s'est compressée. Les ingénieurs ont commencé à se soucier davantage de l'observabilité parce que c'était eux qui regardaient le tableau de bord après que leur propre déploiement soit sorti.
  • L'isolation des fonctionnalités a réduit dramatiquement la surface de régression. Un changement dans le module de facturation n'avait plus de chemin théorique pour casser la page des paramètres utilisateur. Notre suite de tests de régression a diminué de portée par équipe ; les tests d'intégration se sont concentrés sur les points de contrat plutôt que sur l'app entière.
  • La migration incrémentale a été une bouée de sauvetage. Nous n'avions pas de gel de réécriture big-bang de six mois. Les modules React ont remplacé les vues Angular une route à la fois, sur dix-huit mois, pendant que le produit continuait de livrer. Les parties prenantes métier ont à peine remarqué la transition — ce qui est exactement ce que vous voulez.

Voici ce qui a fait mal.

  • L'état partagé était un mal de tête permanent. Nous nous sommes retrouvés avec un bus d'événements personnalisé sur l'objet window global — fonctionnel, mais fragile. Quand deux équipes ont indépendamment changé la forme du payload d'événement, nous avons eu des bugs silencieux qui n'apparaissaient que dans des séquences de navigation spécifiques. Nous avons finalement modélisé les événements inter-MFE comme une API interne, avec un registre de schémas, ce qui a énormément aidé mais a coûté des semaines à construire.
  • Les dépendances en double ont gonflé le bundle. Bien configurer le shared de Module Federation entre Angular et React — deux systèmes de build différents — a demandé un vrai effort. Pendant plusieurs sprints, les utilisateurs téléchargeaient deux copies de RxJS et presque deux copies d'une bibliothèque de graphiques avant qu'on le détecte. L'analyse automatisée du bundle en CI est devenue indispensable.
  • La coordination des versions n'a jamais complètement disparu. La version Angular du shell et la matrice de dépendances des modules React devaient rester vaguement compatibles. Quand Angular a sorti une mise à jour majeure, on ne pouvait pas juste mettre à niveau le shell ; on devait d'abord auditer les dépendances peer de chaque module. Le coût de coordination était plus faible qu'avec le monolithe, mais il n'a pas disparu.

Le verdict final : l'architecture était le bon choix pour cette organisation à cette échelle. Mais pour être honnête, nous avons sous-estimé l'investissement opérationnel d'environ trente pour cent, et le problème d'état partagé a pris deux fois plus de temps à résoudre proprement que prévu. Allez-y les yeux ouverts.

Quand NE PAS utiliser les micro-frontends

Le signe le plus clair que les micro-frontends ne conviennent pas à votre situation, c'est quand la principale source de douleur frontend n'est pas la coordination à grande échelle des équipes — c'est autre chose.

  • Une seule petite équipe. Si tout le monde côté frontend peut tenir dans un seul appel vidéo, vous n'avez pas de problème de coordination. Vous avez un codebase à organiser. Les micro-frontends vous donneraient toute la surcharge opérationnelle sans aucun bénéfice d'autonomie des équipes. Utilisez plutôt un frontend monolithique modulaire avec des frontières de modules bien imposées.
  • Une petite application. Si tout le frontend est quelques routes et quelques milliers de lignes, le diviser crée plus de surface d'infrastructure que le produit lui-même. La surcharge de la configuration de Module Federation et d'un CD multi-pipeline l'emporte largement sur tout bénéfice.
  • Quand un monorepo avec de bonnes frontières ferait l'affaire. Nx, Turborepo et des outils similaires vous permettent d'imposer des frontières de modules strictes, d'exécuter des builds uniquement pour les packages affectés et de donner aux équipes un certain degré de propriété — sans la complexité de composition à l'exécution. Pour beaucoup d'entreprises dans la tranche 20–80 ingénieurs, un monorepo bien structuré est le meilleur compromis. Il est aussi dramatiquement plus facile à refactoriser.
  • Quand votre équipe n'est pas encore à l'aise avec les bases. Si votre pipeline CI/CD est peu fiable, votre histoire d'observabilité est mince, ou qu'il y a des dysfonctionnements de communication inter-équipes non résolus, ajouter la complexité des micro-frontends amplifiera tous ces problèmes. Consolidez d'abord les fondations.

C'est étroitement analogue à la décision côté backend. Tous les backends ne devraient pas être une flotte de microservices — et le même raisonnement s'applique ici. Si vous n'avez pas lu Monolithe → Microservices, les questions qu'il pose avant de diviser un backend s'appliquent presque mot pour mot au frontend : avez-vous des besoins de mise à l'échelle indépendante, des domaines de panne indépendants et des équipes réellement autonomes ? Si non, le monolithe — ou le monolithe modulaire — est probablement la meilleure réponse.

Le point idéal du monolithe modulaire

Un monorepo frontend bien organisé avec des frontières de lint strictes, des packages appartenant à chaque équipe et un système de build incrémental rapide vous donne 70–80 % du bénéfice d'autonomie à une fraction du coût opérationnel. Avant de vous tourner vers Module Federation, demandez-vous si des frontières de modules plus propres dans votre codebase actuel résoudraient le vrai problème.

Par taille d'entreprise

L'une des lentilles les plus utiles pour cette décision est simplement : combien d'ingénieurs frontend avez-vous, et à quel point leurs équipes doivent-elles fonctionner indépendamment ?

Taille de l'organisationStructure typique de l'équipe frontendRecommandationPattern d'exemple du monde réel
Petite (< 15 développeurs FE) Un ou deux squads, tout le monde connaît le code de tout le monde. Non. Utilisez un monolithe modulaire ou un monorepo bien structuré. La surcharge de coordination des micro-frontends dépasse le bénéfice. Startups SaaS en phase précoce : app Next.js avec des dossiers de fonctionnalités et des imports stricts — livre vite, facile à raisonner.
Taille moyenne (15–60 développeurs FE) Trois à huit squads, qui commencent à ressentir la contention de déploiement et la friction de propriété. Peut-être, aux coutures. Envisagez d'extraire uniquement les frontières à friction la plus élevée — ex. une caisse, un tableau de bord de reporting — plutôt que de tout diviser. Un monorepo avec mise en cache du build peut le résoudre d'abord. E-commerce scale-up : monorepo pour la plupart des fonctionnalités, un remote Module Federation uniquement pour le flux de paiement (équipe isolée PCI, déploiement séparé).
Grande / enterprise (60+ développeurs FE) Plusieurs squads, souvent sur plusieurs fuseaux horaires, avec des frontières de propriété d'équipe strictes et des roadmaps séparées. Souvent justifié. La surcharge de coordination d'un déploiement partagé est réelle et mesurable. Module Federation ou composition côté serveur avec une équipe plateforme mature est un investissement judicieux. Grandes banques, opérateurs télécom, retail mondial : app shell appartenant à une équipe plateforme ; des dizaines de micro-frontends appartenant à des tribus de fonctionnalités, chacune avec son propre pipeline CD et son contrat de version.

Le blog d'ingénierie de Spotify a documenté leur « modèle de squad » et les décisions d'architecture frontend qui en ont découlé. Zalando a écrit ouvertement sur son approche de composition côté serveur Tailor. Les équipes de la plateforme numérique d'IKEA ont discuté de Module Federation à grande échelle. Ce que ces entreprises ont en commun, ce n'est pas la technologie — c'est l'échelle : de nombreuses équipes autonomes avec des roadmaps réellement indépendantes qui, autrement, se bloqueraient mutuellement quotidiennement.

À l'autre bout du spectre, certaines des organisations frontend les plus productives que j'ai vues dans la tranche 20–50 développeurs font tout tourner dans un seul monorepo Nx avec des frontières de modules strictement imposées et un CI incrémental rapide. Elles obtiennent des builds rapides, une propriété claire et zéro bug de composition à l'exécution — parce qu'il n'y a pas de composition à l'exécution. Elles réévaluent la question des micro-frontends tous les six mois à mesure que l'entreprise grandit, et c'est exactement ce qu'il faut faire.

Points clés à retenir

  • Les Micro-Frontends appliquent l'idée de décomposition des microservices à l'UI : des tranches frontend constructibles et déployables indépendamment, chacune appartenant à une seule équipe, composées à l'exécution (ou au build, ou côté serveur) en un seul produit.
  • Module Federation (Webpack 5 / Rspack / Vite) est l'approche d'exécution dominante — il fournit une vraie indépendance de déploiement mais nécessite une configuration soignée des dépendances partagées et une gestion des contrats de version.
  • Les bénéfices principaux sont l'indépendance de déploiement, l'autonomie des équipes, la migration incrémentale de framework et l'isolation des pannes. Si vous n'en avez pas réellement besoin à grande échelle, vous payez le coût sans la récompense.
  • Les vrais coûts sont la duplication du bundle, la gouvernance du système de design partagé, la complexité de l'état inter-MFE, le décalage de versions, la latence à l'exécution et une surcharge DevOps plus lourde. Aucun n'est fatal — mais tous nécessitent un investissement actif.
  • N'utilisez pas les micro-frontends si vous avez une petite équipe, une petite app, ou si un monorepo bien structuré résoudrait la friction réelle. Le monolithe modulaire est sous-estimé.
  • Adaptez l'architecture à la topologie de l'équipe : petites équipes → monolithe modulaire ; taille moyenne → monorepo ou divisions MFE chirurgicales ; grande entreprise → plateforme micro-frontend complète avec une équipe plateforme dédiée.
  • La complexité va toujours quelque part. Les micro-frontends la déplacent du code source vers les contrats d'intégration et l'infrastructure opérationnelle. Assurez-vous que votre organisation est prête à prendre en charge ce changement avant de vous engager.

Cet article fait partie d'une série sur l'architecture frontend et backend. Si vous êtes arrivé ici en premier, je vous encourage à revenir au début de la série — Ports & Adapters — qui couvre le pattern d'architecture hexagonale et comment garder votre logique métier centrale propre et testable, quel que soit le framework ou le mécanisme de livraison qui l'entoure. Les idées se complètent : la même pensée qui place des frontières claires à l'intérieur d'un seul service backend s'applique, à un grain plus large, aux frontières entre les équipes frontend. D'autres écrits sur l'architecture sont à venir — revenez bientôt, et j'espère vous y retrouver.