Apprenez comment fonctionne les NgModules
Un gros travail d’ingénierie a été effectué par l’équipe de Google pour développer le système de NgModule propre à Angular. Ce système a été assez critiqué au début de l’existence du framework car c’est vrai qu’il est assez complexe. En effet de nombreux débutants en Angular ont été repoussé par la complexité de ces modules Angular. C’est pourquoi plus tard Angular a choisi de légèrement simplifier via les services providedIn 'root' par défaut et ainsi éviter des erreurs plus ou moins grave de configuration du cycle de vie des services. Finalement avec l’apparition des Standalone Components en version 14 de Angular, les NgModules sont devenus optionnels et ainsi la majorité des nouveaux projets vont être développés sans NgModules cependant tous les projets commencés avant la version 14 vont surement garder des traces du passé même si l’équipe Angular fournit des méthodes de migration automatisées. Si vous travaillez sur un projet avec NgModules n’ayez pas peur, le système de module est très bien conçu et avec un minimum d’apprentissage que nous allons voir ensemble il devient agréable à les utiliser.
Types de modules
- App module : c'est le module racine utilisé pour amorcer l'application. Il ne devrait pas y avoir beaucoup de contenu car la majeure partie de la base de code doit être encapsulée dans le Core module et ensuite dans des modules spécifiques au domaine appelés features modules.
- Core module : composants au niveau de l'application tels que les services de header, de footer, de fil d'Ariane, de navigation et de singleton. Ce module doit être importé une fois dans le module d'application et le module ne doit rien exporter car seul le shell utilise ces composants.
- Shared module : les composants partagés, les directives et les pipes utilisés dans l'application doivent être à l'intérieur de ce module et exportés pour pouvoir être utilisés par d'autres modules qui l'importent. Il est courant d'importer et d'exporter des modules construits de Angular, par exemple le module Common ou un module Material à l'intérieur de votre module partagé si vous avez vraiment besoin d'y accéder à plusieurs endroits, comme dans de nombreux features modules. Afin d'optimiser au mieux votre application, ce module ne doit pas être importé dans les modules App ou Core, comme cela, il sera chargé de manière lazy une fois que l'utilisateur commencera à utiliser le premier feature module chargé en lazy lui aussi. Voir ci-dessous un module partagé vs plusieurs modules partagés. Et parce que vos modules partagés seront importés par de nombreuses fonctionnalités chargées en lazy, ils ne doivent contenir que des déclarables et des modules qui ne contiennent que des déclarables et ne doivent jamais implémenter de services via le providers array, sinon vous aurez des problèmes avec les singletons.
- Feature module : diviser les éléments en modules lazy spécifiques au domaine aidera à fonctionner à long terme. Ces modules doivent être isolés et n'exporter rien d'autre que le module lui-même pour effectuer le lazyloading.
Modules lazy
Développer une application Angular en ayant compris le concept de lazy modules est important, en effet les avantages d’utiliser ce pattern apporte de nombreux avantages.
- Temps de démarrage de l'application plus rapide, en effet, si vous divisez votre application en plusieurs modules de fonctionnalités à chargement lazy, le main bundle restera petit et votre application sera donc rapide à charger et à démarrer.
- Builds plus rapides en mode dev, en effet pendant le développement c'est aussi plus rapide puisque le compilateur n'a qu'à reconstruire les modules lazy affectés par vos modifications et non toute l'application.
- L'isolation des fonctionnalités aide la maintenabilité de votre application et garantit également une meilleure scalabilité, car votre code est plus facile à comprendre et à utiliser.
Un module Shared
- Si nous mettons tous les pipes, directives et composants communs partagés dans un gros module Shared, puis l'importons partout (à l'intérieur des modules synchrone et asynchrone), alors ce code se retrouvera apres la compilation dans notre bundle principal initial. Donc ce n'est pas la méthode recommandée surtout si votre module Shared contient beaucoup de choses.
Plusieurs modules Shared
- D'un autre côté, si nous divisons le code couramment utilisé entre des modules chargés en lazy, un nouveau chunk partagé sera créé et ne sera chargé que si l'un de ces modules lazy est chargé. Cela devrait améliorer le temps de chargement initial de l'application. Mais faites-le judicieusement, car il est parfois préférable de mettre des petites directives dans un seul chunk plutôt que d'avoir la requête supplémentaire nécessaire pour un chargement de chunk séparé minuscule.
Configuration du module
Declarations
Le array des declarations ne prend que les déclarables. Les déclarables sont des composants, des directives et des pipes. Les déclarables doivent appartenir à exactement un module sinon le compilateur émet une erreur. Les déclarables sont privés par défaut, ils ne peuvent donc être utilisés que dans le template de tout composant faisant partie de ce même NgModule. Si vous souhaitez l'utiliser en dehors, vous devez utiliser le array d'exports. Les pipes sont un cas particulier, ils doivent également être ajouté au array des providers si vous utilisez la fonction de transformation dans un template de composant ou si vous souhaitez l'utiliser via un constructeur. Vous pouvez également fourir votre pipe localement au composant ou bien utiliser le providedIn 'root' si vous souhaitez le partager globalement comme singleton.
Imports
Autres modules dont les declarables exportées sont nécessaires aux templates de composants déclarés dans ce NgModule. Fondamentalement, c'est utile pour utiliser des déclarables qui sont exportés dans d'autres modules. Par exemple, si ModuleA importe ModuleB, alors ModuleA sera autorisé à utiliser n'importe quel déclarable exporté par ModuleB.
Exports
Le sous-ensemble de déclarations qui doit être visible et utilisable dans les templates de composants d'autres NgModules. Cela signifie qu'un template externe à ce module peut utiliser des déclarables exportés à partir de n'importe quel Module importé. Par exemple, si vous souhaitez utiliser dans votre template d'application un composant modal déclaré dans un Module modal, ce composant modal doit d'abord être déclaré et exporté dans votre Module modal et, bien sûr, le Module modal doit être importé dans votre Module d'application. Un autre cas plus complexe est également celui des principes d'exportation indirecte rendus possibles par l'exportation d'un Module entier au lieu d'un seul déclarable. En effet, si ModuleA importe ModuleB, et l'exporte également, cela rend les déclarables de ModuleB disponibles partout où ModuleA est importé.
Providers
Le tableau des providers fait partie de l'injection de dépendances, vous en apprendrez plus sur cette partie dans ce cours d'injection de dépendances.