Au cours des dernières années, la communauté front-end a activement discuté et utilisé le terme "micro-frontend" (ci-après dénommé MF). Différentes entreprises partagent leurs approches pour organiser une telle solution architecturale , mais jusqu'à présent, il existe peu de description des problèmes que les MF sont conçus pour résoudre sur le Web, des critères de leur applicabilité et des limites d'utilisation.
Dans cet article, j'ai essayé de comparer différentes manières d'organiser les MF, ainsi que de formuler des recommandations sur où utiliser quelle approche.
L'article peut être utile à la fois aux analystes et aux équipes de développement lors de la conception de l'architecture d'un projet et de la mise en place des processus, ainsi qu'aux propriétaires de produits, car l'introduction des MF peut fournir un développement plus gérable.
Avant de passer à la définition de MF, regardons quelques problèmes qui peuvent être rencontrés dans les projets :
Vous avez un gros projet . La taille d'un projet est généralement subjective et peut être déterminée empiriquement par la quantité de fonctionnalités et le nombre de développeurs. Si vous avez assez de travail pour embrouiller 1-2 front-ends et en même temps ils ne "poussent pas leurs coudes" - c'est un petit projet, 3-6 est moyen, et plus que 6-8 est déjà un gros .
Vous avez une grosse équipe . Encore une fois, empiriquement, cela fait plus de 10 front-enders, le reste des participants ne compte pas. En règle générale, une équipe de cette taille peut déjà être divisée en sous-équipes qui prennent en charge des fonctionnalités spécifiques pour le support et acquièrent leurs propres analystes, backenders et QA.
Vous avez une grande fonctionnalité. Un seul développeur ne peut maintenir qu'un morceau de code pour sa sous-équipe. Affiner le reste du code peut être coûteux en raison de l'ignorance du domaine ou de la complexité de la mise en œuvre d'une logique tierce.
le désir de changer la pile;
une exigence de l'entreprise pour soutenir une famille de projets connexes.
Comment pouvez-vous organiser des relations entre tant de personnes ? Comment pouvez-vous construire des processus sur un projet de cette envergure ? Comment pouvez-vous délimiter correctement les domaines de responsabilité ? Plus vous avez collecté de problèmes, plus il est intéressant d'envisager l'introduction d'une approche micro-frontale. Puisqu'il s'agit d'une continuation naturelle de la tendance évolutive du développement vers la décomposition du code et de l'équipe projet.
Ainsi, l'approche MF est la division d'un front monolithique en bases de code distinctes stockées dans des référentiels distincts, auxquels des sous-équipes distinctes ont accès. En même temps, ils peuvent/devraient avoir leurs propres stands de démonstration, tests et cycles de publication. En conséquence, le microfront est une pièce détachable de l'interface. Il n'est pas nécessaire de diviser par page, la fonctionnalité peut être de bout en bout (par exemple, kit d'interface utilisateur d'entreprise).
Séparément, il convient de souligner que les MF sont davantage une décision organisationnelle sur la manière de gérer la complexité du développement dans un grand projet. Les MF ne vous aideront pas à accélérer le frontend, certaines implémentations, au contraire, le ralentiront même. Mais cette approche accélérera le développement lui-même en raison de l'attribution de domaines de responsabilité et de tests isolés.
À l'inverse, il convient de mentionner le chargement paresseux par rapport aux MF. Ils résolvent différents problèmes, mais parfois les gens pensent qu'il ne s'agit que d'une seule chose, car dans les deux cas, nous "divisons" l'application.
Le chargement paresseux résout le problème de performances : comment ne pas forcer l'utilisateur à charger l'intégralité du bundle frontal, comment ne pas attendre plus longtemps que nécessaire et comment lancer le front sur le client plus rapidement et commencer à interagir avec lui plus tôt.
Les MF ne résolvent pas le problème de performances, et parfois même l'exacerbent. Mais ils aident à organiser le développement d'une manière plus confortable pour une sous-équipe particulière, minimisant les problèmes ci-dessus.
Parlons maintenant de l'approche consistant à combiner les MF en une seule application. Quoi que vous choisissiez, cela devrait ressembler à une application unique pour l'utilisateur. Vous pouvez fusionner à la fois au stade de l'assemblage et de manière dynamique - lors de l'exécution du code du côté de l'utilisateur.
Ainsi, toutes les façons d'organiser les MF peuvent être attribuées au temps de construction ou d'exécution. Chacun a ses avantages et ses inconvénients.
| Temps de construction | Durée |
---|---|---|
Vérification de type | + | - |
Gestion des versions | + | pas de sens |
Déploiement indépendant | - | + |
La vérification de type joue un rôle important dans le développement moderne. Lorsqu'il est géré par des sous-équipes distinctes et indépendantes, il devient une nécessité. Comment assurer la cohérence des MF, qu'ils utilisent correctement et transmettent les données dans le bon format, etc.
En fusionnant les microfronts au moment de la construction, vous n'êtes pas privé de la possibilité de vérifier les types. Dans le cas d'un runtime union, il faudra écrire des tests d'intégration pour que le front n'« explose » pas brutalement sur la production.
Le versioning et le déploiement indépendant sont très contradictoires :
La gestion des versions signifie que vous pouvez prendre n'importe quelle version du MF de l'autre équipe. Cela est particulièrement vrai lorsque vous devez effectuer des travaux supplémentaires pour mettre à niveau les dépendances du MF-a par rapport aux autres. Chaque équipe choisit un meilleur moment pour se mettre à niveau.
Le déploiement indépendant donne plus d'autonomie et d'indépendance aux équipes. Il est important de toujours utiliser les dernières versions des MF. Cela nécessite une rétrocompatibilité.
La gestion des versions peut également être implémentée avec la fusion d'exécution, mais ce n'est pas pratique. Il est logique de contacter le runtime uniquement pour des raisons de déploiement indépendant, et ce dernier ne peut pas exister avec la gestion des versions.
Ensuite, nous verrons des exemples d'implémentations spécifiques de chaque approche de combinaison de MF.
La plus ancienne façon d'organiser les MF. iframe est une balise spéciale pour transmettre l'adresse d'une ressource qui sera affichée sur le site principal. Le résultat est un site dans un site.
Parmi les avantages , il convient de noter la facilité de mise en œuvre, l'isolement complet de la logique et des styles, la possibilité d'effectuer un déploiement indépendant et l'absence de liaison aux frameworks.
Ces avantages ont un coût en termes de performances, car chaque insertion d'un iframe entraîne une charge de ressources. Vous ne pouvez pas éviter cela : les tentatives de débogage et de rattachement d'un nœud DOM n'enregistreront pas les ressources précédemment chargées, vous devrez les retélécharger. Vous pouvez minimiser la dégradation des performances en configurant la mise en cache.
Pour ce faire, vous devez configurer l'invalidation du cache basée sur le temps pour les ressources immuables. Heureusement, tous les cli modernes prêts à l'emploi pour les fichiers js et css collectés attachent un petit hachage au nom. Les inconvénients de cette méthode incluent l'incapacité des robots de recherche à rendre les iframes pour une indexation ultérieure.
Avantages | Les inconvénients |
---|---|
Mise en œuvre facile | Performance |
Isolement de la logique et des styles | référencement |
Déploiement indépendant | |
Cadre agnostique | |
La communauté front-end attend depuis longtemps la création de composants natifs, mais au final, ils n'ont jamais acquis la popularité de masse que beaucoup attendaient. Les trois frameworks frontaux les plus populaires (React, Vue, Angular) créent toujours des composants à leur manière.
Malgré la possibilité de créer des MF sur des composants Web, je n'ai pas vu cela dans la pratique. Et ce n'est pas un hasard, il existe un certain nombre de bloqueurs :
Soit libs Lit soit Stencil n'est pas assez populaire et pas assez commun. De plus, il n'y a pas assez de spécialistes sur le marché qui savent travailler avec eux ou qui sont prêts à apprendre.
Les éléments angulaires ou vue-custom-element restent exotiques. Dans un environnement natif, il n'y a pas grand intérêt à les utiliser. Si vous avez déjà divisé l'application, puis en packages npm ordinaires, afin que vous puissiez ensuite connecter les composants comme vous le souhaitez. L'utilisation de composants Web avec d'autres frameworks est déraisonnable car avec les composants générés, vous devez connecter une mini-version du framework sur lequel ils ont été écrits.
Il peut être coûteux de déplacer des fonctionnalités complexes dans des composants Web. Comme vous devrez configurer la communication de votre composant avec le reste de l'application, il n'est peut-être pas justifié de retirer une page entière dans un composant personnalisé séparé.
Les robots de recherche ne peuvent pas créer de composant Web, ce qui affectera l'optimisation du référencement.
Avantages | Les inconvénients |
---|---|
Convient aux fonctionnalités transversales | Difficile à mettre en œuvre |
Compatible avec n'importe quel framework | référencement |
Isolement de la logique et des styles | |
Développer avec des packages npm présente de nombreux avantages. Les développeurs importent simplement les composants et les fichiers dont ils ont besoin à partir de la bibliothèque lib. En même temps, le typage est conservé dans le projet, il y a le versioning. La construction est optimale : l'arborescence fonctionne (suppression du code inutilisé pendant la construction) et les développeurs peuvent facilement configurer le chargement paresseux.
Cependant, cette méthode a aussi ses inconvénients. Dans ce cas, vous serez obligé de maintenir l'unité de la pile, ainsi que de maintenir les versions de vos MF et leurs dépendances transitives. En revanche, cela peut être un plus : en publiant une nouvelle version du package, d'autres équipes peuvent se charger de remonter la version de leurs dépendances à un moment qui leur convient s'ils ont besoin d'introduire des fonctionnalités supplémentaires ou, à l'inverse , supprimer quelque chose.
Avantages | Les inconvénients |
---|---|
Performance | N'a pas de déploiement indépendant |
référencement | Pile unique |
Vérification de type | |
Gestion des versions | |
Comme alternative à MF sur les packages npm, considérez les sous-modules git. En fait, ce sont des référentiels au sein d'un référentiel, au sein duquel il peut également y avoir des référentiels. Vous pouvez définir différentes branches dans les sous-modules. Par exemple, les modules de fonctionnalités peuvent avoir une branche factice sans rien dedans. Cela est nécessaire pour que l'assemblage aille plus vite et que les autres modules ne créent pas d'effets secondaires. Les branches factices peuvent être très pratiques pour le développement et les tests locaux.
En termes d'avantages et d'inconvénients, cette approche est très proche des packages npm. Nous importons également simplement quelque chose, mais à partir d'un dossier voisin, et non à partir d'un package, et l'utilisons.
Voyons les différences entre les deux méthodes :
Les packages NPM sont, en fait, un micro-produit fini et modérément isolé avec ses propres versions et versions. Tout est axé sur la création de fonctionnalités réutilisables. Mais l'application peut être complexe/alambiquée et puante, il peut donc être assez coûteux d'emballer un grand monolithe. C'est là qu'il serait raisonnable d'envisager des sous-modules car ils vous permettent de couper le référentiel très grossièrement lorsque nous déplaçons le dossier vers un référentiel séparé sans aucune préparation supplémentaire.
Les packages NPM peuvent être imbriqués de manière récursive. Les sous-modules aussi, mais au niveau de l'assemblage, ils peuvent commencer à dupliquer des fonctionnalités si l'un des sous-modules est inclus plusieurs fois dans différents dossiers en tant que sous-module séparé. Dans ce cas, il vaut la peine d'utiliser une structure de module plus plate.
Si vous avez besoin de déployer rapidement une fonctionnalité dans tous les packages à la fois, le développement inter-packages peut être extrêmement gênant. Bien que tout reste le même sur les sous-modules, vous pouvez apporter des modifications qui affectent d'autres sous-modules. Dans ce cas, il est facile de déboguer. Mais au final, vous ne fusionnerez pas les modifications elles-mêmes - au niveau de la demande de fusion, une équipe tierce dont vous avez touché le module peut vous demander de mettre le code en conformité avec ses règles.
npm | sous-modules git |
---|---|
Réutilisabilité | Découpe grossière de la fonctionnalité |
Dépendances imbriquées arbitrairement | Structure plate |
Développement multiplateforme | Développement avec n'importe quel nombre de modules |
single-spa est essentiellement un cadre qui combine d'autres cadres. Une technologie incroyablement puissante, qui cache un grand nombre de nuances, fait l'objet d'un article séparé.
Le schéma est similaire à iframe, mais le chargement du MF se fait désormais via import + importmap natif ou via Systemjs si des polyfills sont nécessaires.
Contrairement à toutes les méthodes d'organisation des MF, celle-ci est hautement adaptée pour combiner différents cadres sous elle-même. Mais il convient de mettre en garde contre l'utilisation de la technologie pour la technologie elle-même. S'il est possible de se débrouiller avec une seule pile, vous devez l'utiliser. Le développement peut être à jamais chargé de maintenir un projet techniquement complexe et de corriger les bogues des effets secondaires de différentes applications. L'utilisateur peut ressentir une gêne, car. la quantité de code à télécharger sur le client sera augmentée (les cœurs des différents frameworks pour les différentes fonctionnalités + le cœur du spa unique lui-même et ses plugins).
Avantages | Les inconvénients |
---|---|
Déploiement indépendant | Documentation volumineuse, qui ne couvre pas encore tous les cas |
Cadre agnostique | Difficultés avec le référencement |
Interface de ligne de commande puissante | |
Un plugin webpack 5 qui a été développé spécifiquement pour créer des MF. Technologie prometteuse : un petit plug-in de construction pour un regroupement plus correct et des importations dynamiques au moment de l'exécution.
Le schéma se répète presque individuellement sur un seul spa, mais maintenant les importations dynamiques sont utilisées pour charger les MF
Avantages | Les inconvénients |
---|---|
Déploiement indépendant | niveau faible |
Réalisation facile | |
Compatible avec SSR | |
Voyons ce qui peut être appliqué et pour quoi :
iframe - un seul insert pour une combinaison incongrue
composants Web - lorsque vous avez besoin d'une petite fonctionnalité de bout en bout sans être lié à un cadre, comme un kit d'interface utilisateur d'entreprise
packages npm - s'il existe une possibilité de réutilisation entre les projets et/ou si vous avez besoin d'une vérification de type au moment de la construction
sous-modules git - lorsque vous devez découper grossièrement un projet et répartir les domaines de responsabilité
spa unique - lorsqu'il y a un fort besoin de combiner plusieurs cadres indéfiniment, de préférence sans SSR
module-federation - tous les autres scénarios d'utilisation des MF, sous réserve de l'unité de la pile.
Chaque approche est bonne à sa manière et chaque chose doit avoir sa place. Avant de passer aux MF, nous vous conseillons de vous demander si vous en avez vraiment besoin. Quelle que soit l'approche choisie, cela compliquera forcément quelque chose au niveau du développement, du CI/CD ou de la performance. S'il existe des opportunités de rester sur une pile unique et une application monolithique, acceptez volontiers cette opportunité.
Et, bien sûr, n'oubliez pas les utilisateurs . En fin de compte, ils téléchargent tous les frameworks connectés et subissent d'éventuels bugs dus à une intégration incorrecte des MF dans différentes fonctionnalités. Les entreprises, à leur tour, devront payer pour la mise en œuvre et le soutien de tout cela.