Schlagwort-Archive: webpack

Angular 2 mit webpack 2 mit ts, less, sass Loader für Anfänger in Visual Studio 2015 (Webpack Version – Beta 27)


Wäre die Welt nicht schön, wenn man sich nur mit Angular 2 beschäftigen könnte und nicht noch über das Deployment für den Live Betrieb nachdenken muss. Denn dann wäre die Standardinstallation von Angular 2 mit SystemJs völlig ausreichend. Wenn man allerdings seine erste kleine Angular 2 Anwendung erstellt hat, dann merkt man schnell das man sich noch mit dem Live Deployment beschäftigen muss. Denn wenn man die Anwendung startet dann dauert es bis zu 300++ Requests bevor die Seite komplett geladen ist und das ist nicht für Live geeignet.

Da ich bisher nur Angular 1 Seiten mit ASP.NET MVC umgesetzt habe, hatte ich bisher auch nicht viel Kontakt mit “import” Statements, gulp, grunt, webpack oder SystemJs – denn das hat bei Angular 1 alles Visual Studio für mich übernommen.

Jetzt stellte sich mir die Frage warum und weshalb brauche ich diesen neumodischen Kram eigentlich?

Bei Angular 2 kann ich hier leider nicht mehr auf Visual Studio zurückgreifen. Denn bei einer Umsetzung z.B. mit webpack muss klar unterscheiden zwischen dem Ordner “App” in dem wir die Anwendung schreiben (unsere TypeScript Dateien und HTML Templates liegen) und einem Ordner “wwwroot” in dem die “kompilierte” Anwendung (JavaScript Dateien) abgelegt wird, wenn diese fertig kompiliert wurde. Der Webserver ruft dann die “index.html” aus dem “wwwroot” Ordner auf.

Aber wie kompiliert man aus TypeScript Dateien, Less, Sass und HTML Templates eine richtige JavaScript Anwendung?

Mit SystemJs

Im Standardbeispiel von Angular 2 ist dies einfach gelöst, es gibt zum einen das direkte Übersetzen der TypeScript Dateien in JavaScript beim Speichern und SystemJs kümmert sich dann mit Hilfe der “systemjs.config.js” das alle passenden Dateien zur Laufzeit ausliefert werden und die Styles sind im besten Fall direkt auf der Seite eingebunden (300+ Requests).

Daher muss man sich um ein passendes “Bundling” der Dateien kümmern und dafür gibt es mehrere Möglichkeiten. Zum einen kann man gulp und grunt verwenden und die passenden Deployscripte schreiben oder man verwendet npm Scripts mit webpack 2 und schreibt dafür die Deployscripte. Ich habe mich für die zweite Variante entschieden, da es sich dabei aktuell wohl um die bevorzugte Variante zum Bereitstellen von Angular 2 handelt und da es auf der Angular 2 Seite zumindest ein Beispiel für die Umsetzung mit webpack 1 gibt. Ich beziehe mich aber im meinem Blogpost auf die aktuelle Variante webpack Beta 27.

Hinweis zu “npm Scripts”: In der “package.json” in der alle abhängigen npm Pakete für das Projekt angegeben sind, gibt es auch noch die Möglichkeit Kommandozeilen Befehle für npm abzulegen die mit “npm run <scriptname>” ausgeführt werden können, im folgenden Beispiel z.B. “npm run start” wird das “start” Script ausgeführt.

Mit webpack

Also was macht webpack eigentlich und wie funktioniert das ganze dann?

Wenn man webpack verwendet, gibt es wie schon beschrieben ein Verzeichnis in dem man seinen Quellcode hat z.B. “App” hier liegen alle TypeScript Dateien und HTML Templates. Auch unsere “index.html” in dieser sind weder styles noch script Tags enthalten, all das fügt webpack später beim Buildprozess automatisch in die “index.html” ein.

image

Und dann gibt es noch ein Verzeichnis für die Kompilierten Dateien  z.B. “wwwroot” hier liegen dann alle übersetzten und zusammengefassten JavaScript Dateien und Styles – der Ordner wird NICHT mit in die Quellcodeverwaltung eingecheckt.

image

Webpack kümmert sich dann um “alles” d.h. aufgrund der “import” Anweisungen in unseren Dateien weiß webpack genau welche Dateien wir alle benötigen und welche in einer Datei zusammengefasst werden sollen.

Webpack im “Detail”

Für die Implementierung von Angular 2 mit webpack 2 gibt es ein sehr gutes Github repository an dem ich mich orientiert habe. Im Folgenden gehe ich daher nicht auf alle Details ein, sondern beschreibe eher die Probleme auf die ich gestoßen bin. Diese könnt Ihr z.B. oft in den Kommentaren der Quellcode Dateien nachlesen.

Für Visual Studio gibt es eine sehr gute Task Runner Extension für webpack, mit dieser kann man die webpack Tasks direkt in Visual Studio starten vom einfachen Build bis hin zum Webpackserver (dazu weiter unten mehr) und man muss nicht immer eine npm Konsole öffnen.

Allgemeine “App” Einstellungen

Damit nicht der komplette JavaScript Code in einer Datei landet, splittet man diese am besten auf:

  • polyfills.ts – damit die Anwendung auch in älteren Browsern funktioniert muss auch als erstes im Browser geladen werden
  • vendors.ts – Angular Framework und abhängige Komponenten
  • boot.ts – der Root unserer Anwendung

Ich verwende z.B. noch Twitter Bootstrap als globalen Style mit Less und evtl. noch andere Styles z.B. in Sass oder css direkt. Auch die Styles sollen von webpack übersetzt, minifiziert und in der “index.html” automatisch eingebunden werden.

Denn webpack bindet “NUR” die Dateien in den Build Prozess ein, die auch über ein “import” Statement in einer der Dateien polyfills, venders oder boot eingebunden sind oder von diesen mit “import” eingebunden werden.

Damit meine Bootstrap Styles global verfügbar sind habe ich mich für das Einbinden von bootstrap in die vendors entschieden.

Denn wenn man die Styles direkt in einer Komponente als “styleUrls” einbindet, sind diese durch Angular 2, in den Standardeinstellungen nur in der eingebundenen Komponente gültig – ViewEncapsulation.

Ausnahmen für das Einbinden nicht direkt über “import” bilden die “templateUrl” und die “styleUrls”, diese werden von den webpack Loadern erkannt und dann entsprechend geladen.

Webpack Bereitstellungsmöglichkeiten

Die Task Runner Extension für die webpack Bereitstellung in Visual Studio, kann mit einem Rechtklick auf die “webpack.config.js” mit “Taskausführungs-Explorer” geöffnet werden.

image

Es gibt verschiedene Möglichkeiten, wie man die Dateien für den “wwwroot” Ordner von webpack erstellen lassen kann.

  • Manuell, sobald man eine Änderung durchgeführt hat und diese ausprobieren möchte, kann man einfach unter “Run” sein Projekt für die passende Umgebung neu bauen lassen

image

und die Ausgabe könnte dann folgendermaßen aussehen

image

  • Oder man kann einen Watcher ausführen lassen, der das Webverzeichnis der aktuellen Anwendung überwacht und sobald Änderungen an Dateien vorgenommen wurde, wird das Paket automatisch neu gebaut, hier muss dann nur noch mit F5 der Browser aktualisiert werden um die neuen Änderungen auch zu sehen
  • Dann gibt es noch einen einfachen node.js express Webserver der die aktualisierten Dateien bereitstellen kann. Hier gibt es zwei unterschiedliche Modus um die Seite zu aktualisieren.
  • COLD – die Seite wird automatisch komplett neu geladen (wie in meinem Beispiel)
    • HOT – es werden nur die Teile ersetzt die sich geändert haben (HOT wird auch HMR genannt und steht für “Hot Module Replacement”)

Die “webpack.config.js”

Wenn man webpack einsetzt, dann muss SystemJs komplett aus dem Projekt entfernt werden, denn webpack übernimmt dann das Bereitstellen von Development Paketen und den Live (Production) Paketen.

Damit die Visual Studio Extension für webpack auch funktioniert, muss die Datei “webpack.config.js” im Root Verzeichnis der Webseite abgelegt werden.

Da es unterschiedliche Konfigurationen gibt, für Allgemeine Einstellungen, Produktionseinstellungen, Liveeinstellungen und Testeinstellungen wird die Konfiguration in mehrere Dateien aufgeteilt und in meinem Beispiel im Verzeichnis “Config” abgelegt. In der “web.config.js” wird nur ausgewertet welcher Wert als NODE_ENV übergeben wurde über den Aufruf des Kommandozeilenbefehls z.B. für development über den Webpack Taskplaner

cmd /c SET NODE_ENV=development&& webpack -d –color

und es wird dann die passende “webpack.dev.js” Datei aufgerufen.

Die jeweilige webpack Konfiguration, setzt sich dabei aus zwei Dateien zusammen, einer Datei die speziell für die jeweils aufgerufene Umgebung z.B. development (dev) => “webpack.dev.js” die Werte enthält und einer allgemeinen Konfiguration “webpack.common.js”, die für alle Bereitstellungsszenarien immer die gleichen Werte beinhaltet. Diese beiden Konfigurationsdateien werden dann mit Hilfe einer JavaScript Bibliothek von Webpack “webpackMerge” zusammengeführt.

Die “webpack.common.js”

In der Konfiguration wird angegeben welche Startdateien es gibt, in unserem Falle drei “polyfills”, “vendors” und “boot”. Dann gibt es die “module” Sektion in denen die Loader verwendet werden, die wir auch in der package.json entsprechend in den dev-dependencies angeben müssen. Da sich webpack 2 aktuell noch in einer Beta befindet, hatte ich auch entsprechende Probleme die Loader für Less und Sass zum Laufen zu bekommen (siehe Kommentar über dem jeweiligen Loader).

ACTHUNG: Bei den Style Loadern gibt es jeweils einen Loader für die „StyleUrls“ in den Componenten und dann gibt es noch einen Loader für die globalen Styles die direkt per „import“ eingebunden werden, denn beide brauchen unterschiedliche Loader. Bei den jeweiligen Loadern sind die Verzeichnise für die diese zuständig sind per „include“ und „exclude“ festgelegt.

Um die HTML Dateien kümmert sich der “angular2-template-loader” wichtig ist das diese in der “templateUrl” in der Component mit einem relativen Pfad angegeben werden und mit einem “./” starten wie z.B. “./app.component.html”. Was bedeutet die HTML Datei befindet sich im gleichen Verzeichnis wie die Komponente. Gleiches gilt für die “styleUrls”.

ACHTUNG: KEINE ES6 Anführungszeichen verwenden bei den URL Angaben, hier wird dann einfach nur der String ausgeben “./app.component.html” und NICHT das HTML Template.

Wenn ich das ganze richtig verstanden habe, dann kümmert sich der “raw-loader” um die HTML Dateien die der “angular2-template-loader” entsprechend “bereitgestellt” hat.

HINWEIS: Die HTML Dateien die in der Component angegeben werden, werden mit in die bereitgestellten JavaScript Dateien von webpack eingebettet und es gibt keine Extra Dateien dafür im Ausgabeordner. Die Styles werden dank des „ExtractTextPlugin“ in einer Extra Datei abgelegt.

Dann gibt es noch die Plugins, welche teilweise direkt von webpack bereitgestellt werden oder extra in den dev-dependencies mit angegeben werden.

Die Plugins kümmern sich z.B. darum das in der “index.html” auch die richtigen Scripte, Styles und base Url eingebunden werden (HtmlWebpackPlugin und ExtractTextPlugin). Denn im Produktionsmodus wird noch ein Hash mit an den Dateinamen der jeweiligen JavaScript oder Style Datei angefügt, damit nicht ausversehen alte Daten geladen werden. Aus diesem Grund können wir auch nicht direkt die Styles und Scripte in unserer “index.html” verlinken, sondern müssen diese von webpack einfügen lassen.

HINWEIS: Ich habe mich aktuell dazu entschieden bei den DevDependencies immer nur noch die Direkte Version zu verwenden ohne „^“ oder „~“ vor der Versionsnummer, denn wenn Ihr pech habt wie ich, dann wird z.B. TypeScript von Version 2.0.10 auf 2.1.14 angehoben und plötzlich funktioniert das Deployment nicht mehr da es Probleme mit dem „awesome-typescript-loader“ gibt. Vor allem sucht man den Fehler erst einmal bei sich selbst, bevor man daran denkt das node evtl. eine neuere Version gezogen haben könnte die nicht vollständig kompatibel zu allen anderen Paketen ist.

Die “webpack.dev.js”

Die speziellen dev Einstellungen für unsere Anwendung.

Wichtig ist hier z.B. der Wert für “output.publicPath”, denn der hier angegebene Wert wird als Basispfad vor alle Script und Style Tags in der “index.html” eingefügt. (siehe Kommentare in der beigefügten dev Konfiguration)

Daraus ergibt sich dann z.B. die folgende “wwwroot\index.html” wenn das ganze erfolgreich kompiliert wurde.

Hier kann man gut erkennen, das wir aktuell die Daten vom webpack Server holen, der auf Port 3000 lauscht, auch das können wir entsprechend in der “webpack.dev.js” einstellen.

Webpack Zusammenspiel mit Visual Studio

Ich habe zwar aktuell keine Backend Funktionen in .NET implementiert, aber Visual Studio dient aktuell nur noch als Backend um z.B. Daten aus der .NET Welt im Browser anzuzeigen. Im Development Modus laufen am Ende zwei Webserver. Einer im IIS der unsere Anwendung hostet und die “index.html” aus dem wwwroot aufruft und der webpack webserver der die aktuellen Scripte und Styles bereitstellt.

Im Zusammenspiel mit der folgenden RouteConfig

und dem einfachen HomeController für den Index Aufruf.

Wird kein “Views” Ordner mehr benötigt.

Beispiel “installieren”

  1. Webpack Taskrunner Extension für VS 2015 installieren und VS neustarten
  2. Das Projekt von GitHub laden und in VS 2015 öffnen (Achtung hier sind noch mehr Projekte enthalten, bitte darauf achten, das diese nicht mit gebaut werden sondern nur “Angular2MitWebpack2”.
  3. das Verzeichnis mit einer NPM Konsole öffnen und mit Hilfe von “npm install” alle Pakete installieren lassen
  4. Den Taskrunner öffnen und einmal das “Run – Development” ausführen lassen und danach dann “serve – Cold” starten
  5. Die Webseite starten, diese sollte jetzt funktionieren.

Quellen:

https://webpack.js.org/

https://github.com/AngularClass/angular2-webpack-starter

https://offering.solutions/articles/asp-net/how-to-set-up-angular-2-and-webpack-in-visual-studio-with-asp-net-core/