Taille de texte par Defaut
Agrandir la Taille du Texte
Réduire la Taille du Texte
Options d'accessibilité
Informatique

Passons de Angular 5 à Angular 6

Jean-Marc Lagniez
10 octobre 2018
Pas de commentaires

Le partage : c’est la vie, et à ITK on l’a bien compris. Quand on peut avoir un aussi beau résultat que son voisin en trois petits clics : on aime ! Pour cela, on a la solution : La NgLib.

La NgLib permet de partager un ensemble de librairies coté front-end pour angular dans un but de visualisation de données, d’interaction avec l’utilisateur ou de requêtage du serveur. La NgLib a pour objectif de proposer un ensemble de nouveaux composants tels que angular material mais fait par les mimines de tous les développeurs d’ITK 😀 !

En raison de l’évolution de angular, on a créé plusieurs versions de la NgLib à travers les années. La première version est la ItkJsLib pour angularJs, la deuxième version est la Ng2Lib à l’arrivée d’angular 2, la troisième version est la ng5lib qui a été un tremplin pour passer de notre propre builder vers angular cli et la nouvelle version est la ng6lib qui utilise la méthode préconisée par angular cli pour faire des librairies.

Aujourd’hui cet article a pour objectif d’expliquer comment on est passé de la ng5lib vers la ng6lib et comment basculer une application de angular 5 à angular 6.

De ng5lib vers ng6lib

Initialisation de la ng6lib

Pour initialiser la ng6lib, c’est identique à une application classique:

npm install -g @angular/cli
ng new ng6lib
cd ng6lib

On pouvait aussi mettre à jour la ng5lib afin de passer à la dernière version en faisant:

cd ng5lib
ng update @angular/cli

Le problème de cette solution est qu’elle ne permet pas d’avoir une base stable pour débuter. On a donc préféré repartir d’un projet flambant neuf.

Copie de la librairie rich-chart de la ng5lib

Dans un premier temps, on va créer la librairie rich-chart et pour le faire, la nouvelle commande d’angular cli est là à notre rescousse.

ng g library rich-chart

Cette commande permet de créer la librairie rich-chart dans le dossier projects à la racine de la ng6lib.

On récupère l’ensemble du code de la rich-chart et on le copie dans projects/rich-chart/src/lib et on exporte les composants, modules, constantes, etc. dans projects/rich-chart/src/public_api.ts:

export * from './lib/rich-chart.module';
export * from './lib/rich-chart.component';
export * from './lib/core/chart.component';

Vous pouvez dès à présent builder votre première librairie:

ng build rich-chart

Vous ouvrez le dossier « `dist« ` et vous voyez la librairie rich-chart prête à l’emploi.
Il est temps maintenant de l’utiliser pour la page de démo de la ng6lib afin de voir si tout est fonctionnel.

Utilisation de la librairie dans votre page de demo

Vous êtes développeur, votre première envie est de voir rapidement les modifications. Ne vous en faites pas, l’équipe d’angular cli a tout prévu car il suffit d’importer dans vos sources les éléments dont vous aurez besoin.
Vous ajoutez dans vos sources de la ng6lib, par exemple app.module.ts, l’import de votre librairie en faisant:

import {RichChartModule, RichChartComponent, ChartComponent} from 'rich-chart'

Rich-chart est vu comme une librarie présente dans le « `node_module« ` ! Et ça c’est beau car il permet de réaliser un premier test d’intégration de la librairie buildée dans un de vos projets !

Vous lancez la page de démo et là c’est le drame, ça ne fonctionne pas. Un bug s’est glissé dans le code source de votre lib rich-chart. Vous vous empressez d’aller le corriger et en un temps trois mouvements, vous le détectez et le résolvez.

Vous regardez votre page de démo et là… rien. Le bug est toujours présent et angular cli ne semble pas avoir pris en compte la modification. Que se passe-t-il ?

Vous utilisez une librairie buildée, angular cli ne fait plus le lien entre vos sources et le build. Il faut relancer le build:

ng build rich-chart

Super le bug est corrigé mais ça va devenir rapidement désagréable si on doit rebuilder à chaque modification.
La solution à ce problème est simple. Il suffit de changer dans le tsconfig.json de la ng6lib ceci :

"rich-chart": [
        "dist/rich-chart"
],

par :

"rich-chart": [
        "projects/rich-chart/src/public_api.ts"
],

Vous pouvez maintenant modifier la lib rich-chart et voir les changements en direct :D. Voici pour nous à quoi ressemble la librairie rich-chart :

Passez votre application de angular 5 à angular 6

Vous êtes fier, vous avez votre librairie fonctionnant avec le top du top angular 6 ! Maintenant, il est temps de faire la migration de votre vieille application poussiéreuse tournant sous angular 2, 3, 4 ou 5 pour quelque chose de plus récent telle la version 6, vous ne croyez pas?

La solution est simple, c’est de lancer cette commande à la racine de votre application :

ng update @angular/cli

Vous patientez et là c’est la catastrophe:

401 Unauthorized

Ce problème peut provenir de votre ~/.npmrc. Une solution simple est de le supprimer et d’enlever vos librairies internes du package.json provisoirement. Vous pouvez relancer la commande de mise à jour avec succès !

Vous voilà avec une application fonctionnant avec :

"@angular/cli": "6.x.x",
"@angular/xxxx": "6.x.x",
"rxjs": "6.x.x",
"@itk/rich-chart": "6.0.0"

Vous lancez votre application comme d’habitude :

npm run start

Une première erreur survient:

Unknown option: '--locale'

Il faut savoir qu’une grande partie des options a été déplacée dans le fichier angular.json qui est le remplaçant du fichier .angular-cli.json.
Il faut alors créer votre configuration dans angular.json.

"configurations": {
  "production": {
    ...
  },
  "local": {
    "aot": true,
    "i18nLocale": "fr",
    "fileReplacements": [
      {
        "replace": "src/environments/environment.ts",
        "with": "src/environments/environment.local.ts"
      }
    ]
  },
  "serve": {
    "builder": "@angular-devkit/build-angular:dev-server",
    "options": {
      "browserTarget": "CropWin:build"
    },
    "configurations": {
      "production": {
        "browserTarget": "CropWin:build:production"
      },
      "local": {
        "browserTarget": "CropWin:build:local",
        "port": 9090
      }
    }
  },

Vous mettez à jour votre script du package.json:

"scripts": {
  "start": "ng serve --configuration=local",

Vous pouvez relancer votre application comme à vos habitudes:

npm run start

Encore une fois, des erreurs sont affichées. Ici c’est rxjs qui ne fonctionne plus.

error TS2307: Cannot find module 'rxjs-compat/Observable
error TS2305: Module '"/node_modules/rxjs/Observable"' has no exported member 'Observable
error TS2339: Property 'map' does not exist on type 'Observable<{}>'

Cette fois ci il n’y a pas de solution miracle, il faut repasser sur le code pour le mettre au goût du jour de l’équipe de rxjs (rxjs-compat n’est pas une solution !).

Pour un exemple simple:

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import 'rxjs/add/operators/map';
==============>
import { Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';
Observable.of({a: 1, b: 1}).map(data => {c: data.a + data.b}) 
==============> 
of({a: 1, b: 1}).pipe(map(data => {c: data.a + data.b}))

Pour un exemple de code métier:

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/switchMap';
import 'rxjs/add/operator/delay';
import 'rxjs/add/operator/retryWhen';
============>
import { Observable, of, throwError } from 'rxjs';
import { switchMap, delay, retryWhen } from 'rxjs/operators';
this.dataService.get(CwSimulationService.fillUrlWithParams(CwSimulationService.URL_FETCH_ROI, plotId))
      .switchMap((roiSimulation: ROISimulationOutputDTO) =>
        roiSimulation.simulationLifeCycle === SimulationLifecycle.PENDING ||
        roiSimulation.simulationLifeCycle === SimulationLifecycle.PREPARING ?
          Observable.throw(roiSimulation) :
          Observable.of(roiSimulation)
      )
      .retryWhen(error => error.delay(CwSimulationService.DELAY));
============>
this.dataService.get(CwSimulationService.fillUrlWithParams(CwSimulationService.URL_FETCH_ROI, plotId))
      .pipe(switchMap((roiSimulation: ROISimulationOutputDTO) =>
        roiSimulation.simulationLifeCycle === SimulationLifecycle.PENDING ||
        roiSimulation.simulationLifeCycle === SimulationLifecycle.PREPARING ?
          throwError(roiSimulation) :
          of(roiSimulation)
      ))
      .pipe(retryWhen(error => error.pipe(delay(CwSimulationService.DELAY))));

Toutes les erreurs ont disparu, vous pouvez à présent aller sur votre belle application qui n’aura pas changé d’un pouce :+1.

Commentaires 0

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.