Utilisez le plus que possible le ng CLI pour générer les fichiers souhaités
src-┐
assets-
styles-
index.html
main.ts
app-┐
moduleName-┐ // ng g module <name> [--route <routeName> --module <moduleTargeted>] [--routing]
[components] // ng g component moduleName/components/<name> --module <moduleTargeted>
[pages] // ng g component moduleName/pages/<name> --module <moduleTargeted> --type page
[models] // ng g class moduleName/models/<Name> || ng g enum types/<name>
[guards] // ng g guard moduleName/guards/<name>
![services]
![directives]
![pipes]
![moduleName]
[moduleName-routing.module.ts] // Créé par --routing
[moduleName.component.ts|html|scss|spec] // Créé par --routing
moduleName.module.ts
shared-┐ // ng g module shared
[components] // ng g component shared/components/<name> --module <moduleTargeted>
[directives] // ng g diretive shared/directives/<name> --module <moduleTargeted>
[pipes]-┐ // ng g pipe shared/pipes/<name> --module app
pipeName.pipe.ts|spec.ts
[models]
![moduleName]
shared.module.ts
interceptors-┐ // ng g interceptors interceptors/<name>
index.ts // The "barrel" file https://angular.io/guide/http#provide-the-interceptor
interceptorName.interceptor.ts|spec.ts
guards-┐ // ng g guards/<name>
guardName.guard.ts|spec.ts
resolvers-┐
resolverName.resolver.ts
services-┐ // ng g service services/<name>
serviceName.service.ts|spec.ts
models-┐ // ng g class models/<Name> || ng g enum types/<name>
Model.ts|spec.ts
enumName.enum.ts
[errors]
app-routing.module.ts
app.component.ts|html|scss|spec
app.module.ts
[]
: optionel
![]
: optionel, à utiliser avec précaution. Ne devrait pas servire dans la grande majorité des cas.
Un composants n'est jamais appelé par un router.
components-┐
componentName-┐
componentName.ts|html|scss|spec.ts
[components]
![models]
![services]
![directives]
![pipes]
Les pages sont des composants. On les différencie cependant par un point : elles ne sont appelées que par un router.
L'arborescence des pages doit représenter au mieux l'arborescence du routing.
exemple : URL /path/to/my-page
src/app/myModule/pages/path/pages/to/pages/myPage/myPage.component.ts|html
pages-┐
pageName-┐
componentName.ts|html|scss|spec.ts
[components]
[pages]
![models]
![services]
![directives]
![pipes]
On distingue deux types de modules.
- Les modules avec router, ils peuvent contenir des pages et des guards.
Ce sont les modules les plus fréquents. Votre découpage de modules doit s'axer sur vos fonctionnalitées. ex : shipping, builling, address book.
- Les modules sans router, ils ne peuvent pas contenir de pages ni de guards. Plus rare, ils se résument généralement à un module
shared
.
Le module shared
doit contenir tous les composants, directives et pipes génériques de l'application et de fait utiliser par plusieurs modules (mais pas forcèment tous).
Pourquoi ne pas inclure des services et des guards dans le module
shared
?Les services et les guards sont de facto par
@Injectable({ providedIn: 'root' })
partagés dans toute l'application.
Le module shared
ne doit pas être importé dans le appModule
il doit explicitement être importé dans les modules souhaités.
Sinon il perd de sont intérêt au profit de appModule
. Il faut développer le shared
module comme s'il était une librairie externe. Ses composants doivent être agnostiques à votre métié.
Le dossier services
à la racine contient tous les services de l'application avec les annotations @Injectable({ providedIn: 'root' })
.
Dans le cas excpetionnel où un service est défini au un niveau d'un module, d'un component ou d'une directive, etc ... Il doit alors utiliser @Injectable({ providedIn: <Target> })
et ne doit jamais contenir 'root'
. Il peut utiliser any
dans le cas d'un module lazy.
Il faut utiliser autant que possible l'annotation @Injectable({ providedIn: ... })
plutôt que @NgModule({ providers: [...] })
qui reste pour des raisons de compatibilités.
Dans un framework avec des composants l'héritage est à proscrire ! Si des composants partagent des logiques alors il faut les découper en plus de composants et/ou services et faire de la composition.
C'est dans ces dossiers que vous devez représenter tout votre système de typage, Interface, Class, Enum.
Le typage ne suit pas le graph de dépendance des NgModules mais celui des ESModules. Déclarez vos typages au plus proche des éléments qui l'utilisent.
Utilisez les Class pour représenter des objets de que vous allez manipuler dans votre métier, aux quels vous souhaitez y associer des méthodes.
Vous utiliserez les Interfaces majoritairement pour représenter des ressources que vous récupérez ou que vous envoyez. Un exemple de structure pour représenter une ressource.
interface Input { ... }
interface Output { ... }
class MyObject {
constructor (input: Input) { ... }
usefullMethod() { ... }
toJSON: Output () { ... }
}
Il est parfois utile de représenter des erreurs avec le système de typage. Elles pourraits être représentées dans le dossier models. Mais il peut être pratique de les représenter dans un dossier différent.
export class InputRequiredError extends Error {
constructor(property: string) {
super(`${property} is required`);
}
}