#Développement de l'interface utilisateur

0 Abonnés · 2 Publications

Thèmes liés au développement d'interface utilisateur (IU) pour les clients web, bureau et mobiles.

Article Sergei Sarkisian · Juil 5, 2022 10m read

Avant de commencer à aborder des sujets intermédiaires et avancés, je voudrais résumer quelques points plus généraux. Ils sont subjectifs, bien sûr, et je serai heureux d'en discuter si vous avez une autre opinion ou de meilleurs arguments pour l'un d'entre eux.

La liste n'est pas exhaustive et c'est voulu, car je couvrirai certains sujets dans de futurs articles.

Conseil 1. Suivez le guide de style officiel

Angular est assez strict en termes de limitation de l'architecture possible d'une application, mais il y a encore de nombreux endroits qui vous permettent de faire les choses à votre façon. L'imagination des développeurs est sans limite, mais elle rend parfois le travail difficile pour ceux qui travaillent sur le projet avec vous ou après vous.

L'équipe Angular fait un bon travail en maintenant l'architecture Angular elle-même et ses bibliothèques, donc ils savent certainement comment créer une base de code stable et supportable.

Je recommande de suivre leur guide de style officiel et de ne s'en écarter que si les choses ne fonctionnent pas de cette façon. Cela rendra les choses plus faciles quand vous arriverez à un nouveau projet ou si quelqu'un arrive dans votre projet.

Rappelez-vous, un code et une architecture d'application supportables, stables et faciles à comprendre sont plus importants que des solutions intelligentes mais cryptiques que personne ne pourra rattraper (peut-être même vous à l'avenir).

Guide de style officiel d'Angular : https://angular.io/guide/styleguide

Conseil 2. Envisagez d'acheter le livre Angular Ninja

Vous pouvez penser que c'est de la pub, mais voilà : c'est un très bon livre avec tous les principaux concepts d'Angular et le prix est à votre convenance. Vous pouvez également choisir combien d'argent ira aux auteurs et combien ira à une œuvre de charité.

L'un des auteurs de ce livre est membre d'Angular teem, donc c'est certainement la source d'information la plus fiable sur Angular après la documentation officielle. Vous pouvez voir les chapitres du livre sur la page du livre et lire des exemples de chapitres pour décider si le livre en vaut la peine.

De plus, le livre est mis à jour avec la sortie d'une nouvelle version d'Angular et vous obtenez toutes les mises à jour du livre gratuitement.

Le blog Ninja Squad lui-même est une très bonne source d'informations sur Angular, avec des articles et des nouvelles sur les nouvelles versions, les meilleures pratiques, les fonctionnalités expérimentales et plus encore.

Le livre Angular Ninja : https://books.ninja-squad.com/angular

Conseil 3. Lisez la documentation officielle

Avant de vous plonger dans l'écriture du code de votre application, il est bon de lire la documentation et les guides officiels, surtout si vous démarrez votre projet sur une version d'Angular que vous n'avez jamais utilisée auparavant. Les choses sont dépréciées tout le temps, les tutoriels et les guides sur Internet peuvent être dépassés et vous pouvez finir par augmenter votre dette technique au lieu d'utiliser les nouvelles meilleures pratiques et fonctionnalités.

C'est aussi une bonne habitude de vérifier pour quelle version le guide a été écrit. S'il s'agit d'une version antérieure de plus de deux ans à celle que vous utilisez, il est préférable de vérifier si les choses ont changé depuis.

Documentation officielle : https://angular.io

Conseil 4. Envisagez d'utiliser Angular CDK même si vous n'utilisez pas Angular Material.

Je l'aborderai plus en détail dans de futurs articles, mais je sais que de nombreux développeurs Angular ne connaissent même pas Angular CDK.

Angular CDK est une bibliothèque de directives et de classes de base utiles qui peuvent vous aider à développer de meilleures applications. Par exemple, elle contient des éléments tels que FocusTrap, Drag & Drop, VirtualScroll et d'autres qui peuvent être facilement ajoutés à vos composants.

Angular CDK : https://material.angular.io/cdk/categories

Conseil 5. Fixez vos dépendances dans package.json

Il n'est pas particulièrement lié à Angular et il peut être important dans tout projet. Lorsque vous faites npm install --save <quelque chose> , il sera ajouté à votre package.json avec ^ ou ~ au début de la version du package. Cela signifie que votre projet sera capable d'utiliser n'importe quelle version mineure/patch de la même version majeure de la dépendance. Cela se passera mal à l'avenir avec une probabilité de presque 100%. J'ai été confronté à ce problème dans différents projets à de nombreuses reprises. Le temps passe et une nouvelle version mineure d'une dépendance sort et votre application ne se construit plus. Parce qu'un auteur de cette dépendance a mis à jour ses dépendances en version mineure (ou même en patch) et maintenant elles sont en conflit avec votre build. Ou peut-être qu'il y a un nouveau bug dans la nouvelle version mineure de votre dépendance et vous n'avez aucun problème dans votre code (parce que vous avez installé vos dépendances avant la nouvelle version), mais toute autre personne essayant d'installer et de construire votre projet à partir du référentiel sera confrontée au bug dont vous n'avez même pas connaissance (et vous ne serez pas en mesure de le reproduire sur votre machine).

package-lock.json existe pour résoudre ce problème et pour aider les développeurs à avoir le même ensemble de dépendances à travers le projet. Idéalement, il devrait être livré au dépôt, mais de nombreux développeurs décident d'ajouter ce fichier à .gitignore. Et s'il n'est plus là, vous pouvez vous retrouver avec les problèmes ci-dessus. Il est donc préférable de ne pas faire aveuglément confiance à la résolution de vos dépendances et de la fixer sur la version spécifique, de la scanner régulièrement pour détecter les vulnérabilités (avec npm audit), puis de la mettre à jour et de la tester manuellement.

Conseil 6. Essayez de mettre votre application à niveau vers la nouvelle version d'Angular dès que vous le pouvez.

Angular évolue en permanence et de nouvelles versions sortent tous les 6 mois environ. En gardant votre application à jour, vous pourrez utiliser toutes les nouvelles fonctionnalités, y compris des constructions plus rapides et d'autres optimisations. En outre, la mise à niveau vers la prochaine version majeure d'Angular ne devrait pas poser de gros problèmes dans ce cas. Mais si vous avez 5 versions de retard et que votre application est de taille moyenne ou grande, le processus de mise à jour vers la dernière version peut être difficile car Angular n'a pas de schéma pour mettre à niveau les applications sautant des versions intermédiaires d'Angular. Vous devrez mettre à jour toutes les versions intermédiaires une par une, en vérifiant que l'application fonctionne sur chaque version. La mise à jour directe sans schéma Angular CLI est possible, mais peut aussi être délicate. Je vous suggère donc de garder votre application fraîche et à jour.

Conseil 7. Essayez de réduire votre liste de dépendances

Il est facile de prendre l'habitude d'introduire de nouvelles dépendances dans votre application lorsque vous avez besoin de nouvelles fonctionnalités. Mais avec chaque dépendance, la complexité de votre application augmente et le risque d'une soudaine avalanche de dettes techniques s'accroît.

Si vous décidez d'ajouter une nouvelle dépendance dans votre application, pensez à ceci :

  • La dépendance est-elle bien supportée ?
  • Combien de personnes l'utilisent ?
  • Quelle est la taille de l'équipe de développement ?
  • A quelle vitesse ils ferment les problèmes sur GitHub ?
  • La documentation de la dépendance est-elle bien rédigée ?
  • A quelle vitesse est-elle mise à jour après la sortie d'une nouvelle version d'Angular ?
  • Quel est l'impact de cette dépendance sur les performances et la taille du bundle de votre application ?
  • Quelle sera la difficulté de remplacer cette dépendance si elle est abandonnée ou dépréciée à l'avenir ?

Si la réponse à certaines de ces questions est négative, envisagez de vous en débarrasser ou au moins de la remplacer par quelque chose de plus mature et de mieux supporté.

Conseil 8. N'utilisez pas <any> comme type "temporaire".

Encore une fois, il est facile de commencer à utiliser n'importe quel type au fur et à mesure que vous écrivez votre logique d'entreprise, parce que l'écriture de types appropriés pourrait prendre du temps, et vous devez terminer votre tâche dans ce sprint. Les types peuvent être ajoutés plus tard, bien sûr. Mais c'est une pente glissante pour augmenter la dette technique.

L'architecture de votre application et les types doivent être définis avant d'écrire toute logique métier. Vous devez clairement comprendre quels objets vous aurez et où ils seront utilisés. La spécification avant le code, n'est-ce pas ? (Tom Demarco a écrit un livre à ce sujet avant qu'il ne devienne courant : https://www.amazon.com/Deadline-Novel-About-Project-Management/dp/0932633390).

Si vous écrivez le code sans types prédéfinis, vous risquez de vous retrouver avec une architecture d'application moins bonne et des fonctions qui utilisent des objets très similaires mais différents. Vous devrez donc soit créer des types différents pour chaque fonction (ce qui aggravera encore les choses), soit passer votre temps à écrire des spécifications, des types ET du refactoring, ce qui est une perte de temps par rapport à ce qui aurait été fait auparavant.

Conseil 9. Prenez le temps de comprendre le processus de construction

Angular fait un excellent travail pour faciliter le travail du développeur en ce qui concerne la construction du projet. Mais les options par défaut ne sont pas toujours les meilleures dans tous les cas.

Passez votre temps à comprendre comment le processus de construction fonctionne dans Angular, quelles sont les différences entre les constructions de développement et de production, quelles options Angular a pour les constructions (comme les optimisations, les cartes de source, le regroupement et plus).

Conseil 10. Examinez le contenu de votre liasse.

Toutes les bibliothèques ne fournissent pas de tree-shaking et nous ne faisons pas toujours les importations de la bonne manière, il y a donc toujours une chance que quelque chose de redondant soit empaqueté avec notre application.

C'est donc une bonne habitude d'examiner le contenu de votre bundle de temps en temps.

Il y a de bons articles décrivant le processus en utilisant webpack-bundle-analyzer , donc je ne le couvrirai pas ici, mais voici un lien pour l'un d'entre eux : https://www.digitalocean.com/community/tutorials/angular-angular-webpack-bundle-analyzer

Je couvrirai ce sujet plus en détail plus tard dans la série.

Conseil 11. Utilisez la propriété providedIn des services au lieu d'importer le service dans le module.

De nombreux exemples de code Angular sur Internet utilisent l'importation des services dans les modules. Mais ce n'est pas la façon préférée de déclarer les services depuis Angular 6 ou 7. Nous devrions utiliser la propriété providedIn du décorateur @Injectable pour permettre le tree-shaking et un meilleur bundle de nos applications. Angular est suffisamment intelligent pour comprendre dans quel bundle le service doit être inclus, quand il doit être initialisé et combien d'instances du service doivent être créées.

Il y a trois valeurs que providedIn accepte. La plupart du temps, root est suffisant, mais il en existe deux autres :

  • root : le service sera singleton dans la portée de l'application
  • any : une instance du service sera créée pour tous les modules chargés avec empressement, avec une instance différente créée pour chaque module paresseux.
  • platform : le service sera singleton pour toutes les applications tournant sur la même page.

Conseil 12. N'oubliez pas les principales règles d'exécution

  • Utilisez trackBy pour les collections afin de réduire les opérations de redécoupage et l'exécution de JavaScript.
  • Utilisez la stratégie de détection des changements onPush partout où vous le pouvez (je l'aborderai dans l'article dédié).
  • Effectuez les calculs lourds en dehors de ngZone
  • Utilisez des modèles d'accélération et de ralentissement avec vos événements pour éviter les appels inutiles au serveur et l'inondation d'événements.
  • Utilisez le défilement virtuel pour afficher de grands ensembles de données.
  • Utiliser des pure pipes pour la transformation des données dans vos templates
  • Utilisez la compilation AoT
  • Chargez paresseusement les parties de votre application qui ne sont pas nécessaires à son démarrage.
  • Évitez les calculs et les appels de fonction dans vos modèles.

Merci de votre lecture ! J'espère que certains de ces conseils vous ont été utiles. Si vous avez des commentaires et des remarques, s'il vous plaît, faites-le moi savoir dans les commentaires, je serai heureux de discuter 😃. A bientôt !

0
0 174
Article Sergei Sarkisian · Juil 3, 2022 9m read

Bonjour, je m'appelle Sergei Sarkisian et je crée des fronts Angular depuis plus de 7 ans en travaillant chez InterSystems. Comme Angular est un framework très populaire, nos développeurs, clients et partenaires le choisissent souvent comme partie de la pile pour leurs applications.

J'aimerais commencer une série d'articles qui couvriront différents aspects d'Angular : concepts, comment faire, meilleures pratiques, sujets avancés et plus encore. Cette série s'adressera aux personnes qui connaissent déjà Angular et ne couvrira pas les concepts de base. Comme je suis en train d'établir la feuille de route des articles, je voudrais commencer par mettre en évidence certaines fonctionnalités importantes de la dernière version d'Angular.

Formes strictement typées

Il s'agit probablement de la fonctionnalité d'Angular la plus demandée ces dernières années. Avec Angular 14, les développeurs peuvent désormais utiliser toutes les fonctionnalités de vérification stricte des types de TypeScript avec les formulaires réactifs d'Angular.

La classe FormControl est maintenant générique et prend le type de la valeur qu'elle contient.

/* Avant Angular 14 */
const untypedControl = new FormControl(true);
untypedControl.setValue(100); // est définie, aucune erreur

// Maintenant
const strictlyTypedControl = new FormControl<boolean>(true);
strictlyTypedControl.setValue(100); // vous recevrez le message d'erreur de vérification de type ici

// Également dans Angular 14
const strictlyTypedControl = new FormControl(true);
strictlyTypedControl.setValue(100); // vous recevrez le message d'erreur de vérification de type ici

Comme vous le voyez, le premier et le dernier exemple sont presque identiques, mais les résultats sont différents. Cela se produit parce que dans Angular 14 la nouvelle classe FormControl infère les types à partir de la valeur initiale fournie par le développeur. Ainsi, si la valeur true a été fournie, Angular définit le type boolean | null pour ce FormControl. La valeur nullable est nécessaire pour la méthode .reset() qui annule les valeurs si aucune valeur n'est fournie.

Une ancienne classe FormControl non typée a été convertie en UntypedFormControl (il en est de même pour UntypedFormGroup, UntypedFormArray et UntypedFormBuilder) qui est pratiquement un alias pour FormControl<any>. Si vous effectuez une mise à jour depuis une version précédente d'Angular, toutes les mentions de votre classe FormControl seront remplacées par la classe UntypedFormControl par Angular CLI.

Les classes Untyped* sont utilisées avec des objectifs spécifiques :

  1. Faire en sorte que votre application fonctionne absolument comme elle l'était avant la transition de la version précédente (rappelez-vous que le nouveau FormControl déduira le type de la valeur initiale).
  2. S'assurer que toutes les utilisations de FormControl<any> sont prévues. Donc vous devrez changer tout UntypedFormControl en FormControl<any> par vous-même.
  3. Pour fournir aux développeurs plus de flexibilité (nous couvrirons ceci ci-dessous)

Rappelez-vous que si votre valeur initiale est null alors vous devrez explicitement spécifier le type de FormControl. Aussi, il y a un bug dans TypeScript qui exige de faire la même chose si votre valeur initiale est false.

Pour le groupe de formulaire, vous pouvez aussi définir l'interface et juste passer cette interface comme type pour le FormGroup. Dans ce cas, TypeScript déduira tous les types à l'intérieur du FormGroup.

interface LoginForm {
    email: FormControl<string>;
    password?: FormControl<string>;
}

const login = new FormGroup<LoginForm>({
    email: new FormControl('', {nonNullable: true}),
    password: new FormControl('', {nonNullable: true}),
});

La méthode de FormBuilder .group() a maintenant un attribut générique qui peut accepter votre interface prédéfinie comme dans l'exemple ci-dessus où nous avons créé manuellement FormGroup :

interface LoginForm {
    email: FormControl<string>;
    password?: FormControl<string>;
}

const fb = new FormBuilder();
const login = fb.group<LoginForm>({
    email: '',
    password: '',
});

Comme notre interface n'a que des types primitifs non nuls, elle peut être simplifiée avec la nouvelle propriété nonNullable FormBuilder (qui contient l'instance de la classe NonNullableFormBuilder qui peut aussi être créée directement) :

const fb = new FormBuilder();
const login = fb.nonNullable.group({
    email: '',
    password: '',
})

❗ Notez que si vous utilisez un FormBuilder non Nullable ou si vous définissez une option nonNullable dans le FormControl, alors lorsque vous appelez la méthode .reset(), elle utilisera la valeur initiale du FormControl comme valeur de réinitialisation.

Aussi, il est très important de noter que toutes les propriétés dans this.form.value seront marquées comme optionnelles. Comme ceci :

const fb = new FormBuilder();
const login = fb.nonNullable.group({
    email: '',
    password: '',
});

// login.value
// {
//   email?: string;
//   password?: string;
// }

Cela se produit parce que lorsque vous désactivez un FormControl à l'intérieur du FormGroup, la valeur de ce FormControl sera supprimée de form.value.

const fb = new FormBuilder();
const login = fb.nonNullable.group({
    email: '',
    password: '',
});

login.get('email').disable();
console.log(login.value);

// {
//   password: ''
// }

Pour obtenir l'objet complet du formulaire, vous devez utiliser la méthode .getRawValue() :

const fb = new FormBuilder();
const login = fb.nonNullable.group({
    email: '',
    password: '',
});

login.get('email').disable();
console.log(login.getRawValue());

// {
//   email: '',
//   password: ''
// }

Avantages des formulaires strictement dactylographiés :

  1. Toute propriété et méthode retournant les valeurs du FormControl / FormGroup est maintenant strictement typée. Par exemple, value, getRawValue(), valueChanges.
  2. Toute méthode permettant de modifier la valeur d'un FormControl est maintenant sécurisée par le type : setValue(), patchValue(), updateValue().
  3. Les FormControls sont maintenant strictement typés. Cela s'applique également à la méthode .get() de FormGroup. Cela vous empêchera également d'accéder aux FormControls qui n'existent pas au moment de la compilation.

Nouvelle classe FormRecord

L'inconvénient de la nouvelle classe FormGroup est qu'elle a perdu sa nature dynamique. Une fois définie, vous ne serez pas en mesure d'ajouter ou de supprimer des FormControls à la volée.

Pour résoudre ce problème, Angular présente une nouvelle classe - FormRecord. FormRecord est pratiquement le même que FormGroup, mais il est dynamique et tous ses FormControls doivent avoir le même type.

folders: new FormRecord({
  home: new FormControl(true, { nonNullable: true }),
  music: new FormControl(false, { nonNullable: true })
});

// Ajouter un nouveau FormContol au groupe
this.foldersForm.get('folders').addControl('videos', new FormControl(false, { nonNullable: true }));

// Cela entraînera une erreur de compilation car le contrôle est de type différent.
this.foldersForm.get('folders').addControl('books', new FormControl('Some string', { nonNullable: true }));

Et comme vous le voyez, ceci a une autre limitation - tous les FormControls doivent être du même type. Si vous avez vraiment besoin d'un FormGroup à la fois dynamique et hétérogène, vous devriez utiliser la classe UntypedFormGroup pour définir votre formulaire.

Composants sans module (autonomes)

Cette fonctionnalité est toujours considérée comme expérimentale, mais elle est intéressante. Elle vous permet de définir des composants, des directives et des tuyaux sans les inclure dans un module.

Le concept n'est pas encore totalement au point, mais nous sommes déjà capables de construire une application sans ngModules.

Pour définir un composant autonome, vous devez utiliser la nouvelle propriété standalone dans le décorateur Composant/Pipe/Directive :

@Component({
  selector: 'app-table',
  standalone: true,
  templateUrl: './table.component.html'
})
export class TableComponent {
}

Dans ce cas, ce composant ne peut être déclaré dans aucun NgModule. Mais il peut être importé dans les NgModules et dans d'autres composants autonomes.

Chaque autonome composant/pipe/directive a maintenant un mécanisme pour importer ses dépendances directement dans le décorateur :

@Component({
  standalone: true,
  selector: 'photo-gallery',
  // un module existant est importé directement dans un composant autonome
	// CommonModule importé directement pour utiliser les directives Angular standard comme *ngIf
  // le composant autonome déclaré ci-dessus est également importé directement
  imports: [CommonModule, MatButtonModule, TableComponent],
  template: `
    ...
    <button mat-button>Next Page</button>
		<app-table *ngIf="expression"></app-table>
  `,
})
export class PhotoGalleryComponent {
}

Comme je l'ai mentionné ci-dessus, vous pouvez importer des composants autonomes dans n'importe quel ngModule existant. Il n'est plus nécessaire d'importer l'intégralité d'un module partagé, nous ne pouvons importer que les éléments dont nous avons réellement besoin. C'est également une bonne stratégie pour commencer à utiliser de nouveaux composants autonomes:

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, HttpClientModule, TableComponent], // import our standalone TableComponent
  bootstrap: [AppComponent]
})
export class AppModule {}

Vous pouvez créer un composant autonome avec Angular CLI en tapant:

ng g component --standalone user

Application Bootstrap sans module

Si vous voulez vous débarrasser de tous les ngModules dans votre application, vous devrez amorcer votre application différemment. Angular a une nouvelle fonction pour cela que vous devez appeler dans le fichier main.ts:

bootstrapApplication(AppComponent);

Le second paramètre de cette fonction vous permettra de définir les providers dont vous avez besoin dans votre application. Comme la plupart des fournisseurs existent généralement dans les modules, Angular (pour l'instant) exige d'utiliser une nouvelle fonction d'extraction importProvidersFrom pour eux :

bootstrapApplication(AppComponent, { providers: [importProvidersFrom(HttpClientModule)] });

Chargement paresseux de la route des composants autonomes:

Angular dispose d'une nouvelle fonction de route de chargement paresseux, loadComponent, qui existe exactement pour charger des composants autonomes:

{
  path: 'home',
  loadComponent: () => import('./home/home.component').then(m => m.HomeComponent)
}

loadChildren ne vous permet plus seulement de charger paresseusement un ngModule, mais aussi de charger les routes des enfants directement à partir du fichier des routes :

{
  path: 'home',
  loadChildren: () => import('./home/home.routes').then(c => c.HomeRoutes)
}

Quelques notes au moment de la rédaction de l'article

  • La fonctionnalité des composants autonomes est encore au stade expérimental. Elle sera bien meilleure à l'avenir avec le passage à Vite builder au lieu de Webpack, un meilleur outillage, des temps de construction plus rapides, une architecture d'application plus robuste, des tests plus faciles et plus encore. Mais pour l'instant, beaucoup de ces éléments sont manquants, nous n'avons donc pas reçu le paquet complet, mais au moins nous pouvons commencer à développer nos applications avec le nouveau paradigme Angular en tête.
  • Les IDE et les outils Angular ne sont pas encore tout à fait prêts à analyser statiquement les nouvelles entités autonomes. Comme vous devez importer toutes les dépendances dans chaque entité autonome, si vous manquez quelque chose, le compilateur peut aussi le manquer et vous faire échouer au moment de l'exécution. Cela s'améliorera avec le temps, mais pour l'instant, les développeurs doivent accorder plus d'attention aux importations.
  • Il n'y a pas d'importations globales présentées dans Angular pour le moment (comme cela se fait dans Vue, par exemple), donc vous devez importer absolument chaque dépendance dans chaque entité autonome. J'espère que ce problème sera résolu dans une prochaine version, car l'objectif principal de cette fonctionnalité est de réduire le boilerplate et de rendre les choses plus faciles.

C'est tout pour aujourd'hui. A bientôt !

0
0 424