Fermer

avril 10, 2018

Comment mettre à jour des projets angulaires à la dernière version –


Dans cet article, nous verrons comment mettre à jour les projets angulaires vers la dernière version.

Cet article fait partie 6 du tutoriel SitePoint Angular 2+ sur la création d'une application CRUD avec le CLI angulaire .

  1. Partie 0 – Le guide de référence ultime CLI angulaire
  2. Partie 1 – Mise en route de notre première version de l'application Todo
  3. Partie 2 – Création de composants séparés afficher une liste de todos et un seul todo
  4. Partie 3 – Mettre à jour le service Todo pour communiquer avec une API REST
  5. Partie 4 – Utiliser le routeur angulaire pour résoudre les données
  6. Partie 5 – Ajouter une authentification pour protéger le contenu privé [19659009] Partie 6 – Comment mettre à jour les projets angulaires vers la dernière version

Dans partie 1 nous avons appris à faire fonctionner notre application Todo et à la déployer sur les pages GitHub. Cela fonctionnait très bien mais, malheureusement, l'application entière était entassée dans un seul composant

Dans partie 2 nous avons examiné une architecture de composants plus modulaire et avons appris à décomposer ce composant en un arbre structuré.

Dans partie 3 nous avons mis à jour notre application pour communiquer avec un backend d'API REST en utilisant RxJS et le service HTTP d'Angular.

Dans partie 4 nous avons présenté Angular Router et appris comment le routeur met à jour notre application lorsque l'URL du navigateur change et comment nous pouvons utiliser le routeur pour résoudre les données de notre API backend.

Dans partie 5 nous avons ajouté l'authentification à notre application et appris comment nous pouvons protéger les sections de notre application contre un accès non autorisé.

Ne vous inquiétez pas! Vous n'avez pas besoin d'avoir suivi la partie 1, 2, 3, 4 ou 5 de ce tutoriel pour 6 pour avoir du sens. Vous pouvez simplement prendre une copie de notre repo vérifier le code de la partie 5, et l'utiliser comme point de départ. Ceci est expliqué plus en détail ci-dessous

Up and Running

Pour commencer notre objectif de mettre à jour Angular, assurez-vous que vous avez installé la dernière version de la CLI Angular. Si vous ne le faites pas, vous pouvez l'installer avec la commande suivante:

 npm install -g @ angular / cli @ latest

Si vous devez supprimer une version antérieure de l'interface CLI angulaire, vous pouvez:

 npm uninstall -g @ angular / cli angular-cli
npm cache propre
npm installer -g @ angular / cli @ dernier

Après cela, vous aurez besoin d'une copie du code de la partie 5. Ceci est disponible sur GitHub . Chaque article de cette série comporte une balise correspondante dans le référentiel, ce qui vous permet de basculer entre les différents états de l'application.

Le code que nous avons terminé dans la partie 5 et dans lequel nous commençons dans cet article est marqué comme partie-5 . Le code avec lequel nous terminons cet article est marqué comme part-6 .

Vous pouvez penser à des balises comme un alias à un ID de validation spécifique. Vous pouvez passer de l'un à l'autre en utilisant git checkout . Vous pouvez lire plus sur cela ici .

Donc, pour démarrer (avec la dernière version de la CLI Angular installée) nous ferions ceci:

 git clone git @ github.com:sitepoint-editors/angular-todo-app.git
cd angular-todo-app
git checkout partie-5
npm installer
ng servir

Puis visitez http: // localhost: 4200 / . Si tout va bien, vous devriez voir l'application Todo fonctionnelle

Mise à jour angulaire: notre plan d'attaque

Dans cet article, comme nous mettons à jour Angular, nous apprendrons ce qui suit:

  • comment fonctionnent les versions angulaires
  • ] où trouver des instructions sur la façon de mettre à jour Angular
  • comment mettre à jour notre code d'Angular 4 à Angular 5 (Angular 5 étant la dernière version au moment de l'écriture).

À la fin de cet article, vous aurez comprendre:

  • la signification sous-jacente des versions angulaires spécifiques
  • où trouver des instructions exactes sur la façon de mettre à jour les applications angulaires
  • comment déterminer quels changements de code sont requis (le cas échéant) pour Angular 5.

La ​​signification des versions angulaires

Pour soutenir un écosystème prospère, Angular doit être à la fois stable et évolutive.

D'une part, Angular vise à fournir aux développeurs une stabilité maximale pour les applications critiques. D'autre part, il a constamment besoin de s'adapter et de progresser pour supporter les derniers changements dans les technologies web.

Par conséquent, l'équipe Angular a décidé d'utiliser un cycle de publication basé sur le temps avec sémantique versioning .

Un cycle de publication basé sur le temps signifie que nous pouvons nous attendre à de nouvelles versions d'Angular (Angular 5, Angular 6, Angular 7, etc.) toutes les deux semaines ou tous les mois.

le numéro de version d'Angular nous permet de prédire s'il va ou non casser notre application si nous l'améliorons.

Essentiellement, une version sémantique ressemble à ceci: Major.Minor.Patch .

Donc la version v1.3.8 a un composant majeur avec une valeur de 1, un composant mineur avec une valeur de 3 et un composant de correctif avec une valeur de 1.

Lorsqu'une nouvelle version est publiée, la nouvelle version indique implicitement le type de modification qui a été apporté au code.

Les règles suivantes sont appliqué quand une version sémantique est augmentée:

  1. Chaque incrément se produit numériquement avec un incrément de 1.

  2. Lorsqu'un bogue est corrigé et que le code reste rétrocompatible, le composant de correctif est augmenté:

     v0.0.3 // Before bugfix
    v0.0.4 // Après correction de bugs
     
  3. Lorsque la fonctionnalité est ajoutée et que le code reste rétrocompatible, le composant mineur est augmenté et le composant de correctif est remis à zéro:

     v0.2.4 // Avant l'ajout de nouvelles fonctionnalités
    v0.3.0 // Après l'ajout de nouvelles fonctionnalités
     
  4. Lorsqu'une modification est implémentée qui rend le code incompatible, également connu sous le nom de changement de rupture le composant majeur est augmenté et les composants mineur et correctif sont remis à zéro:

     v7 .3.5 // Avant d'implémenter des modifications incompatibles vers l'arrière
    v8.0.0 // Après l'implémentation des modifications incompatibles avec les versions antérieures
    

Si vous n'êtes pas familier avec le versioning sémantique, assurez-vous de consulter ce guide simple de versioning sémantique .

L'équipe Angular combine versionnage sémantique avec un cycle de publication basé sur le temps pour viser :

  • un nouveau patch chaque semaine
  • une nouvelle version mineure tous les mois
  • une nouvelle version majeure tous les 6 mois

Le calendrier des sorties n'est pas figé, car il peut y avoir des vacances ou des événements spéciaux, mais c'est un bon indicateur de ce que nous pouvons attendre en termes de versions à venir.

Vous pouvez suivre le blog Angular officiel et le journal des modifications officielles pour rester à jour sur le

Un énorme avantage des versions sémantiques est que nous pouvons mettre à jour en toute sécurité des applications angulaires avec des versions de correctifs ou des versions mineures sans avoir à craindre de casser nos applications

Mais qu'en est-il s'il existe une nouvelle version majeure? Angular Update Guide

Nous avons déjà lea a averti qu'une version majeure peut venir avec des changements de rupture. Alors, comment savons-nous si notre application existante va se casser ou pas si nous la mettons à jour?

Une façon serait de lire le journal officiel des modifications et de parcourir la liste des changements. façon plus simple est d'utiliser le Guide de mise à jour angulaire pour mettre à jour Angular. Vous sélectionnez votre version actuelle d'Angular et la version que vous souhaitez mettre à niveau et l'application vous indique les étapes exactes que vous devez prendre:

 Mettre à jour Angular avec le Guide de mise à jour angulaire

Pour l'application Todo, nous souhaitons passer d'Angular 4.0 à Angular 5.0

Sélectionnons le niveau de complexité de l'application Advanced afin que nous puissions voir toutes les mesures possibles:

 Angular Update Guide Résultats

Nous obtenons un aperçu complet de toutes les étapes que nous devons suivre pour mettre à jour notre application

Comme c'est gentil!

Avant la mise à jour

La ​​ Avant la mise à jour La liste contient 12 éléments. Aucun des éléments ne s'applique à notre application Angular Todo, donc nous pouvons passer à l'étape suivante.

Pendant la mise à jour

Depuis la liste Pendant la mise à jour seul le dernier élément s'applique à notre application. Nous devons mettre à jour nos dépendances, donc nous allons lancer les commandes proposées à la racine de notre projet:

 $ npm install @ angular / {animations, commun, compilateur, compilateur-cli, noyau, formulaires, http, platform-browser, plate-forme-navigateur-dynamique, plate-forme-serveur, routeur} @ '^ 5.0.0' typescript@2.4.2 rxjs@'5.5.2 '

$ npm install typecript@2.4.2 --save-exact

Comme nous avons mis à jour notre CLI Angular avec la dernière version dans la section Up and Running nous mettons également à jour notre version locale:

 $ npm install @ angular / cli @ latest --save-dev

Pour vérifier que notre application s'exécute correctement, nous lançons:

 $ ng serve

Si ng serve ne parvient pas à démarrer, essayez de supprimer votre répertoire node_modules et package-lock.json et exécutez npm install pour recréer un répertoire node_modules propre et fichier package-lock.json .

Après la mise à jour

La ​​liste Après la mise à jour contient quatre éléments, dont le premier et le dernier s'appliquent à notre application:

  • passer de HttpModule à HttpClientModule
  • importer des opérateurs RxJS de rxjs / opérateurs et utiliser l'opérateur de tuyau RxJS

Nous allons les aborder un par un.

Passer de HttpModule à HttpClientModule

Le guide de mise à jour angulaire nous dit que nous devrions passer de HttpModule à HttpClientModule

Si nous examinons les notes de mise à jour Angular version 5.0.0 nous apprendre qu'Angular 4.3 et versions ultérieures sont livrées avec un nouvel HttpClient qui gère automatiquement les réponses JSON et supporte les Intercepteurs HTTP

Il indique que, pour mettre à jour notre code, nous devons remplacer HttpModule par HttpClientModule injectez le service HttpClient et supprimez tous les appels de la carte (res => res.json ()) car le nouveau HttpClient automatiquement analyse les réponses JSON.

Ouvrons src / app / app.module.ts et remplacons HttpModule :

 // ...
importer {HttpModule} à partir de '@ angular / http';

@NgModule ({
  déclarations: [
    // ...
  ],
  importations: [
    // ...
    HttpModule,
  ],
  fournisseurs: [
    // ...
  ],
  bootstrap: [AppComponent]
})
classe d'exportation AppModule {
}

avec HttpClientModule :

 // ...
importer {HttpClientModule} à partir de '@ angular / common / http';

@NgModule ({
  déclarations: [
    // ...
  ],
  importations: [
    // ...
    HttpClientModule,
  ],
  fournisseurs: [
    // ...
  ],
  bootstrap: [AppComponent]
})
classe d'exportation AppModule {
}

Ensuite, nous devons utiliser le service HttpClient au lieu du service Http et supprimer tous les appels de la carte (res => res.json ()) notre code parce que le nouveau HttpClient analyse automatiquement les réponses pour nous

Dans partie 3 nous avons centralisé tout le code HTTP dans un service appelé ApiService et nous récoltons maintenant les avantages de cette approche.

Par conséquent, nous avons seulement à mettre à jour un fichier, ouvrons src / app / api.service.ts et remplaçons:

 import {
  Http,
  En-têtes
  RequestOptions,
  Réponse
} à partir de '@ angular / http';

// ...

@Injectable ()
classe d'exportation ApiService {

  constructeur(
    http privé: Http,
    session privée: SessionService
  ) {
  }

  signIn public (nom d'utilisateur: chaîne, mot de passe: chaîne) {
    retourner ceci.http
      .post (API_URL + '/ sign-in', {
        Nom d'utilisateur,
        mot de passe
      })
      .map (réponse => response.json ())
      .catch (this.handleError);
  }

  public getAllTodos (): Observable  {
    const options = this.getRequestOptions ();
    retourner ceci.http
      .get (API_URL + '/ todos', options)
      .map (réponse => {
        const todos = réponse.json ();
        return todos.map ((todo) => nouveau Todo (todo));
      })
      .catch (this.handleError);
  }

  public createTodo (todo: Todo): Observable  {
    const options = this.getRequestOptions ();
    retourner ceci.http
      .post (API_URL + '/ todos', todo, options)
      .map (réponse => {
        retourne nouveau Todo (response.json ());
      })
      .catch (this.handleError);
  }

  public getTodoById (todoId: number): Observable  {
    const options = this.getRequestOptions ();
    retourner ceci.http
      .get (API_URL + '/ todos /' + todoId, options)
      .map (réponse => {
        retourne nouveau Todo (response.json ());
      })
      .catch (this.handleError);
  }

  mise à jour publiqueTodo (todo: Todo): Observable  {
    const options = this.getRequestOptions ();
    retourner ceci.http
      .put (API_URL + '/ todos /' + todo.id, todo, options)
      .map (réponse => {
        retourne nouveau Todo (response.json ());
      })
      .catch (this.handleError);
  }

  public deleteTodoById (todoId: number): Observable  {
    const options = this.getRequestOptions ();
    retourner ceci.http
      .delete (API_URL + '/ todos /' + todoId, options)
      .map (réponse => null)
      .catch (this.handleError);
  }

  handleError privé (erreur: Response | any) {
    console.error ('ApiService :: handleError', erreur);
    return Observable.throw (erreur);
  }

  private getRequestOptions () {
    const headers = nouveaux en-têtes ({
      'Autorisation': 'Porteur' + cette.session.accessToken
    });
    return new RequestOptions ({headers});
  }
}

avec

 import {
  HttpClient,
  HttpErrorResponse,
  HttpHeaders
} à partir de '@ angular / common / http';

// ...

@Injectable ()
classe d'exportation ApiService {

  constructeur(
    http privé: HttpClient,
    session privée: SessionService
  ) {
  }

  signIn public (nom d'utilisateur: chaîne, mot de passe: chaîne) {
    retourner ceci.http
      .post (API_URL + '/ sign-in', {
        Nom d'utilisateur,
        mot de passe
      })
      .catch (this.handleError);
  }

  public getAllTodos (): Observable  {
    const options = this.getRequestOptions ();
    retourner ceci.http
      .get (API_URL + '/ todos', options)
      .map (réponse => {
        const todos =  réponse;
        return todos.map ((todo) => nouveau Todo (todo));
      })
      .catch (this.handleError);
  }

  public createTodo (todo: Todo): Observable  {
    const options = this.getRequestOptions ();
    retourner ceci.http
      .post (API_URL + '/ todos', todo, options)
      .map (réponse => {
        retourner le nouveau Todo (réponse);
      })
      .catch (this.handleError);
  }

  public getTodoById (todoId: number): Observable  {
    const options = this.getRequestOptions ();
    retourner ceci.http
      .get (API_URL + '/ todos /' + todoId, options)
      .map (réponse => {
        retourner le nouveau Todo (réponse);
      })
      .catch (this.handleError);
  }

  mise à jour publiqueTodo (todo: Todo): Observable  {
    const options = this.getRequestOptions ();
    retourner ceci.http
      .put (API_URL + '/ todos /' + todo.id, todo, options)
      .map (réponse => {
        retourner le nouveau Todo (réponse);
      })
      .catch (this.handleError);
  }

  public deleteTodoById (todoId: number): Observable  {
    const options = this.getRequestOptions ();
    retourner ceci.http
      .delete (API_URL + '/ todos /' + todoId, options)
      .map (réponse => null)
      .catch (this.handleError);
  }

  // ...
}

Nous remplaçons les anciennes classes de HttpModule par leurs nouvelles contreparties de HttpClientModule .

Plus spécifiquement, nous remplaçons:

  • import {Http, Headers, RequestOptions, Response} à partir de '@ angular / http'; avec import {HttpClient, HttpErrorResponse, HttpHeaders} à partir de '@ angular / common / http';
  • ligne 81: Response avec HttpErrorResponse
  • ligne 90: En-têtes avec HttpHeaders
  • ligne 93: return new RequestOptions ({headers}); avec return {headers};

Si nous courons:

 $ ng serve

et naviguez notre navigateur à http: // localhost: 4200 nous voyons que notre application fonctionne toujours comme prévu, mais utilise maintenant le HttpClientModule en coulisse.

Il est temps d'aborder le point 2: importer les opérateurs RxJS de rxjs / opérateurs et utiliser l'opérateur de tuyau RxJS

En utilisant l'opérateur de tuyau RxJS

Angular 5 a été mis à jour pour utiliser RxJS 5.5.2 ou plus tard.

À partir de la version 5.5, RxJS est livré avec opérateurs pouvant être acheminés . La documentation officielle dit:

Un opérateur pipeable est n'importe quelle fonction qui renvoie une fonction avec la signature: (source: Observable) => Observable

Vous tirez n'importe quel opérateur dont vous avez besoin d'un endroit, sous rxjs / opérateurs (pluriel!). Il est également recommandé de tirer les méthodes de création Observable dont vous avez besoin directement comme indiqué ci-dessous avec range:

 import {range} from> 'rxjs / observable / range';
importer {map, filter, scan} depuis> 'rxjs / operators';

source const $ = plage (0, 10);

source $ .pipe (
 filtre (x => x% 2 === 0),
 carte (x => x + x),
 scan ((acc, x) => acc + x, 0)
)
.subscribe (x => console.log (x))

Bien que cela semble compliqué, cela signifie essentiellement que nous utilisions auparavant des méthodes chaînées:

 source $
  .operatorOne ()
  .operatorTwo ()
  .souscrire()

nous devrions maintenant importer des opérateurs de rxjs / opérateurs et utiliser la méthode .pipe () pour les appliquer:

 source $
  .tuyau(
    operatorOne (),
    operatorTwo ()
  )
  .souscrire()

Les avantages principaux des opérateurs pipables sont:

  1. ils sont shakeable à l'arbre, ce qui permet aux outils de réduire la taille de notre bundle d'application en supprimant le code inutilisé
  2. ] facilement créer nos propres opérateurs pipables personnalisés .

La ​​méthode .pipe () réduit l'impact sur notre code à un minimum.

Nous avons deux éléments dans notre application qui doivent être refactorisé: notre ApiService et TodosComponent .

Tout d'abord, ouvrons src / app / api.service.ts pour mettre à jour notre ApiService :

 // importer des opérateurs à partir de rxjs / opérateurs
importer {map} à partir de 'rxjs / operators';

// ...

@Injectable ()
classe d'exportation ApiService {

  constructeur(
    http privé: HttpClient,
    session privée: SessionService
  ) {
  }

  // ...

  // met à jour .map () vers .pipe (map ())
  public getAllTodos (): Observable  {
    const options = this.getRequestOptions ();
    retourner ceci.http
      .get (API_URL + '/ todos', options)
      .tuyau(
        map (réponse => {
          const todos =  réponse;
          return todos.map ((todo) => nouveau Todo (todo));
        })
      )
      .catch (this.handleError);
  }

  // met à jour .map () vers .pipe (map ())
  public createTodo (todo: Todo): Observable  {
    const options = this.getRequestOptions ();
    retourner ceci.http
      .post (API_URL + '/ todos', todo, options)
      .tuyau(
        map (réponse => {
          retourner le nouveau Todo (réponse);
        })
      )
      .catch (this.handleError);
  }

  // met à jour .map () vers .pipe (map ())
  public getTodoById (todoId: number): Observable  {
    const options = this.getRequestOptions ();
    retourner ceci.http
      .get (API_URL + '/ todos /' + todoId, options)
      .tuyau(
        map (réponse => {
          retourner le nouveau Todo (réponse);
        })
      )
      .catch (this.handleError);
  }

  // met à jour .map () vers .pipe (map ())
  mise à jour publiqueTodo (todo: Todo): Observable  {
    const options = this.getRequestOptions ();
    retourner ceci.http
      .put (API_URL + '/ todos /' + todo.id, todo, options)
      .tuyau(
        map (réponse => {
          retourner le nouveau Todo (réponse);
        })
      )
      .catch (this.handleError);
  }
}

Nous importons l'opérateur pipérable map de rxjs / operators et met à jour toutes les occurrences de .map (fn) à .pipe (map ( fn)) .

Ensuite, ouvrons src / app / todos / todos.component.ts pour appliquer les mêmes changements à TodosComponent :

 / / import opérateurs de rxjs / opérateurs
importer {map} à partir de 'rxjs / operators';

// ...

@Composant({
  sélecteur: 'app-todos',
  templateUrl: './todos.component.html',
  styleUrls: ['./todos.component.css']
})
classe d'exportation TodosComponent implémente OnInit {

  // ...

  // met à jour .map () vers .pipe (map ())
  ngOnInit public () {
    this.route.data
      .tuyau(
        carte ((données) => données ['todos'])
      )
      .souscrire(
        (todos) => {
          this.todos = todos;
        }
      )
  }

  // ...

}

Encore une fois, nous importons l'opérateur pipelinable map de rxjs / operators et mettons à jour .map (fn) à .pipe (map (fn )) .

C'est tout! Les opérateurs chaînés dans notre application ont été remplacés par des opérateurs pipables, tout comme le Guide de mise à jour angulaire nous l'a demandé.

Si nous naviguons notre navigateur vers http: // localhost: 4200 nous voyons que notre l'application fonctionne toujours parfaitement.

Pour vérifier que nous exécutons vraiment Angular 5, nous pouvons ouvrir l'inspecteur d'élément:

 Angular Version

Angular ajoute une [ng-19459029] version ng attribue à app-root avec la valeur de la version en cours d'exécution. Nous voyons ng-version = "5.2.9" indiquant que nous exécutons Angular 5.2.9

Mission accomplie! Notre application a été améliorée avec succès à Angular 5.2.9

Nous avons couvert beaucoup, donc récapitulons ce que nous avons appris.

Résumé

Dans le premier article nous avons appris comment:

  • initialiser notre application Todo en utilisant CLI angulaire
  • créer une classe Todo pour représenter des todos individuels
  • créer un service TodoDataService pour créer, mettre à jour et supprimer des todos
  • utilisent le composant AppComponent pour afficher l'interface utilisateur
  • déployer notre application sur les pages GitHub.

Dans le deuxième article nous avons refaçonné AppComponent pour déléguer la majeure partie de son travail à:

  • a TodoListComponent pour afficher une liste de todos
  • a TodoListItemComponent pour afficher un seul todo
  • a TodoListHeaderComponent pour créer un nouveau todo
  • a TodoListFooterCompo nent pour montrer combien il reste de todos

Dans le troisième article nous avons appris à:

  • créer un backend API fausse REST
  • stocker l'URL de l'API en tant que variable d'environnement
  • créer un ApiService pour communiquer avec l'API REST
  • mettre à jour le TodoDataService pour utiliser la nouvelle ApiService
  • mettre à jour le ] AppComponent pour gérer des appels d'API asynchrones
  • crée un ApiMockService pour éviter les vrais appels HTTP lors de l'exécution de tests unitaires.

Dans le quatrième article nous avons appris: [19659029] pourquoi une application peut nécessiter le routage

  • ce qu'est un routeur JavaScript
  • ce qu'est le Routeur Angulaire, comment cela fonctionne et ce qu'il peut faire pour vous
  • comment configurer le routeur angulaire et configurer les routes pour notre application [19659030] comment dire routeur angulaire où placer des composants dans le DOM
  • comment gérer gracieusement inconnu
  • Dans le cinquième article, nous avons appris:

    • la différence entre les cookies et les jetons
    • comment créer un AuthService pour implémenter la logique d'authentification
    • comment créer un SessionService pour stocker des données de session
    • comment créer un formulaire de connexion à l'aide d'une forme réactive angulaire
    • comment créer un garde d'itinéraire pour empêcher toute autorisation non autorisée accès à des parties de votre application
    • comment envoyer le jeton d'un utilisateur en tant qu'en-tête d'autorisation dans une requête HTTP à votre API
    • pourquoi vous ne devez jamais envoyer le jeton de votre utilisateur à un tiers.

    pour mettre à jour Angular, nous avons appris:

    • comment fonctionnent les versions angulaires
    • ce que signifie un numéro de version sémantique
    • comment le versioning sémantique peut nous empêcher d'introduire aveuglément les changements de rupture dans notre application
    • comment le Guide de mise à jour angulaire peut aider nous trouvons instr détaillé uctions sur comment mettre à jour Angular
    • comment remplacer HttpModule avec HttpClientModule
    • comment mettre à jour notre code RxJS avec les opérateurs pipables
    • comment la ng-version L'attribut nous permet de vérifier quelle version d'Angular est utilisée.

    Dans les prochaines versions, Angular CLI introduira la commande ng update pour aider à mettre à jour les applications Angular. Dès que plus de détails sont disponibles, nous vous fournirons un article de suivi sur la façon dont cette nouvelle commande peut rendre nos vies encore plus faciles.

    Jusque-là, vous pouvez utiliser cet article comme un guide sur la façon de mettre à jour Angular

    Tout le code de cet article est disponible sur GitHub .

    En avoir un bon!




    Source link