Migration von AngularJS 1.x zu Angular 2 mit ngUpgrade

ngUpgrade ermöglicht als Teil von Angular 2 den Parallelbetrieb der kommenden Version des Frameworks und seiner Vorgänger. Daher eignet es sich als Grundlage für eine schleichende Migration.

In Pocket speichern vorlesen Druckansicht 3 Kommentare lesen
Lesezeit: 9 Min.
Von
  • Manfred Steyer
Inhaltsverzeichnis

ngUpgrade ermöglicht als Teil von Angular 2 den Parallelbetrieb der kommenden Version des Frameworks und seiner Vorgänger. Daher eignet es sich als Grundlage für eine schleichende Migration.

Seit der Ankündigung von Angular 2 steht für Entwicklungsteams die Frage im Raum, wie sich ihre AngularJS-1.x-Anwendungen für ein Upgrade vorbereiten lassen. Das im Lieferumfang von Angular 2 enthaltene ngUpgrade ist eine Antwort darauf. Es erlaubt einen Parallelbetrieb von Angular 1.x und 2 und stellt somit die Grundlage für eine schrittweise Migration dar. Entwickler haben mit dem Werkzeug die Option, neue Anwendungsteile mit Angular 2 zu schreiben, ohne die bisherigen Bestandteile sofort migrieren zu müssen.

Der vorliegende Beitrag veranschaulicht den Prozess anhand eines Beispiels. Der dazugehörige Quellcode ist auf GitHub zu finden. Er nutzt sowohl für AngularJS 1.x als auch für Angular 2 die Sprache TypeScript und kompiliert die damit geschaffenen Konstrukte für die Ausführung im Browser nach ECMAScript 5.

Die nachfolgende Abbildung skizziert den Aufbau der vorgestellten Anwendung.

Blau eingefärbt sind AngularJS-1.x-Komponenten, mit der kommenden Version verfasste Elemente sind orange markiert.


Demnach handelt es sich um eine AngularJS-1.x-Anwendung, was auch eine Voraussetzung für den Einsatz von ngUpgrade darstellt. Innerhalb der Anwendung kommen jedoch Komponenten (Direktiven) und Services, die sowohl mit AngularJS 1.x als auch mit Angular 2 geschrieben wurden, zum Einsatz. Die jeweils genutzte Framework-Version findet sich bei der Darstellung der Bestandteile links oben.

Um Angular-2-Konstrukte in AngularJS 1.x zu nutzen, sind sie einem sogenannten Downgrade zu unterziehen. Das bedeutet, dass Entwickler sie mit einem von ngUpgrade bereitgestellten Wrapper versehen, damit sie nach außen wie ein Angular-1.x-Gebilde wirken. Im betrachteten Fall passiert das bei FlugCard, FlugService und der Komponente PassagierSuchen. Angular-1.x-Konstrukte versieht ngUpgrade für den Einsatz innerhalb von Angular 2 auf Wunsch ebenfalls mit einem Wrapper. In dem Fall ist von einem Upgrade die Rede. Im betrachteten Beispiel ist das für PassagierCard und PassagierService nötig.

Sowohl die Bundles für AngularJS 1.x als auch die für Angular 2 samt ngUpgrade bindet das Beispiel über Skriptverweise ein. Die Anwendung ist in TypeScript geschrieben. Die aus den Quellen kompilierten ECMAScript-5-Dateien lädt die Anwendung über den Modul-Loader System.js:

System.import('app/app').catch(console.error.bind(this));

Da durch den Einsatz des ECMAScript-2015-Modulsystems in TypeScript jede Datei ihre Abhängigkeiten über import-Anweisungen bekannt gibt, muss die Anwendung lediglich das Laden der Datei app/app.js anfordern. Wie bei AngularJS-Anwendungen üblich, registriert sie die einzelnen Konstrukte, darunter Controller und Services. Zusätzlich kümmert sie sich um das Bootstrapping der Anwendung. Dazu kommt jedoch nicht angular.bootstrap, sondern die gleichnamige Methode aus dem sogenannten UpgradeAdapter von ngUpgrade zum Einsatz. Er ist der Dreh- und Angelpunkt für den angestrebten Parallelbetrieb. Ein Gegenstück zum Bootstrapping über das Attribut ng-app bietet ngUpgrade hingegen nicht. Da mehrere Stellen der Anwendung dieselbe Instanz des UpgradeAdapters benötigen, empfiehlt es sich, ihn in einer eigenen Datei zu instanziieren:

// upgrade-adapter.ts
import {UpgradeAdapter} from 'angular2/upgrade';
export const upgradeAdapter = new UpgradeAdapter();

Die Datei app.ts kann den UpgradeAdapter anschließend importieren und zum Bootstrapping der Anwendung nutzen:

// app.ts
import {upgradeAdapter} from './upgrade-adapter';
[...]
var app = angular.module('app', ['ui.router']);
[...]
upgradeAdapter.bootstrap(document.body, ['app']);