66 votes

Dois-je créer un module par composant dans une application Angular 4+ ?

Nous avons une application Angular 4 de taille moyenne (+-150 composants).

Nombre de ces composants nécessitent l'injection de classes de service et la déclaration d'autres composants dans l'application.

Une approche que nous avons expérimentée et que nous avons trouvée beaucoup plus conviviale pour les développeurs consiste à créer un module par composant. Le module importe les modules des composants enfants et fournit (ou importe) tous les services nécessaires au composant. Il exporte également le composant lui-même afin que les autres composants puissent y faire référence par l'intermédiaire du module.

La composition des composants est un jeu d'enfant et la mise en place du dispositif de test d'un composant est très simple (c'est là qu'il y avait auparavant beaucoup de répétitions de dépendances et de dépendances de l'arbre des composants enfants).
Cette approche semble correspondre à l'architecture basée sur les composants et permet une forme d'encapsulation autour des dépendances d'un composant.
C'est trop beau pour être vrai ;)

Ma question est la suivante : quel est l'impact sur les performances (ou autre) de la présence d'un si grand nombre de modules ?

2 votes

Merci pour vos réflexions. Cette approche a permis de réduire considérablement le temps d'exécution de nos tests. Nous sommes passés de 2 minutes 30 secondes pour 700 tests à 5 secondes. Beaucoup moins de travail pour les développeurs ;-) Hmmm... je ne sais pas trop pourquoi ma question a été rétrogradée. Peut-être est-ce un signe que d'autres pensent que c'est une mauvaise idée.

3 votes

Je pense en fait que c'est la meilleure façon de procéder, un seul module inclut les composants parent et enfant, rappelez-vous quand angular était en version bêta, nous ne pouvions pas faire cela... et nous avions un seul module pour les applications énormes, c'était

0 votes

@AngularInDepth.com : Si vous développez une bibliothèque, avoir un module par composant est souvent la meilleure solution. Pourriez-vous expliquer un peu plus en détail pourquoi ?

66voto

Lucas Basquerotto Points 1040

Je considère un module par composant la meilleure façon de concevoir vos applications Angular.

S'il dépend d'autres composants, vous pouvez n'inclure que l'élément modules de composants lié à chaque composant qui est un dépendance directe et n'ont pas besoin de se préoccuper des dépendances indirectes.

Cela peut sembler plus laborieux au début, mais vous serez récompensé par une réduction des problèmes d'entretien.

Si ComponentA dépend de ComponentB qui dépend de ComponentC créer un :

ModuleC en rapport avec ComponentC

ModuleB en rapport avec ComponentB qui importe ModuleC

ModuleA en rapport avec ComponentA qui importe ModuleB (il n'est pas nécessaire d'importer directement ModuleC )

Si ComponentB dépend désormais de ComponentD (comme l'inclusion de <my-component-d> dans le modèle) et cesse de dépendre de ComponentC vous changez simplement ModuleB et tous les composants qui dépendent de ComponentB fonctionnera parfaitement si vous utilisez cette approche.

Pensez maintenant à des centaines de composants. Le nombre de composants dépendra ComponentB ?

Je considère que ce problème est similaire à l'ancienne façon (ou pas trop ancienne) d'inclure des fichiers js dans les balises script :

<script src="build/a.js"></script>
<script src="build/b.js"></script>
<script src="build/c.js"></script>

Et si vous changez b de ne plus dépendre de c et démarre en fonction de d toutes les pages qui importent b doivent maintenant importer d et ainsi de suite, ce qui conduit à un cauchemar en matière de maintenance. Vous pouvez également oublier de supprimer (le désormais inutile) c.js et l'importe inutilement dans certaines pages, augmentant ainsi le temps de démarrage ( ou pire vous le supprimez de tous les fichiers qui importent des b.js mais certaines importations de pages e.js qui dépend de c.js et vous interrompez certaines fonctionnalités de cette page).

Je considère au contraire qu'il est préférable d'importer :

<script src="build/bundle.js"></script>

ou

<script src="build/vendor.js"></script>
<script src="build/main.js"></script>

et les dépendances sont gérées par un module bundler, comme webpack .

Il existe une approche qui consiste à créer un module avec de nombreux composants et à l'importer, mais vous finissez par importer plusieurs composants. que vous n'utilisez pas et si vous utilisez le chargement paresseux, vos modules peuvent devenir énormes à moins que vous n'importiez ce module dans AppModule, ce qui rendrait votre augmentation du temps de démarrage .

Vous pouvez toujours utiliser l'approche d'un composant par module avec des modules de fonctionnalités . Il suffit d'importer le module de composants dans le module de fonctionnalité (au lieu du composant lui-même) :

feature.module.ts :

imports: [
    ComponentAModule,
    ComponentBModule,
    ComponentCModule,
]

(Vous pouvez également les exporter).

Je considère également que cette approche est la meilleure pour la création de bibliothèques. forcer les consommateurs de la bibliothèque pour importer tous les composants même s'ils n'utilisent qu'un ou deux éléments de la bibliothèque.

Je rencontre ce problème avec ionic3 : la version minifiée ionic-angular La bibliothèque a 437KB dont 292KB sont les composants (il est à espérer que cela changera avec ionic4 ). Je n'en utilise que quelques-uns ionic il n'était pas nécessaire de les importer tous, mais je n'ai pas le choix (à moins que je ne fork le repo ou que je ne l'utilise plus).

J'ai une application avec 176 composants et c'était la meilleure approche à mon avis. Auparavant, j'incluais plusieurs composants dans un module de fonctionnalité et cela m'a causé quelques maux de tête par la suite. De plus, il était plus difficile de changer un composant d'un module de fonctionnalité à un autre ( Qu'en est-il de ses dépendances ? Elles ont toutes été mélangées ).

Je n'ai pas trouvé d'approche satisfaisante avec les services ( @Injectable() ).

En fin de compte, c'est à vous de décider. Ceci est mon opinion basée sur mon expérience.

3 votes

Merci pour votre réponse Lucas. Bien que cette question dépende énormément de l'opinion des gens sur la structuration de leur application en fonction de leur contexte, je pense que c'est une très bonne façon de procéder. Ayant adopté cette approche dans mon application, j'ai expérimenté tous les avantages que vous avez mentionnés. La petite quantité de travail que représente la création d'un module par composant améliore définitivement la maintenabilité et la composabilité de l'application. Apparemment, la construction du module disparaît lors de la compilation, de sorte qu'elle n'ajoute même pas de frais généraux. Je vous remercie pour votre réponse.

0 votes

@MarkWhitfeld Oui ! Dans mon cas, le plus gros problème a été le passage initial des modules monolitiques avec plusieurs composants à un module par composant, mais maintenant je n'ai besoin de créer de nouveaux modules que lorsque je crée de nouveaux composants, et le temps nécessaire à la création du module est certainement beaucoup moins long que celui nécessaire à la création du composant lui-même (avec la logique et le modèle), donc je considère la création du module comme faisant partie de la création du composant, et maintenant il est beaucoup plus facile de changer les dépendances entre les composants et de supprimer ceux qui ne sont pas utilisés.

1 votes

Utilisez-vous un module par @Pipe ?

2voto

Sammaye Points 21778

J'aimerais ajouter une réponse, car cela apparaît comme le premier résultat pour moi sur Google et j'ai l'impression d'avoir quelque chose à transmettre aux autres après avoir cherché sans relâche.

J'ai une application dans laquelle toutes les zones, sauf une, sont écrites sous forme de module par écran, ce qui n'est pas tout à fait un composant, mais presque.

J'ai récemment voulu savoir si les modules chargés paresseusement étaient vraiment utiles.

Chargement paresseux

Moot. La plupart des applications Angular, même lorsque cette question est posée, utilisent PWA ou pre-fetching pour s'assurer que l'utilisateur obtient le maximum de l'application dès que possible et que son expérience n'est pas interrompue par des paquets cassés à cause des mises à jour de la source de livraison, c'est-à-dire un seau S3 proxié via CloudFront.

De plus, le lazy loading est totalement inexistant si vous n'utilisez pas la fonction import(). Ainsi, le simple fait d'utiliser la propriété import dans un autre module pour importer d'autres modules ne permet pas de les charger paresseusement.

Taille de l'offre

Les modules coûtent en moyenne 8 ko après la compilation et j'ai calculé qu'avec 27 modules, mon application peut utiliser jusqu'à 556 ko rien que pour maintenir ce mode de codage.

Temps de téléchargement

Encore une fois, non. Module chargé paresseusement = bundle et bundle = thread pour télécharger le bundle. En réalité, vous voulez quelque chose où le code est réparti uniformément mais où les fichiers ne sont pas trop gros, maximum 600kb chacun, ce qui serait facilement téléchargeable sur des connexions 3G lentes.

Temps de rendu

Cela dépend fortement de l'appareil de l'utilisateur, je n'ai pas de test solide à ce sujet, mais même votre téléphone mobile moyen peut facilement gérer une application de grande taille, donc il peut probablement gérer votre application si elle est inférieure à 100 composants par paquet.

N'oubliez pas non plus qu'un module EST dans le fichier, qu'il sera transcodé par le moteur JS et qu'il ajoutera du poids à votre application.

J'ai en fait fait un test de 10 (oui, ce n'est pas très fiable mais c'est juste un test rapide) requêtes d'un navigateur vers deux versions de l'application, l'une avec des changements pour ajouter des modules paresseux à la dernière partie de l'application et l'autre sans (aucun changement) et j'ai trouvé que la version avec des changements retournait plus lentement que la version sans changements. En moyenne, les deux versions étaient proches l'une de l'autre, mais celle qui comportait le plus de modules paresseux revenait un peu plus souvent plus lente.

SOC

Oui, mais cela dépend de ce que ressent le développeur, certains aiment les SCAM, d'autres les paradigmes fous que personne d'autre ne comprend. Quoi qu'il en soit, SOC peut être facilement réalisé en séparant les composants en modules au lieu d'imbriquer sans fin des dossiers et de cliquer sur les inclusions des modules.

Conclusion

Il faut prendre ses propres décisions et les évaluer en fonction de l'impact sur l'utilisateur.

La meilleure solution consiste peut-être à trouver un juste milieu entre l'organisation et la performance.

Angular prend désormais en charge les composants autonomes. https://angular.io/guide/standalone-components et bientôt les nouvelles applications Angular seront codées sans l'utilisation de modules.

0voto

Matrium Points 691

Le modèle SCAM (Single Component Angular Module) tel que recommandé par la réponse acceptée présente cependant un inconvénient/risque (en plus de la platitude) qu'il convient de prendre en compte :

Vous créez en fait un énorme graphe de dépendance de tous vos composants et, comme vous n'avez besoin que d'importer des directement (plutôt que tous les modules utilisés de manière transitoire), il est très facile de perdre de vue ce qui se passe réellement lorsque vous importez un module. Qu'est-ce qui est exactement nécessaire pour faire fonctionner votre AppModule maintenant ? Pire : si quelqu'un importe plus tard quelque chose dans l'App-Module, il peut en fait importer de manière transitive un grand nombre de modules, ce qui peut augmenter considérablement votre budget de Première peinture de contenu y Le temps de l'interactivité .

Cela s'explique par le fait qu'avec le SCAM, on peut finir par ne plus savoir quelles sont les VRAIES dépendances d'un composant (toutes les dépendances transitives), parce qu'il y a tellement de modules. Ce n'est pas une exclusivité du SCAM (faites toujours très attention à ce que vous importez dans le module d'application), mais le SCAM l'aggrave imo, car il rend les dépendances difficiles à voir et à comprendre.

Je m'en tiendrais à la module par caractéristique en général, mais utiliser l'approche module par composant pour tous composants partagés . Il s'agit d'une solution un peu intermédiaire, mais qui pourrait constituer un bon équilibre. Il permet de contenir un peu la "folie des modules", tout en offrant les mêmes avantages que SCAM dans une certaine mesure. Cela fonctionne encore mieux avec les composants Angular 14+ Standalone - vous pouvez l'utiliser pour la plupart des composants partagés, tout en continuant à contrôler vos modules de fonctionnalités comme d'habitude.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X