Ein Grundgerüst in wenigen Augenblicken

Angular Tutorial: Rascher Projektstart mit dem Angular CLI

Manfred Steyer

Das CLI für Angular vereinfacht den Projektstart mit Angular drastisch, indem es ein Grundgerüst für die Anwendung bereitstellt. Beispielsweise konfiguriert es einen Build-Prozess und richtet Werkzeuge zum Testen der Anwendung ein, damit nimmt es Entwicklern Arbeit ab.

Früher war der Projektstart mit JavaScript einfach: Nach dem Herunterladen eines Frameworks wurde es über einen oder wenige Skriptverweise eingebunden, und schon konnte man mit der Entwicklung loslegen. Heutzutage setzen Anwendungen stärker auf JavaScript oder sind sogar vollständig damit geschrieben. Zur Beherrschung der damit einhergehenden Komplexität sowie zur Steigerung der Qualität greifen Teams deswegen auf immer mehr Werkzeuge zurück. Beispiele dafür sind Compiler, Build-Werkezeuge, Linter oder Testing-Frameworks.

Auch wenn diese Werkzeuge den Einsatz von JavaScript professionalisieren und somit die Entwicklung vereinfachen, ist deren Set-up in der Regel alles andere als trivial. Das Angular-CLI [1] soll dieses Problem für Angular (>= Version 2) lösen. Es generiert ein professionelles Projekt-Set-up, das sich an etablierten Konventionen orientiert und bereits die genannten Werkzeuge integriert. Zusätzlich schirmt es das Team gegen komplexe Details des eingesetzten Build-Werkzeugs ab und hilft beim Generieren weiterer Projektbestandteile, wie Komponenten oder Services.

Dieser Artikel stellt das CLI anhand eines einfachen Projekts zum Suchen nach Flügen vor (Abb. 1) und zeigt somit einen Weg auf, um mit Angular möglichst schnell produktiv zu werden. Das generierte Projekt bietet minifizierte Bundles für den Produktivbetrieb ebenso wie die Integration des TypeScript-Compilers und Werkzeuge für Unit- sowie End-2-End-Tests. Das gesamte Beispiel findet sich zum Download unter [2].

steyer_cli_1

Abb. 1: Das hier betrachtete Beispiel

 

Lesen Sie auch: Das große Angular Tutorial: Erste Schritte mit Angular 2 und TypeScript

Projekt-Set-up mit dem CLI

Das CLI für Angular lässt sich über den Package-Manager npm, der Teil von Node.js [3] ist, installieren:

 

npm install -g @angular/cli

Danach steht das CLI über den Befehl ng zur Verfügung. Ein Aufruf mit dem Argument new veranlasst das CLI, ein neues Projekt im angeführten Ordner zu generieren:

ng new flight-app

Diese Anweisung richtet ein neues Angular-Projekt mit einer ersten Komponente sowie den oben genannten Werkzeugen ein. Zusätzlich bezieht es die nötigen Pakete via npm, weswegen sich dieser Vorgang auch etwas länger gestaltet (Abb. 2).

steyer_cli_2

Abb. 2: Generierung eines neuen Projekts mit dem CLI

Danach kann man im generierten Projektordner weitere Projektbestandteile generieren, wie Komponenten oder Services. Das hier betrachtete Beispiel richtet zum Suchen nach Flügen einen FlightService im Ordner shared ein, der die Kommunikation mit einem Web API übernimmt. Dazu kommt der Parameter g zum Einsatz, der für generate steht:

cd flight-app

ng g service shared/Flight

Obwohl sich der Service FlightService nennt, ist lediglich der Name Flight anzugeben. Die Endung Service zieht das CLI per Definition heran. Beim Generieren des Service informiert das CLI durch eine Warnung darüber, dass der Service noch bereitgestellt werden muss: WARNING Service is generated but not provided, it must be provided to be used. Das bedeutet, dass der Service später im Programmcode zu registrieren ist.

Zum Anzeigen der Flüge sieht das hier betrachtete Beispiel eine FlightSearchComponent vor. Diese wird ebenfalls mit dem CLI generiert, wobei auch hier das Suffix Component wegzulassen ist:

ng g component FlightSearch

Für die Optik der Anwendung sorgt zusätzlich Twitter Bootstrap, das über npm bezogen wird:

npm install bootstrap --save

Die mit diesen Anweisungen generierte Projektstruktur beinhaltet unter anderem den Ordner src, der für den Programmcode vorgesehen ist. Wie Abbildung 3 zeigt, hat das CLI für die FlightSearchComponent einen eigenen Ordner mit vier Dateien eingerichtet: Neben der TypeScript-Datei und einer dazugehörigen HTML- und CSS-Datei findet sich dort auch eine Datei mit der Endung spec.ts. Diese ist für Unit-Tests vorgesehen, die die Funktionsfähigkeit der Komponente überprüfen.

Im Ordner shared begleitet auch eine solche spec.ts-Datei den FlightService. Die meisten dieser generierten Dateien beinhalten auch schon eine Grundstruktur, die sich für die Implementierung der gewünschten Anwendungsfälle anpassen lässt. Zusätzlich zu beachten ist die Datei index.html, die die Angular-Anwendung im Browser repräsentiert und sie unter Nutzung der main.ts startet.

steyer_cli_3

Abb. 3: Generierte Projektstruktur

 

Visual Studio Code und das CLI
Obwohl eine auf Angular basierende Anwendung mit jedem beliebigen Editor bzw. mit jeder beliebigen IDE geschrieben werden kann, bietet sich dafür Visual Studio Code [4] als leichtgewichtiger, freier und plattformübergreifend verfügbarer Editor besonders an. VS Code bietet Codevervollständigung für TypeScript und validiert die geschriebenen Codezeilen im Zuge der Eingabe. Um dateiübergreifende Fehler zu finden, sollte der Compiler ab und zu direkt angestoßen werden. Dazu ist STRG+SHIFT+b (wie Build) zu drücken. Beim ersten Kompilieren legt der Editor einen Build Task für TypeScript an, der in der Datei .vscode/tasks.json zu finden ist. Um anzuzeigen, dass der Compiler den Quellcode samt TypeScript-Konfiguration im Ordner src findet, ist der Parameter args zu erweitern:"args": ["-p", "src"],

Als der vorliegende Text geschrieben wurde, verwendete Visual Studio Code noch eine ältere Version von TypeScript. Um damit einhergehende Probleme zu vermeiden, sollte die neuere, von dem CLI referenzierte Version eingesetzt werden. Dazu ist unter Datei | Einstellungen | Benutzereinstellungen die folgende Zeile einzutragen:

"typescript.tsdk": "./node_modules/typescript/lib"

Anwendung erstellen

Nachdem das CLI das Grundgerüst der Anwendung generiert hat, kann es ausgebaut werden. Zunächst ist die Bibliothek RxJS, die Angular an vielen Stellen nutzt, in der main.ts zu importieren:

import 'rxjs';

Für die Optik der Anwendung ist darüber hinaus die CSS-Datei von Twitter Bootstrap in der Datei angular-cli.json zu referenzieren:

"styles": [
  "styles.css",
  "../node_modules/bootstrap/dist/css/bootstrap.css"
  ],

Das veranlasst das CLI, die CSS-Datei in das für die Auslieferung generierte Bundle aufzunehmen. Zur Repräsentation der abgerufenen Flüge erhält das Beispiel zusätzlich ein Interface über die Datei shared/flight.ts bereitgestellt:

export interface Flight {
  id: number;
  from: string;
  to: string;
  date: string;
}

Danach können die generierten Grundgerüste ausgebaut werden. Der FlightService, der wie üblich mit dem Dekorator Injectable markiert ist, erhält über den Konstruktor den von Angular bereitgestellten Http-Service (Listing 1). Diesen nutzt er in seiner Methode find, um Flüge bei einem Web-API abzurufen. Die Klasse Headers repräsentiert die per HTTP übersendenden Kopfzeilen, und UrlSearchParams spiegelt die zu übersendenden Parameter wider.

Die Methode get des Http-Service liefert ein so genanntes Observable, das die via HTTP asynchron erhaltenen Daten repräsentiert. Ihre Methode map bildet die empfangene HTTP-Antwort durch Aufruf von json auf ein JavaScript-Array ab, das die empfangenen Flüge repräsentiert. Zusätzlich liefert map ein neues Observable, das dieses Array repräsentiert.

import {Injectable} from '@angular/core';
import {Http, URLSearchParams, Headers} from '@angular/http';

@Injectable()
export class FlightService {

  constructor(private http: Http) {
  }

  public find(from: string, to: string) {

    let url = 'http://www.angular.at/api/flight';

    let headers = new Headers();
    headers.set('Accept', 'text/json');

    let search = new URLSearchParams();
    search.set('from', from);
    search.set('to', to);

    return this.http.get(url, { headers, search })
                    .map(resp => resp.json());
  }
}

 

Damit der Service der Anwendung zur Verfügung steht, muss er registriert werden. Dies kann unter anderem in der Datei app.module, die das Hauptmodul der Anwendung repräsentiert, mit der Eigenschaft providers erfolgen (Listing 2).

 

import { FlightService } from './shared/flight.service';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';

import { AppComponent } from './app.component';
import { FlightSearchComponent } from './flight-search/flight-search.component';

@NgModule({
  declarations: [
    AppComponent,
    FlightSearchComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule
  ],
  providers: [FlightService],
  bootstrap: [AppComponent]
})
export class AppModule { }

 

Bei einer genaueren Betrachtung dieser Datei fällt auf, dass das CLI unter declarations die generierte FlightSearchComponent registriert hat. Zusätzlich findet man dort eine AppComponent. Diese Komponente repräsentiert die gesamte Anwendung und wird später an die FlightSearchComponent delegieren. Damit auch Angular weiß, dass diese Komponente die gesamte Anwendung widerspiegelt, kommt sie erneut im Bereich bootstrap vor. Ein Blick in die main.ts verrät, dass die Anwendung dieses Modul beim Start der Anwendung an Angular übergibt.

Komponente zum Suchen nach Flügen

Die FlightSearchComponent (Listing 3) ist mit dem Dekorator Component versehen. Dieser informiert über das zu verwendende Template sowie über die einzubindende CSS-Datei. Ihre Eigenschaft selector benennt das HTML-Element, das die Komponente repräsentiert. Außerdem erhält sie für alle UI-Elemente der Anwendung (Abb. 1) eine Eigenschaft: Die Strings from und to repräsentieren die beiden Eingabefelder und das Array flights die gefundenen Flüge. Die Methode search kommt nach einem Klick auf die Schaltfläche Search zum Einsatz. Sie nutzt den von Angular über den Konstruktor erhaltenen FlightService zum Abrufen von Flügen. Um diese Flüge entgegenzunehmen, kommt die Methode subscribe des erhaltenen Observables zum Einsatz. Ihr erster Parameter ist ein Lambdaausdruck, der die via HTTP asynchron erhaltenen Flüge entgegennimmt. Der Lambdaausdruck im zweiten Parameter nimmt im Fehlerfall ein Fehlerobjekt entgegen und gibt es in der JavaScript-Konsole aus.

 

import {FlightService} from '../shared/flight.service';
import {Flight} from '../shared/flight';
import {Component} from '@angular/core';

@Component({
  selector: 'flight-search',
  templateUrl: './flight-search.component.html',
  styleUrls: ['./flight-search.component.css']
})
export class FlightSearchComponent {

  from: string = 'Hamburg';
  to: string = 'Graz';
  flights: Array<Flight> = [];

  constructor(private flightService: FlightService) {
  }

  search() {

    if (!this.from || !this.to) return;

    this
      .flightService
      .find(this.from, this.to)
      .subscribe(
        flights => { this.flights = flights; },
        err => { console.error(err); });
  }
}

 

Das Template dieser Komponente beinhaltet Eingabefelder, die es mit ngModel an from und to bindet (Listing 4). Ebenso bindet es das Click-Event der Schaltfläche an die Methode search. Die Tabelle mit den Flügen baut es mit einer for-Schleife auf, die sämtliche Flüge iteriert. Die Pipe date formatiert das Datum bei dessen Ausgabe. Informationen zu den verwendeten Datenbindungsausdrücken finden sich in Tabelle 1.

 

<div class="form-group">
  <label>From: </label>
  <input name="from" [(ngModel)]="from" class="form-control">
</div>
<div class="form-group">
  <label>To: </label>
  <input name="to" [(ngModel)]="to" class="form-control">
</div>
<div class="form-group">
  <button class="btn btn-default" (click)="search()" [disabled]="!from || !to">Suchen</button>
</div>

<table class="table table-striped">
  <tr *ngFor="let f of flights">
    <td>{{f.id}}</td>
    <td>{{f.from}}</td>
    <td>{{f.to}}</td>
    <td>{{ f.date | date:'dd.MM.yyyy HH:mm' }}</td>
  </tr>
</table>

 

Schreibweise Beschreibung
[disabled] Eckige Klammern definieren ein Property Binding. Dabei handelt es sich um ein One-Way-Binding, das Daten aus der Komponente in die angegebene DOM-Eigenschaft übernimmt.
{{f.from}} Spezielle Art eines Property Bindings, das die definierte Eigenschaft in die Seite schreibt.
(click) Runde Klammern definieren ein Event Binding, das eine Methode der Komponente an ein DOM-Event bindet.
[(ngModel)] Die Kombination von eckigen und runden Klammern definiert ein Two-Way-Binding, bei dem Daten von der Komponente in die View sowie bei einer Änderung durch den Benutzer von der View zurück in die Komponente fließen. Bei ngModel handelt es sich um eine Erweiterung von Angular, die sich um die Verknüpfung mit Eingabefeldern kümmert.
*ngFor Ein Sternchen, wie es bei ngFor zum Einsatz kommt, definiert ein Template. Das sind HTML-Fragmente, die Angular zunächst gar nicht und bei Bedarf einmal oder mehrfach rendert.

Tabelle 1: Datenbindungsausdrücke für Templates

 

Damit Angular die FlightSearchComponent anzeigt, ist sie in der Datei app.component.html – dem Template der AppComponent – zu referenzieren. Dazu kommt ein Element zum Einsatz, das dem Selektor der FlightSearchComponent entspricht:

 

<div class="container">
  <h1>Flight App</h1>
  <flight-search></flight-search>
</div>

Anwendung ausführen und bereitstellen

Um die Anwendung auszuführen, reicht ein Aufruf von ng serve im Projektverzeichnis. Daraufhin generiert das CLI Bundles für den Programmcode. Im Zuge dessen kompiliert es auch TypeScript nach EcmaScript 5 – also handelsübliches JavaScript, das in jedem Browser läuft. Zusätzlich startet das CLI einen Webserver, der seine Dienste über http://localhost:4200 zur Verfügung steht. Über diese Adresse lässt sich die Anwendung mit einem Browser aufrufen. Bei jeder Änderung am Programmcode generiert das CLI die Bundles neu und aktualisiert das Browserfenster.

Einen Build für die Bereitstellung in einer Produktivumgebung erzeugt das CLI nach einem Aufruf von

 

ng build --prod

 

Dabei minifiziert das CLI die Bundles und hinterlegt sie gemeinsam mit weiteren für die Ausführung benötigten Dateien im Ordner dist.

Statische Quellcodeanalyse

Zur Sicherstellung der Quellcodequalität kommt das CLI mit einer Unterstützung für TSLint [5] und codelyze. Ersteres prüft TypeScript-Dateien auf vordefinierte Konventionen; Letzteres macht dasselbe für Angular-Konstrukte, wie Komponenten oder Services. Als Basis für diese Prüfung stützt sich codelyze auf den Style Guide aus der Dokumentation für Angular [6]. Um mit diesen Werkzeugen eine statische Quellcodeanalyse auszuführen, ist lediglich ng lint aufzurufen. Im hier betrachteten Fall fördert die Analyse die in Abbildung 4 gezeigten Probleme zutage.

steyer_cli_4

Abb. 4: Beispielanwendung

 

Die erste Zeile prangert das if ohne geschweifte Klammern in der FlightSearchComponent an. Die zweite Zeile bemängelt, dass der Selektor der Komponente kein anwendungsspezifisches Präfix aufweist. Der Style Guide empfiehlt es zur Vermeidung von Namenskonflikten. Standardmäßig geht das CLI vom Präfix app aus. Demnach müsste der Selektor für die FlightSearchComponent auf app-flight-search und nicht auf flight-search lauten. Wer ein anderes Präfix nutzen möchte, kann dies in der Datei angular-cli.json konfigurieren.

Anwendung testen

Wie oben schon erwähnt, richtet das CLI auch ein Grundgerüst für Unit-Tests ein. Dieses basiert auf dem populären JavaScript-Testing-Framework Jasmine [7].

Eine ausgebaute Variante des Grundgerüsts zum Testen der FlightSearchComponent findet sich in Listing 5. Nach zahlreichen Imports definiert es eine Klasse FlightServiceMock. Dabei handelt es sich um eine Testattrappe für den FlightService, die zum Testen der FlightSearchComponent den Zugriff auf das Web-API simuliert und ein hartkodiertes Flug-Array mit einem Flug retourniert. Dieses Array schachtelt es in einem weiteren, das Observable.from in ein Observable umwandelt. Das zusätzliche äußere Array ist notwendig, da ein Observable im Laufe der Zeit auch mehrere Objekte veröffentlichen kann.

Danach definiert das betrachtete Beispiel mit describe eine Testsuite und spendiert ihr mit der Methode it zwei Testfälle. Zusätzlich definiert es mit beforeEach eine Methode, die Jasmine zur Vorbereitung vor jedem einzelnen Testfall ausführt.

 

import { FlightService } from './../shared/flight.service';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { CommonModule} from '@angular/common';
import { TestBed, async } from '@angular/core/testing';
import { FlightSearchComponent } from './flight-search.component';
import {Observable} from 'rxjs';

class FlightServiceMock {
  find(von, nach) {
    let result = [[{ id: 1, from: 'Graz', to: 'Hamburg', date: '2017-01-01' }]];
      return Observable.from(result);
  }
}

describe('Component: FlightSearch', () => {

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpModule, FormsModule, CommonModule],
      declarations: [FlightSearchComponent],
      providers: [
        {provide: FlightService, useClass: FlightServiceMock}
      ]
    });
  });

  it('does not load flights without parameter', () => {
    let flightSearch = TestBed.createComponent(FlightSearchComponent);
    flightSearch.componentInstance.from = '';
    flightSearch.componentInstance.to = '';
    flightSearch.componentInstance.search();
    expect(flightSearch.componentInstance.flights.length).toBe(0);
  });

  it('loads flights with parameter', () => {
    let flightSearch = TestBed.createComponent(FlightSearchComponent);
    flightSearch.componentInstance.from = 'Graz';
    flightSearch.componentInstance.to = 'Hamburg';
    flightSearch.componentInstance.search();
    expect(flightSearch.componentInstance.flights.length).toBe(1);
  });
});

 

Die Methode beforeEach konfiguriert das TestBed von Angular. Dabei handelt es sich um eine Klasse, die das Testen von Angular-Konstrukten unterstützt. Dazu definiert es ein Testmodul, das ein paar Standardmodule von Angular importiert und die zu testende FlightSearchComponent deklariert. Interessant ist hier der Eintrag providers. Er definiert, dass Angular anstatt des eigentlichen FlightService die Attrappe FlightServiceMock nutzen soll. Somit erhält das Konstruktorargument der FlightSearchComponent im Rahmen der Tests einen FlightServiceMock übergeben.

Die beiden Testfälle gestalten sich einfach: Sie erzeugen jeweils eine Instanz der FlightSearchComponent und prüfen, ob das Suchen nach Flügen mit bzw. ohne die Suchparameter from und to erlaubt ist. Der erste Testfall geht davon aus, dass die Komponente aufgrund der fehlenden Parameter keine Flüge anfordert. Der zweite geht davon aus, dass die Komponente mit dem konfigurierten FlightService nach Flügen sucht. Da es sich dabei um den FlightServiceMock handelt, ist mit einem gefundenen Flug zu rechnen.

Um die Testfälle auszuführen, reicht ein Aufruf von ng test. Das CLI führt die Testfälle mit dem Werkzeug Karma [8] aus. Da es sich dabei um ein Kommandozeilenwerkzeug handelt, lässt es sich auch einfach in einen CI-Prozess einbinden. Die Ergebnisse der Tests finden sich zunächst auf der Konsole. Allerdings kann Karma über die Datei karma.conf.js angewiesen werden, Testergebnisse in Dateien zu sammeln. Hierfür steht eine Vielzahl so genannter Reporter zur Verfügung, die die Testergebnisse zum Beispiel in Form XML oder HTML bereitstellen. Das CLI konfiguriert in der hier betrachteten Version einen Reporter, der mit dem Werkzeug Istanbul [9] die Testabdeckung des Projekts ermittelt und in einer HTML-Datei protokolliert. Diese findet sich im Ordner coverage (Abb. 5).

steyer_cli_5

Abb. 5: Testabdeckung

 

End-2-End-Tests

Auch für End-2-End-Tests bietet das CLI eine Unterstützung. Dabei handelt es sich um Tests, die den Browser fernsteuern und Benutzereingaben simulieren. Für die Ausführung solcher Tests stützt sich das CLI auf das Werkzeug Protractor [10], das auch aus dem Angular-Team stammt. Die generierten Grundgerüste sehen den Einsatz des Page-Object-Patterns vor. Dieses repräsentiert eine zu testende Seite mit einem Objekt, das Elemente aus der Seite ausliest bzw. Eingaben simuliert.

Listing 6 zeigt die Umsetzung eines Page Objects für die hier betrachtete Anwendung. Es handelt sich dabei um eine Erweiterung des Grundgerüsts, das das CLI unter e2e/app.po.ts zur Verfügung gestellt hat. Die eingerichteten Methoden steuern das Verhalten des Browsers, fragen Elemente auf der Seite ab und simulieren Benutzereingaben. Das dazu verwendete browser-Objekt sowie die beiden eingesetzten Funktionen element und by zum Abfragen von Elementen stellt Protractor zur Verfügung.

 

import { browser, element, by } from 'protractor';

export class FlightAppPage {
  navigateTo() {
    return browser.get('/');
  }

  setParameter(from: string, to: string) {
    element(by.name('from')).clear();
    element(by.name('from')).sendKeys(from);
    element(by.name('to')).clear();
    element(by.name('to')).sendKeys(to);
  }

  search() {
    element(by.tagName('button')).click();
  }

  getFlightCount() {
    return element.all(by.tagName('tr')).count();
  }
}

 

Einen darauf aufbauenden End-2-End-Test, der die von dem CLI generierte Datei e2e/app.po.ts erweitert, findet sich in Listing 7. Er simuliert einen Benutzer, der Flüge von Graz nach Hamburg sucht und prüft, ob dabei drei Flüge gefunden werden.

import { FlightAppPage } from './app.po';

describe('flight-app App', function() {
  let page: FlightAppPage;

  beforeEach(() => {
    page = new FlightAppPage();
  });

  it('should display message saying app works', () => {
    page.navigateTo();
    page.setParameter('Hamburg', 'Graz');
    page.search();
    
    let count = page.getFlightCount();
    expect(count).toBe(3);
  });
});

 

Um alle End-2-End-Tests anzustoßen, kommt folgender Aufruf zum Einsatz: ng e2e.

Fazit

Das Angular-CLI generiert ein gutes Grundgerüst für eine eigene Angular-Anwendung. Im Zuge dessen richtet es einen Build-Vorgang ein und kümmert sich um die Integration von Werkzeugen zur Quellcodeanalyse und fürs Testing. Zusätzlich stellt es Grundgerüste für Angular-Konstrukte, wie Komponenten oder Services, zur Verfügung. Hiermit entlastet es das Entwicklungsteam von lästigen und häufig auch langwierigen initialen Aufgaben.

Auch wenn Angular beim Verfassen dieses Texts als finale Version vorlag, war das CLI noch immer in der Betaphase. Eine finale Version ist laut Aussagen des CLI-Teams frühestens im ersten Quartal 2017 zu erwarten. Obwohl die betrachtete Betaversion bereits auf Webpack basiert, gestaltet sich der Build noch etwas träge, sodass Entwickler mehrere Sekunden warten müssen, um Änderungen in Aktion zu sehen. Auch das Aufsplitten auf mehrere Bundles unterstützt das CLI derzeit nicht.

Aus diesen Gründen empfiehlt es sich derzeit, bei großen Projekten auf Seed-Projekte [11], wie das offizielle aus dem Angular-Team, zu setzen und sich zusätzlich mit Build-Lösungen wie Webpack zu beschäftigen. Zusätzlich empfiehlt es sich, das CLI im Auge zu behalten, denn es wird im Laufe der nächsten Zeit weitere Möglichkeiten und Performanceverbesserungen erhalten und bietet auch eine offizielle Lösung für das Projekt-Set-up.

Geschrieben von
Manfred Steyer
Manfred Steyer
Manfred Steyer ist selbstständiger Trainer und Berater mit Fokus auf Angular 2. In seinem aktuellen Buch "AngularJS: Moderne Webanwendungen und Single Page Applications mit JavaScript" behandelt er die vielen Seiten des populären JavaScript-Frameworks aus der Feder von Google. Web: www.softwarearchitekt.at
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.