Header Menu Icon
Blog Post Page Background ImageBlog Post Page Background Image
Angular v7 vs. Angular v8Angular v7 vs. Angular v8

Angular v7 vs. Angular v8

Neuerungen in Angular 8

Das 8.0.0.0 Release von Angular (ab 28. Mai 2019) ist endlich da und diese Hauptversion umfasst die gesamte Plattform, einschließlich des Frameworks selbst, des Angular Materials und des CLI. Dieses Update enthält eine Vorschau auf Ivy (Angulars neuer Compiler und neue Rendering-Pipeline), Web-Worker-Unterstützung, differentielles Laden (dank dessen werden moderne Browser die Startzeit deutlich verkürzen) und vieles mehr (die vollständige Liste der Änderungen ist auf Angulars offizielles Changelog zu sehen).

Was ist Ivy?

An Ivy ist ein Codename für große Arbeit aus dem Angular-Team und eine Grundlage für die Zukunft von Angular. Ivy ist Angulars Compiler und Rendering-Pipeline der nächsten Generation. Es ist das dritte in der Reihe nach dem ursprünglichen Compiler (für Angular 2) und Renderer2 (für Angular 4 und höher). Misko Hevery und Kara Erickson (Software-Ingenieure bei Google) gaben uns den ersten Blick auf Ivy unter ngConf-2018. Derzeit befindet sich Ivy noch im Preview-Modus und ist nicht vollständig, aber Sie können es für Experimente und Tests aktivieren. Um ein neues Projekt mit aktiviertem Ivy zu starten, verwenden Sie den nächsten Befehl mit --enable-ivy flag:
$ ng new my-ivy-app --enable-ivy
Und um ein bestehendes Projekt für die Verwendung von Ivy zu aktualisieren, setzen Sie die Option enableIvy in angularCompilerOptions in tsconfig.app.json Ihres Projekts:


    {
      "compilerOptions": { ... },
      "angularCompilerOptions": {
        "enableIvy": true
      }
    }
    

"Ahead-of-time" (AOT) Kompilierung mit Ivy ist schneller und sollte standardmäßig verwendet werden. Legen Sie in der Workspace-Konfigurationsdatei angular.json die Standard-Build-Optionen für Ihr Projekt fest, um immer die AOT-Kompilierung zu verwenden.

Ivy wird kleinere und einfachere Pakete und schnellere Kompilierungen haben, wie es das Angular-Team sagt. Ivy folgt dem Ortsprinzip, bei dem immer nur eine Datei auf einmal kompiliert wird. Beim Erzeugen der Ausgabe betrachtet es nur eine Komponente und deren Vorlage, nicht deren Abhängigkeiten. Dies führt zu einer schnelleren Kompilierung und Vereinfachung des Prozesses. Mit der Lokalität gibt es mehr Möglichkeiten für die Metaprogrammierung, wie Komponenten höherer Ordnung und die Möglichkeit, Module, Komponenten oder Pipes dynamisch zu generieren. Ivy verwendet effizienteres Tree-Shaking, indem es ungenutzte Teile Ihres Codes entfernt, was zu kleineren Bundles und schnelleren Ladezeiten führt. Ivy zerlegt die Dinge in kleinere, atomare Funktionen. Diese atomaren Funktionen machen den Renderer-Code viel freundlicher für das Tree-Shaking, da sie nur den Code generieren, den Sie aus der von Ihnen geschriebenen Vorlage benötigen.

Unterstützung von Webworkern

Webworker sind eine gute Möglichkeit, Ihre Anwendung zu beschleunigen, wenn Sie eine rechenintensive Verarbeitung (wie Bild- oder Videomanipulation) durchführen. Sie ermöglichen es Ihnen, die Arbeit in einen Hintergrund-Thread zu verlagern, wodurch der Haupt-Thread frei wird, um die Benutzeroberfläche zu aktualisieren. Sie können einen Webworker überall in Ihrer Anwendung hinzufügen. Wenn die Datei, die Ihre teure Berechnung enthält, src/app/app/app.component.ts ist, können Sie einen Webworker mit dem Befehl:
$ ng generate webWorker my-worker
hinzufügen.

Die Ausführung dieses Befehls wird:

  • Ihr Projekt so konfigurieren, dass es den Webworker verwendet, falls dies noch nicht geschehen ist.
  • Die Datei src/app/app.app.worker.ts mit dem Gerüstcode hinzufügen, um Nachrichten zu empfangen:

    addEventListener('message', ({ data }) => {
      const response = `worker response to ${data}`;
      postMessage(response);
    });
    
  • Gerüstcode zu src/app/app/app.component.ts hinzufügen, um den Worker zu verwenden:

    if (typeof Worker !== 'undefined') {
      // Create a new worker
      const worker = new Worker('./app.worker', { type: 'module' });
      worker.onmessage = ({ data }) => {
        console.log('page got message: ${data}');
      };
      worker.postMessage('hello');
    } else {
      // Web Workers are not supported in this environment.
      // You should add a fallback so that your program still executes correctly.
    }    
    

Sobald Sie einen Webworker haben, können Sie ihn normal in Ihrer Anwendung verwenden, und Sie müssen Ihren Code überarbeiten, um ihn zu verwenden, indem Sie Nachrichten an und von ihm senden.

Differenzielles Laden

Differentielles Laden ist ein Prozess, bei dem der Browser basierend auf seinen eigenen Fähigkeiten zwischen einem modernen oder älteren JavaScript-Codebundle wählt. Bisher war es üblich, Anwendungen mit dem alten ECMAScript 5 zu kompilieren, da diese JavaScript-Version heute fast auf jedem Browser läuft. Dies bedeutet, dass sowohl der IE 11 als auch der Webcrawler hinter der Google-Suchmaschine den Programmcode erfolgreich ausführen können. Das neue ECMAScript 2015 und seine neueren Versionen sind jedoch effizienter: Diese Versionen ermöglichen kompaktere Bundles und der Browser kann sie auch effizienter interpretieren.

Um das differentielle Laden zu aktivieren, ist es notwendig, einen oberen und einen unteren Balken für die ECMAScript-Versionen einzustellen, die Sie unterstützen möchten. Der obere Balken wird in die Datei tsconfig.json eingetragen:


    {
      "compilerOptions": {
        ...
        "module": "esnext",
        "moduleResolution": "node",
        ...
        "target": "es2015",
        ...
      }
    }    
    

Wenn das Target auf es2015 gesetzt ist, erzeugt und labelt Angular CLI zwei Bundles.

Die untere Balken hingegen wird durch eine Browserliste definiert, eine Datei, die CLI beim Erstellen eines neuen Projekts im Projekt-Wurzelverzeichnis erstellt und in der Sie erkennen können, wie viele Browser unterstützt werden müssen:


    > 0.5%
    last 2 versions
    Firefox ESR
    not dead
    IE 9-11
    

Im veranschaulichten Fall zeigt die Browserliste auf ECMAScript 5 Browser mit dem Eintrag IE 9-11, wodurch das CLI den unteren Balken als diese Version bestimmt.

Der Nachteil dieses Prozesses wird hier klar: Der Zeitaufwand für den Build-Prozess wird verdoppelt.

Die verschiedenen Browser können nun entscheiden, welche Version der Bundles geladen werden soll. Dazu erhalten die Skript-Referenzen in den index.html den Zusatz: Diejenigen, die auf ECMAScript 5-Bundles verweisen, erhalten den Zusatz nomodule. Dadurch wird verhindert, dass Browser mit Unterstützung für ECMAScript-Module und damit ECMAScript 2015 und neuer den Verweis ignorieren. Die ECMAScript 2015+ Bundles hingegen werden vom CLI über type="module" implementiert. Daher ignorieren ältere Browser diese Skript-Tags:


      <script src="main-es2015.js" type="module"></script> <!-- ECMAScript 2015+ -->
  
      <script src="main-es5.js" nomodule></script>         <!-- Older browsers (IE 11), ECMAScript 5 -->
    

Durch das differenzierte Laden (siehe unten) können die Paketgrößen bereits jetzt optimiert werden.

Creative Suite vs. Creative Cloud Gradient image
Bundle-Größen einer Hello-World-Anwendung mit und ohne Ivy (Quelle: ngconf 2019 Keynote von Brad Green und Igor Minar)

Lazy-Loading

Um ein Lazy-loaded Modul in einer Angular App vor Version 8 zu erstellen, mussten Sie wie folgt vorgehen:


      import { NgModule } from '@angular/core';
      import { RouterModule } from '@angular/router';
      
      @NgModule({
          imports: [
              RouterModule.forChild([{
                  path: '',
                  loadChildren: './lazy/lazy.module#LazyModule'
              }])
          
      })
      export class MyModule { }
    

Der Wert vor dem Hash-Zeichen stellt den Pfad dar, der zu der Datei mit der Modul-Implementierung führt; der Wert nach dem Hash-Zeichen steht für die darin enthaltene Klasse. Diese Schreibweise funktioniert auch mit Angular 8, wurde aber zugunsten dynamischer ECMAScript-Importe verworfen, wie folgt:


      import { NgModule } from '@angular/core';
      import { RouterModule } from '@angular/router';
      
      @NgModule({
          imports: [
              RouterModule.forChild([{
                  path: '',
                  loadChildren: () => import('./lazy/lazy.module').then(m => m.LazyModule)
              }])
          
      })
      export class MyModule { }
    

Breaking-Change in ViewChild und ContentChild

In der Angular Version 8 gibt es eine grundlegende Änderung in der Verwendung von ViewChild und ContentChild. Während sie in früheren Versionen für eine Komponente verwendet wurden, um ein Element anzufordern, das nicht innerhalb einer Strukturanweisung wie ngIf oder ngFor liegt, war das Abfrageergebnis bereits in ngOnInit verfügbar. Andernfalls könnte der Programmcode frühestens in ngAfterViewInit (oder ngAfterContentInit für ContentChild) darauf zugreifen. Für Elemente, die aufgrund der Datenbindung erst zu einem späteren Zeitpunkt in das DOM geladen wurden, musste der Programmcode ngAfterViewChecked bzw. ngAfterContentChecked einfügt werden.

Da dieses Verhalten verwirrend war, muss die Komponente nun angeben, wann die Auflösung erfolgen soll:
@ViewChild('info', { static: false }) paragraph: ElementRef;

Wenn static den Wert true hat, wird Angular versuchen, das Element bei der Initialisierung der Komponente zu finden. Das funktioniert nur, wenn es nicht in einer Strukturrichtlinie steht. Bei Verwendung von static: false erfolgt die Auflösung nach dem Initialisieren oder Aktualisieren der Ansicht.

Wie wird aktualisiert?

Das Updaten von Angular CLI auf Version 8 und das Updaten Ihres Projekts auf Angular Version 8 von Version 7 ist sehr einfach, dank der ganzen Arbeit, die in Version 8 geleistet wurde, und des Befehls ng update, mit dem Sie bestimmte Versionen und Abhängigkeiten aktualisieren können.

Hier haben wir eine Checkliste zusammengestellt, die Sie durchlaufen müssen, um Ihre Angular-Anwendung von Version 7 auf 8 erfolgreich zu aktualisieren:

Vor dem Update

  • Wenn Sie den alten HttpModule und den Dienst Http verwenden, wechseln Sie zu HttpClientModule und dem Dienst HttpClient. HttpClient vereinfacht die Standard-Ergonomie (Sie müssen nicht mehr auf JSON mappen) und unterstützt nun typisierte Rückgabewerte und Interceptoren.
  • Sobald Sie und alle Ihre Abhängigkeiten auf RxJS 6 aktualisiert haben, entfernen Sie rxjs-compat.
  • Wenn Sie den Angular Service Worker verwenden, migrieren Sie alle versionedFiles in das Datei-Array. Das Verhalten ist das gleiche.

Während des Updates

  • Aktualisieren Sie auf Version 8 des Kernframeworks und der CLI, indem Sie auf Ihrem Terminal ausführen:
    $ ng generate webWorker my-worker
  • Ersetzen Sie /deep/ durch ::ng-deep in Ihren Styles, beide sind veraltet, aber die Verwendung von ::ng-deep wird bevorzugt, bis der Shadow-Piercing-Kombinator vollständig aus Browsern und Tools entfernt ist.
  • Angular verwendet nun TypeScript 3.4, um zu aktualisieren führen Sie aus:
    $ npm update -g typescript
  • Stellen Sie sicher, dass Sie Node 10 oder höher verwenden.
  • Wenn Sie ViewChild oder ContentChild verwenden, müssen Sie nun angeben, dass die Änderungserkennung ausgeführt werden soll, bevor die Ergebnisse gesetzt werden (überprüfen Sie Breaking-Change im ViewChild und ContentChild Kapitel oben).
  • Wenn Sie Angular Material verwenden, aktualisieren Sie es auf Version 8, indem Sie es in Ihrem Terminal ausführen:
    $ ng update @angular/material

Wenn Sie versuchen, von einer anderen Version als der Angular Version 7 zu aktualisieren, können Sie die offizielle Angular Upgrade Anleitung für Anweisungen zum Vorgehen verwenden.

Fazit

Ohne das Ivy sind die Neuerungen der Angular Version 8 nicht groß und für die meisten Angular-Anwendungen unkritisch. Da es keine großen Änderungen gibt, sollten Sie Ihre Anwendung aktualisieren und in den meisten Fällen wird sie ohne Änderungen ausgeführt. Mit der Erweiterung, die ein differentielles Laden ermöglicht, erzielen Sie spürbare Leistungssteigerungen. Noch wichtiger ist, dass das Upgrade auf Angular 8 sicherstellt, dass Ihre Anwendung für den vollen Funktionsumfang von Ivy bereit ist. Auch wenn Ivy derzeit nur eine Opt-in-Vorschau in der Angular-Version 8 ist, ist dies ein guter Zeitpunkt, um mit der Überprüfung der Ivy-Kompatibilität zu beginnen und Änderungen (falls erforderlich) vorzunehmen, bevor Ivy in Angular 9 oder 10 zum Standard wird und die aktuelle Angular View Engine veraltet ist.

Wenn Sie weitere Fragen oder Anmerkungen haben, kontaktieren Sie uns bitte.