AngularJS – To upgrade or not upgrade?

AngularJS er en JavaScript-baseret open source front-end-webramme til udvikling af applikationer med én side
Strategier og muligheder 

I det følgende vil vi følge Angulars navne konvention og bruge AngularJS for Angular 1.x versioner (pt i version 1.6). Og vi vil bruge Angular for version 2 og fremad.

AngularJS er et populært framework til frontend udvikling. Store organisationer har brugt det i betydelig grad til at udvikle strategiske projekter i de seneste 5 år.

AngularJS bliver stadig udviklet og vedligeholdt. Men med introduktionen af Angular, er det mest oplagte valg at benytte det mere moderne Angular framework (pt. i version 5).

Angular er en fuldstændigt omskrivning og er et enterprise framework med mange fordele. Angular benytter TypeScript. Se artiklen Kom i gang med TypeScript. Dette giver compile-time check og markant større værktøjsunderstøttelse til f.eks. refaktorering. Performance er væsentligt forbedret. Man kan rendere sine views til alternative views såsom NativeScript og Electron.

To upgrade or not upgrade?

Det efterlader imidlertid virksomheder med AngularJS applikationer med nogle overvejelser. Skal man beholde sin kodebase i AngularJS eller skal man portere sin kodebase til Angular?

For små applikationer, er en fuldstændig (big-bang) omskrivning, et oplagt valg. For store og komplekse applikationer, kan det give betydelige omkostninger at lave en big-bang omskrivning. Ydermere kan applikationer, der er baseret på meget tidlige versioner af AngularJS (pre 1.5) kræve mere refaktorering før en opgradering er mulig.

Omskrivning af en komponent

I denne artikel fokuserer vi primært på tilgangen til migrering fra overordnet niveau. De enkelte dele af applikationen er relativt simple at migrere een for een. Kender man AngularJS grundstenene og de respektive modsvar i Angular, er det en relativ simpel opgave at opgradere f.eks. en komponent. Nedenfor er vist en komponent og det tilhørende view i hhv. AngularJS og Angular udgave.

AngularJS component eksempel

angular
  .module(‘companies’)
  .component(‘companyActivity’, {
   templateUrl: ‘./companyActivity.component.html’,
   bindings: {
company: ‘<‘
   },
   controller: [‘companyService’,
function(companyService) {
     this.activityVisible = false;

     this.$onChanges = function () {
       this.companyActivity =
companyService.getActivity(this.company.id);
};

     this.toggleActivity = function() {
       this.activityVisible = !this.activityVisible;
};
}]

 });

Angular component eksempel

import { Component, Input, OnChanges, OnInit } from
‘@angular/core’;
import { CompanyService } from ‘../company.service’;
@Component({
  selector: ‘app-company-activity’,
  templateUrl: ‘./company-activity.component.html’,
  styleUrls: [‘./company-activity.component.css’]
})
export class CompanyActivityComponent implements
OnInit, OnChanges {
  @Input() company;
activityVisible = false;
companyActivity;

  constructor(private companyService: CompanyService)
{}

ngOnInit() {}

ngOnChanges() {
    this.companyActivity =
this.companyService.getActivity(this.company.id);
}

toggleActivity() {
     this.activityVisible = !this.activityVisible;
}
}

AngularJS view template

<a class=“activity-link”
   ng-click=“$ctrl.toggleActivity()”
   ng-class=“{open: $ctrl.activityVisible}”>
   Activity
</a>
<div ng-if=“$ctrl.activityVisible”>
   <p class=“entry” ng-repeat=“entry in
$ctrl.companyActivity”>{{entry}}</p>
</div>

Angular view template

<a class=“activity-link”
   (click)=“toggleActivity()”
   [class.open]=“activityVisible”>
   Activity
</a>
<div *ngIf=“activityVisible”>
   <p class=“entry” *ngFor=“let entry of
companyActivity”>{{entry}}</p>
</div>

ngUpgrade

Angular kommer med en teknologi ngUpgrade, der gør det muligt at opgradere gradvist. Man kan udvælge dele af applikationen til opgradering og dermed få en såkaldt hybrid applikation, hvor Angular og AngularJS eksisterer sammen.

Dette giver mulighed for at man kan styre sin opgradering og opdele den i etaper. Man kan deploye hybrid applikationen til produktion, når man har nået veldefinerede og testede stadier af migreringen. En virksomhed kan dermed planlægge opgradering af dele af applikationen f.eks. sammen med feature opdateringer og derved nedbringe risiko, udvikling, test og dermed omkostningerne. Hybrid app’en kommer til at eksistere så længe opgraderingen foregår. Dette kan tage måneder og måske år, baseret på
virksomhedens strategi for opgradering.

I det følgende vil jeg beskrive de tekniske muligheder ngUpgrade tilbyder samt deres fordele og ulemper.

Upgrading eller downgrading?

ngUpgrade kommer med 2 mulige måder at bootstrappe en hybrid app. De to muligheder er benævnt ved den factory de bruger, hhv. downgradeModule og upgradeModule. I det følgende vil vi kalde den del af applikationen, der er opgraderet til Angular, for Angular app’en. Den del af applikationen, der stadig er kodet i AngularJS, kalder vi for AngularJS app’en. Det er vigtigt pointere, at de 2 apps stadig er en del af samme applikation og, at de tilsammen udgør funktionaliteten af den originale applikation.

upgradeModule

Her starter man Angular app’en op og man ‘upgradere’ AngularJS app’en. Med ‘upgradere’ menes her, at den originale AngularJS kode wrappes med en tynd Angular skal, som bootstrappes i Angular runtime miljøet. Det specielle er her, at AngularJS app’en nu lever i et nyt runtime miljø. Dette kan give anledning til uhensigtmæssigheder. F.eks. kommer Angular app’en og AngularJS app’en til at dele event håndtering. Dette kan potentielt give performance problemer for AngularJS app’en især i store applikationer.

downgradeModule

Ved downgradeModule bootstrapper man AngularJS app’en og indlejrer en ‘downgraded’ Angular app. Angular app’en kan dermed fungere med AngularJS, men den beholder en række af Angular fordele. Angular app’en lever ikke i AngularJS miljøet og beholder f.eks. sin egen event håndtering. Derudover kan man stadig udnytte de fleste Angular features. Bl. a. Ahead of Time kompilering (AoT). Man kan således instantiere og endda lazy-loade Angular app’en som det kendes fra rene Angular applikationer.

Umiddelbart kan upgradeModule tilgangen virke attraktiv. Men det er vigtigt at gøre sig klart, at AngularJS app nu lever i en Angular kontekst. F.eks. som nævnt ovenfor, gør det, at AngularJS koden bruger Angulars change detection library zones.js. Dette gør, at AngularJS skal håndtere mange flere events og dermed flere digest cycles.

Dette kan give uhensigtmæssigheder og en dårligere performance, da en akilleshæl ved AngularJS er dens performance ved at håndtere ændringer.

I downgradeModule tilgangen lever de 2 apps mere isoleret i hver deres runtime og risikoen for uhensigtmæssigheder er derfor mindsket betydeligt. Da man stadig høster de fleste fordele ved Angular for den del, der er opgraderet, er denne tilgang derfor den anbefalede.

Del migrering op

Når man har besluttet sig for en gradvist opgradering, er det en god ide at lægge en strategi for, hvilken del af sin app man vil opgradere først. Man kan have forretningsbestemte prioriteter, men udover det, er det fordelagtigt at skære en opgradering til. Dette kan give fordele for både load performance og udviklingstid.

Vertical slicing

Man kan opgradere vilkårlige komponenter, men det er en fordel at dele det op så hver side i applikationen enten er kodet i AngularJS eller Angular. Hvis man f.eks. bruger en router, vil det svare til, at en route enten er kodet i AngularJS eller Angular. Hermed får man, at hver side eller route kun bruger en Angular runtime af gangen. Dette giver klart et load performance boost. Denne opdeling kaldes også vertical slicing.

Konklusion

Gradvis opgradering til Angular er mulig. Der findes forskellige tilgange til en sådan opgradering. downgradeModule tilgangen har mange fordele så den bør man overveje nøje. Det er forbundet med både udviklings- og load-time hastigheds fordele at opgradere sin applikation af side per side eller route per route.

Ressources

Der er en del dokumentation og tutorials omkring ngUpgrade. De to bedste jeg kan anbefale er her.

Michael Krogh

Michael Krogh

Seniorkonsulent | Instruktør

Michael er pragmatisk teknolog med 20+ års erfaring inden for udvikling af software. Dedikeret ift. at levere solide løsninger, der skaber glade kunder og slutbrugere. Arbejder oftest som applikationsarkitekt eller lederudvikler på frontend-projekter. Michael er desuden instruktør og underviser i VueJS, AngularJS og Typescript.