L'architecture du projet se découpe en deux grandes catégories :
- L'application en elle-même ;
- Des bibliothèques génériques (qui pourraient, en principe, être publiées sur npm).
Concentrons-nous sur l'application. Elle se découpe en trois modules principaux et un sous-module :
commonfeaturefeature/shared(le sous-module)core
Cette organisation vise plusieurs objectifs :
- Éviter les dépendances circulaires.
- Respecter au mieux l'isolation des modules.
- Rendre chaque feature indépendante, facilitant ainsi l'évolution et la maintenance.
- Simplifier les tests unitaires et d'intégration.
Son contenu se trouve dans le dossier common/ (accessible via import ... from '@<app>/common/...';).
Il s'agit en quelque sorte d'une "bibliothèque interne". Son contenu est potentiellement publiable, mais ne l'est pas pour deux raisons principales :
- Spécificité : Il est générique pour notre application, mais pas au point d'être applicable à n'importe quel projet.
- Contraintes techniques : Il peut contenir des éléments non compatibles avec une bibliothèque Angular standard (par exemple,
common/datesqui utilise le polyfillTemporal).
Le module common est organisé par thématiques, qu'elles soient ciblées (config, dates, forms, http, testing, etc.) ou transverses (components, layout, utils, etc.).
Son contenu se trouve dans le dossier feature/ (accessible via import ... from '@<app>/feature/...';).
Idéalement, tout ce qui n'est pas common devrait se trouver ici. Il s'agit du code métier de l'application. On y trouve une arborescence logique :
- Des fonctionnalités découpées par pages.
- Des blocs qui composent ces pages.
- Des sous-blocs qui composent d'autres blocs.
- etc.
Note 1 :
featurepeut dépendre decommon(mais l'inverse est interdit).
Note 2 : Si nécessaire, chaque fonctionnalité (ou sous-fonctionnalité) est responsable de définir ses propres routes et ses stores pour la gestion de ses états.
Son contenu se trouve dans le dossier feature/shared/ (accessible via import ... from '@<app>/feature/shared/...';).
Une "feature partagée" est, comme son nom l'indique, une fonctionnalité (un bloc, un composant, un service, etc.) partagée entre plusieurs features distinctes.
Note 1 : Il n'est pas toujours nécessaire de déplacer des sous-features dans
feature/shared: si un bloc est partagé au sein d'une même feature, il suffit de le remonter dans l'arborescence de celle-ci. Par exemple, si un sous-blocfeature/A/block-1/sub-block-1est aussi utilisé parfeature/A/block-2, on peut le déplacer versfeature/A/sub-block-1.
Note 2 :
feature/sharedpeut dépendre decommon,coreet également d'autres modules defeature/shared(il faut veiller à ne pas créer de dépendances circulaires dans ce cas). Si nécessaire, un module defeature/sharedpeut être scindé en plusieurs modules plus granulaires.
Son contenu se trouve dans le dossier core/ (accessible via import ... from '@<app>/core/...';).
Toutes les fonctionnalités nécessaires au bon fonctionnement de l'application ne sont pas forcément liées au métier ; certaines sont purement techniques.
Ces fonctionnalités techniques pourraient se trouver dans feature, mais pour alléger ce dernier et clarifier les intentions, elles sont isolées dans core. On y trouve par exemple les modules auth ou mercure (pour la gestion de nos Server-Sent Events).
Note 1 : Si une fonctionnalité initialement dans
feature/shareds'avère nécessaire pour un module decore, elle doit être "promue" et déplacée danscorepour respecter le flux des dépendances.
Note 2 :
corepeut uniquement dépendre decommon.
En plus de ces quatre modules applicatifs, nous utilisons des bibliothèques de code générique qui, contrairement à common, ont vocation à être totalement agnostiques du projet.
On en distingue principalement deux :
angular-extension: Contient du code étendant les fonctionnalités natives d'Angular. La bibliothèque est organisée en suivant la structure d'Angular (common,core, etc.) et ses points d'entrée sont accessibles via@angular-extension/common,@angular-extension/core/rxjs-interop, etc.ui: Regroupe l'ensemble des composants génériques et purement visuels, sans aucune logique métier (ex: Skeleton, Popover). Chaque composant est accessible via son propre point d'entrée :@ui/skeleton,@ui/popover, etc.
Note :
angular-extensionest complètement indépendante.uipeut dépendre d'angular-extension. Tous les modules de l'application (common,feature,feature/shared,core) peuvent dépendre de ces bibliothèques.
La flèche
A -> Bsignifie "A importe B" (A dépend de B).
| Module / Bibliothèque | Rôle Principal | Contenu Typique | Dépendances Autorisées (importe...) | Utilisé Par (... est importé par) |
|---|---|---|---|---|
feature |
Logique métier spécifique | Pages, composants métier, stores et routes propres à une fonctionnalité. | feature/shared, core, common, ui, angular-extension |
(Application finale) |
feature/shared |
Logique métier partagée | Composants et services métier réutilisés par plusieurs features (ex: Address, Status, etc.). | core, common, ui, angular-extension |
feature |
core |
Logique technique transverse | Services essentiels et uniques (Auth, Intercepteurs HTTP, SSE), configuration de l'application. | common, ui, angular-extension |
feature, feature/shared |
common |
Boîte à outils de l'application | Code générique et réutilisable non-métier (Pipes, directives, validateurs, helpers de layout). | ui, angular-extension |
feature, feature/shared, core |
ui |
Design System | Composants visuels génériques et agnostiques du métier (Button, Popover, Skeleton). | angular-extension |
Tous les modules de l'application |
angular-extension |
Utilitaires Angular | Fonctions et helpers de bas niveau pour étendre Angular (helpers RxJS, interop, etc.). | (Dépendances externes uniquement) | Tous les modules et la bibliothèque ui |