Loupe

Angular 5 : plus léger, plus rapide, plus simple

La nouvelle release majeure d'Angular, nommée pentagonal-donut est sortie le premier novembre 2017. Cette version n'apporte pas de modifications majeures en terme de code, elle est surtout axée optimisation/performance de l'application et de la compilation.

De meilleures performances

Angular CLI et Build Optimizer

Conjointement à Angular 5, la CLI est aussi mise à jour. Angular CLI 1.5 utilise maintenant le Build Optimizer par défaut. Ce Build Optimizer réalise plusieurs optimisations supplémentaires, qui permettent notamment un meilleur tree shaking (https://developer.mozilla.org/en-US/docs/Glossary/Tree_shaking).

Le compilateur Angular est bien entendu lui aussi amélioré/optimisé, ce qui permet (sans surprise) des compilations plus rapides. Une des améliorations très intéressante pour le développeur est le support de la compilation incrémentale par le compilateur Angular. Cela est possible car le compilateur Angular opère comme un TypeScript transform (disponible depuis Typescript 2.3), ce qui permet au compilateur de se brancher sur la pipeline de compilation TypeScript.

Concrètement, cela permet au développeur de travailler en AOT, sans avoir des temps de compilation indécents.

ng serve --aot

Nous bénéficions alors de tous les avantages de la build AOT, avec la validation des templates notamment. (voir Angular : JIT vs AOT)

Les développeurs d'Angular veulent amener la CLI vers ce comportement par défaut, car leur objectif est de rendre la compilation AOT assez rapide pour que les développeurs n'aient pas à développer en JIT. Cela nous évitera les mauvaises surprises lorsqu'on génère un package de production et qu'on découvre un écart avec la version JIT.

Concrètement, la build AOT du site https://angular.io est passé de plus de 40 secondes de build à 2 secondes, grâce à la compilation incrémentale.

Preserve Whitespaces

Avant cette nouvelle version, le compilateur préservait les espaces, les sauts de lignes et les tabulations présentes dans les templates de composants. Maintenant, il est possible de choisir si l'on veut les préserver ou non, sachant que la feature est désactivée par défaut.

Selon les spécifications, l'implémentation actuelle se comporte de la sorte :

  • Tous les whitespaces au début et à la fin du template sont retirés (trim)
  • Les noeuds de texte ne contenant que des whitespaces seront retirés
    Avant : <div>contenu 1</div> <div>contenu 2</div>
    Après : <div>contenu 1</div><div>contenu 2</div>
  • Une série de whitespaces consécutifs dans un noeud de texte sera remplacé par un espace unique.
    Avant : <div>\n mon contenu \n</div>
    Après : <div> mon contenu </div>
  • Le contenu des balises dont les whitespace ont de l'importance ne sont pas modifiées (balise <pre> par exemple)
  • Il est possible de forcer un espace obligatoirement avec &ngsp;

Cette configuration peut se faire à deux endroits.

Soit au niveau du composant directement, dans le décorateur @Component.

@Component({
    templateUrl: 'no-whitespaces.component.html',
    preserveWhitespaces: false
})
export class NoWhiteSpacesComponent

Soit de manière globale, pour toute l'application, au niveau du fichier tsconfig.json.

{
    "compilerOptions": {...},
    "angularCompilerOptions": {
        "preserveWhitespaces": false
    },
    "exclude": {...}
}

 

RxJS 5.5

La dépendance vers RxJS est enfin mise à jour : c'est la version 5.5.2+ qui est maintenant utilisée, qui supporte les modules ECMAScript, ce qui signifie que le tree shaking permet un bundle final encore plus léger.

Historiquement, d'un point de vue développeur, il fallait faire attention en important les opérateurs d'Observable, sans quoi on se retrouvait avec tous les opérateurs dans le bundle final, tandis que nous en utilisons seulement deux.

Il fallait alors importer les opérateurs de la sorte :

import 'rxjs/add/operator/map';
import 'rxjs/add/operator/finally';

Maintenant, il suffit d'écrire :

import { map, filter } from 'rxjs/operators';

 

UpdateOn Blur/Submit avec Angular Forms

Il est maintenant possible de lancer une validation ainsi qu'une mise à jour des données sur le blur et le submit, et non plus sur tous les évènements d'input.

Pour cela, il suffit de renseigner le paramètre updateOn :

Version Template Driven Forms

<!-- Sur le formulaire-->
<form [ngFormOptions]="{updateOn: 'submit'}">

<!-- Sur un contrôle spécifique -->
<input name="myInput" ngModel [ngModelOptions]="{updateOn: 'blur'}"

 

Version Reactive Forms

// Sur un groupe
new FormGroup(value, {updateOn: 'blur'}));

// Sur un contrôle
new FormControl(value, {updateOn:'blur'}));

 

De nouveaux évènements sur le cycle de vie du routeur

De nouveaux évènements sont mis à disposition pour le cycle de vie du routeur. L'objectif des équipes Angular est de permettre aux développeurs de tester les performances des guards, ou bien de pouvoir gérer le statut d'un loader sur un router-outlet spécifique.

Les nouveaux évènements sont les suivants, leur nom étant assez explicite :

  • GuardsCheckStart
  • ChildActivationStart
  • ActivationStart
  • GuardsCheckEnd
  • ResolveStart
  • ResolveEnd
  • ActivationEnd
  • ChildActivationEnd

Pour gérer un loader sur une activation de route enfant, on pourrait alors faire (extrait du blog angular) :

class MyComponent {
  constructor(public router: Router, spinner: Spinner) {
    router.events.subscribe(e => {
      if (e instanceof ChildActivationStart) {
        spinner.start(e.route);
      } else if (e instanceof ChildActivationEnd) {
        spinner.end(e.route);
      }
    });
  }
}

 

Les pipes internationalisées : Number, Date et Currency

Historiquement, les pipes citées ont été développées en utilisant les API des navigateurs pour récupérer les formats de nombres, dates et les devises. Il fallait alors ajouter des polyfills (des scripts supplémentaires pour rajouter des fonctionnalités manquantes aux API de certains navigateurs), et le résultat n'était quand même pas satisfaisant.

C'est pourquoi, les pipes ont été refaites, et utilisent uniquement une implémentation propre aux équipes d'Angular, se basant sur le Unicode CLDR, ce qui apporte un meilleur support des locales et une configuration beaucoup plus aisée.

Si, pour une raison quelconque, le développeur souhaite utiliser les anciennes pipes, il faut désormais importer le module DeprecatedI18NPipesModule

 

En conclusion

On a le sentiment que cette version apporte une certaine maturité, notamment autour de la build et de son optimisation. Les applications deviennent de plus en plus réactives et optimisées, que ce soit par le framework ou par les outils pour le développeur.  Enfin, on voit qu'il y a des ajustements utiles comme les pipes ou bien les updateOn des formulaires/contrôles de formulaire.

Il n'y a plus qu'à espérer que la version majeure 6.0, qui devrait sortir en mars/avril selon les docs d'Angular, continue d'apporter son lot d'optimisations et de nouvelles features. Personnellement, mon attente principale est de pouvoir passer complètement en mode AOT pour le ng serve :)

Ces billets pourraient aussi vous intéresser

Vous nous direz ?!

Commentaires

comments powered by Disqus