Drei neue Tools im Überblick: gulp, Bower und npm

Visual Studio lernt neue Tricks für Webentwicklung
Kommentare

Für Webentwicklung auf der Microsoft-Plattform gibt es im Moment sehr viel Neues zu lernen. Nicht nur, dass ASP.NET 5 und die CoreCLR einige grundlegende Änderungen bringen, die gesamte Toolsammlung für Webentwicklung ist nicht mehr wiederzuerkennen.

Microsoft wendet sich verstärkt bestehenden plattformunabhängigen Tools aus der Open- Source-Welt zu und integriert sie in die kommende Visual-Studio-Version. Das Ergebnis ist eine Vielzahl an neuen Werkzeugen, die auf den ersten Blick verwirrend wirkt. In diesem Artikel bringen wir etwas Ordnung ins Chaos, indem wir uns drei der Tools ansehen, die für die Visual-Studio-Webentwicklung neu sind: gulp, Bower und npm.

Microsoft brachte mit Visual Studio in der Vergangenheit alles mit, was man für Webentwicklung brauchte. Dazu gehören unter anderem ein Build-System (MSBuild) und ein Paketmanager (NuGet). MSBuild und NuGet sind jedoch nur bedingt für moderne Webentwicklung geeignet. Einige Gründe dafür sind:

• Sie sind in einer Zeit entstanden, in der Single Page Applications (SPA) die Ausnahme waren. Dementsprechend sind sie nicht dafür optimiert.
• Viele Webentwickler bevorzugen Linux oder Mac OS. MSBuild und NuGet sind jedoch nur auf Windows verfügbar.
• Mit Visual Studio profitierte man bisher nicht von den Innovationen in Sachen Webentwicklung, die außerhalb des „Microsoft-Universums“ entstanden sind.

Die neue Microsoft-Strategie

Solche Gründe plus der generelle Fokus von Microsoft in Sachen Open Source haben dazu geführt, dass Microsoft seine Strategie in Sachen Webentwicklungstools angepasst hat. Einige der neuen Grundpfeiler sind:

  • Wenn ein gutes etabliertes Open-Source-Tool existiert, wird es integriert, anstatt das Rad nochmals zu erfinden.
  • Entwicklerinnen und Entwickler sollen die freie Wahl der Tools haben, anstatt dass Microsoft ein (hauseigenes) Tool vorschreibt.
  • Visual Studio kämpft nicht gegen verbreitete Open-Source-Tools, sondern integriert sie, damit man in Visual Studio das Beste aus beiden Welten bekommt: die gute und ausgereifte IDE und die mächtigen Tools aus der Open-Source-Webentwicklungswelt.

Node.js als Fundament

Node.js (kurz node) spielt eine wichtige Rolle für die Webentwicklungstools, die in diesem Artikel vorgestellt werden. Es handelt sich um eine JavaScript-Ausführungsumgebung, die auf der JavaScript Engine von Google Chrome (V8) aufbaut. Sie erlaubt das Ausführen von JavaScript-Code außerhalb des Browsers auf Windows, Linux und Mac OS. Damit lassen sich sowohl Serveranwendungen als auch Kommandozeilenwerkzeuge plattformunabhängig entwickeln. Node.js eignet sich daher hervorragend als Grundlage für Entwicklungstools. Es ist daher die Basis für gulp und Bower. Selbst Microsoft setzt mittlerweile nicht mehr nur auf PowerShell, sondern entwickelt ebenfalls plattformunabhängige Tools mit Node.js. Ein Beispiel dafür ist, das Cross-Platform Command Line Interface für Microsoft Azure, kurz XplatCLI.

Node Package Manager (npm)

Node.js installiert man unter Windows über ein MSI-Paket, das hier heruntergeladen werden kann. Unter Linux verwendet man einen Paketmanager wie APT(z. B. unter Ubuntu sudo apt-get install nodejs). Node.js bringt seinen eigenen Paketmanager mit, den Node Package Manager, kurz npm. Er wird verwendet, um Node.js-Module und Kommandozeilentools zu installieren. Das Verzeichnis der über npm verfügbaren Pakete ist mit über 160 000 riesig. Auch die Zahl von über 1,6 Milliarden Paketdownloads im Juni 2015 zeigt, wie verbreitet npm mittlerweile ist. Das sind in einem Monat mehr als drei Mal so viele Paketdownloads wie NuGet während seiner gesamten bisherigen Geschichte zu bewältigen hatte.

In diesem Artikel beschäftigen wir uns mit den Tools gulp und Bower. Um sie zu installieren, geht man wie folgt vor:

  1. Stellen Sie sicher, dass Node.js und npm installiert sind. Wenn Sie Visual Studio 2015 auf Ihrem System haben, sind Node.js und npm wahrscheinlich schon vorhanden. Falls Sie nicht sicher sind, öffnen Sie ein Kommandozeilenfenster und starten Sie node -v und npm -v. Beide Kommandos müssten die jeweiligen Versionsnummern ausgeben, wenn die Tools installiert sind.
  2. Installieren Sie mithilfe von npm die Tools gulp und Bower global, damit Sie die Tools von jedem Verzeichnis aus aufrufen können. Die entsprechenden Kommandos lauten npm install -g gulp und npm install -g bower.
  3. Wechseln Sie in das Projektverzeichnis.
  4. Erstellen Sie eine npm-Konfigurationsdatei (package.json). Das geschieht mit dem Kommando npm init. In package.json werden verschiedene Aspekte Ihres Programms wie Name, Version, Lizenz etc. beschrieben. Für diesen Artikel ist der Abschnitt devDependencies relevant (Abb. 2). Dort müssen wir eine Abhängigkeit auf gulp und später auch auf nützliche gulp-Erweiterungen eintragen. Das geschieht mit dem Kommando npm install gulp –save-dev. Achten Sie hier besonders auf die Option –save-dev. Sie sorgt für den Eintrag der Abhängigkeit in package.json. Ohne diese Option würde die jeweilige Komponente zwar installiert, es würde jedoch ein Eintrag in der npm-Konfigurationsdatei vorgenommen.

Der Vorteil von devDependencies in package.json zeigt sich bei bestehenden Projekten. Man muss nicht auf jedem neuen Computer alle Abhängigkeiten mit npm einzeln installieren. Ein einziger Aufruf von npm install ohne Parameter genügt und npm installiert alle in package.json referenzierten Abhängigkeiten. In unserem Fall ist das gulp mit den zugehörigen Modulen.

Visual Studio 2015 unterstützt npm und package.json in Webprojekten von Haus aus. Abbildung 1 zeigt, wie man package.json anlegt. In Abbildung 2 sieht man, dass Microsoft npm tief in Visual Studio 2015 integriert hat. Man bekommt IntelliSense mit Livezugriff auf das Onlinepaketverzeichnis von npm, Kontextmenüs zum Wiederherstellen von Paketen (npm install), u. v. m. Visual Studio ändert nichts daran, dass npm alle Dateien im Unterverzeichnis node_modules ablegt. Es wird in der Visual-Studio-Solution nicht als Ordner angezeigt, da Visual Studio weiß, dass darin nur die Ergebnisse von npm enthalten sind.

 

Abb. 1: Anlegen einer npm-Konfigurationsdatei in Visual Studio 2015

Abb. 1: Anlegen einer npm-Konfigurationsdatei in Visual Studio 2015

 

Abb. 2: npm-Unterstützung in Visual Studio 2015

Abb. 2: npm-Unterstützung in Visual Studio 2015

Bower: Package Manager für Webentwicklung

Jedes nicht triviale Webprojekt braucht heutzutage eine Vielzahl an Frameworks und Tools. Bower ist ein Paketmanager, der darauf spezialisiert ist, den Download dieser Komponenten zu automatisieren. Als jemand, der von Visual Studio gewohnt ist, alles aus einer Hand zu bekommen, fragt man sich vielleicht, wozu noch ein Package Manager? Sind npm für Node.js und NuGet für .NET nicht genug? Dazu kommt, dass Frameworks wie das populäre AngularJS 1.4 über alle drei Kanäle, also npm, Bower und NuGet erhältlich sind. Wann also was verwenden? Hier meine Empfehlungen für Webentwicklung mit ASP.NET 5:

  • NuGet sollten Sie nur für .NET Komponenten verwenden. Sie verwalten damit also Ihre serverseitigen Abhängigkeiten.
  • npm verwenden Sie für Entwicklungstools, die auf Node.js basieren. Falls Sie anstelle von ASP.NET serverseitig Node.js verwenden, ersetzt npm natürlich NuGet für Ihren serverseitigen Code.

Für clientseitige Komponenten wie AngularJS oder Bootstrap haben Sie die Wahl zwischen Bower und npm. Die meisten populären Frameworks publizieren über beide Kanäle. Vermeiden Sie die Verwendung von NuGet für clientseitige Komponenten, auch wenn diese dort verfügbar sind. Es handelt sich in der Regel nicht um Pakete, die offiziell unterstützt sind und aktuell gehalten werden. Konzeptionell ist das Verwalten von Abhängigkeiten bei Bower ähnlich wie bei npm:

  • Die Installation von Komponenten erfolgt mit dem Kommando bower install.
  • Abhängigkeiten können in einer JSON-Konfigurationsdatei bower.json gespeichert werden. Sie wird mit bower init angelegt.
  • Möchte man eine Komponente installieren und die entsprechende Abhängigkeit auch in bower.json hinzufügen, verwendet man bower install <Komponente> –save.

Microsoft hat auch Bower in Visual Studio 2015 integriert. Abbildung 3 zeigt IntelliSense und die Bower-Einbindung in die Visual Studio Solution. Ähnlich wie node_modules bei npm gibt es auch bei Bower ein Verzeichnis, in dem alle installierten Komponenten gespeichert sind, das in der Solution aber nicht angezeigt wird: bower_components.

 

Abb. 3: Bower-Unterstützung in Visual Studio 2015

Abb. 3: Bower-Unterstützung in Visual Studio 2015

gulp: Build-System für den Clientcode

Je größer ein Webprojekt wird, desto dringender braucht man ein Build-System, das die Schritte automatisiert, die zur Erstellung einer installierbaren Version notwendig sind. Hier einige Beispiele für Aufgaben, die im Rahmen des Build-Prozesses für clientseitigen Code bei Webprojekten notwendig sind. Die Liste ist keinesfalls komplett, schließlich enthält die Liste an gulp-Plug-ins mittlerweile über 1 500 Einträge.

  • Umwandeln von SASS in CSS
  • Übersetzen von Sprachen wie TypeScript oder CoffeeScript in JavaScript
  • Minification als das Verkleinern von JavaScript auf das absolut Notwendige, um die Ladezeit von Webseiten zu verkürzen
  • Komprimieren von Bildern
  • Zusammenhängen (Concat), um die Anzahl an JavaScript- oder CSS-Dateien zu reduzieren und die Webseite so schneller zu machen
  • Ausführen von Tests (z. B. Jasmine)
  • Git Repository verwalten (z. B. für automatisiertes Deployment)

Natürlich könnte man all diese Aufgaben manuell durchführen. Solche manuellen Prozesse sind jedoch fehleranfällig. Speziell bei größeren Webprojekten in Teams ist Automatisierung wichtig, damit jedes Teammitglied ohne hohen Lernaufwand das Projekt bauen und veröffentlichen kann. Mit gulp kann man den Build-Prozess automatisieren.

gulp baut auf Node.js und npm auf. Im Gegensatz zu Grunt, einem ebenfalls beliebten und weit verbreiteten Tool zur Automatisierung von Build-Prozessen in Webprojekten, wird in gulp der Prozess mit Node.js und JavaScript programmiert, nicht konfiguriert (Code-over-Configuration-Konzept). Grundwissen über Node.js und JavaScript werden bei der Verwendung von gulp daher vorausgesetzt.

gulp verwendet Node.js-Streams. Ausgangspunkt sind Dateien (z. B. TypeScript, SASS, Bilder, JavaScript). Über Streams und Pipes wird der Inhalt der Dateien mithilfe von Plug-ins verarbeitet (z. B. übersetzt oder verkleinert). Am Ende wird das Ergebnis wieder in Dateien geschrieben. Ein Grundprinzip dabei ist, dass jedes Plug-in eine einzelne Aufgabe übernimmt. Ein Plug-in zu schreiben, das in einem Schritt kompiliert, minifiziert und verkettet, wäre gegen die Grundidee von gulp.

Aufbau eines gulpfiles

Listing 1 zeigt ein Beispiel für ein gulpfile. Aus Gründen der besseren Lesbarkeit ist es nicht komplett. Interessierte Leser finden den kompletten Code hier. Das gulpfile besteht auf folgenden Teilen:

  • Zu Beginn werden gulp und zugehörige Plug-ins inkludiert. gulp-Plug-ins sind nichts anderes als kleine Node.js-Programme, daher werden sie mit require
  • Im gulpfile werden an vielen Stellen Dateien referenziert. In dem Beispiel in Listing 1 werden daher Hilfsvariablen am Beginn angelegt, die die Dateinamen bzw. Suchmuster (z. B. wwwroot/**/*.ts) enthalten.
  • gulp.task() legt die Aufgaben fest, die gulp im jeweiligen Projekt durchzuführen hat. Der erste Parameter ist der Name des Tasks, der zweite die Funktion, die die Aufgabe repräsentiert.
  • gulp.src())legt die Quelldateien fest. Als Parameter wird entweder ein einzelner String oder ein Feld von Strings übergeben.
  • Mit gulp.pipe() werden die Quellen mit Plug-ins und mit dem Ziel (gulp.dest) verknüpft.
  • Über gulp.dest() bestimmt man, wohin gulp das Ergebnis schreiben soll.
  • gulp.watch() ermöglicht es, dass man gulp in einem eigenen Prozess dauerhaft laufen lässt. Wenn sich eine der referenzierten Dateien ändert, wird automatisch die entsprechende Task gestartet.
  • gulp.parallel() und gulp.series() werden in diesem Artikel nicht näher behandelt. Damit könnte man bestimmen, welche Schritte parallel und welche nacheinander auszuführen sind.

Listing 1: gulpfile

/// 

// Include all the necessary plugins
var gulp = require("gulp");
var concat = require("gulp-concat");
var uglify = require("gulp-uglify");
...

// Helper arrays holding file and folder names for later use in this gruntfile
// External script dependencies
var dependencyScripts = ["bower_components/jquery/dist/jquery.js", 
  "bower_components/angularjs/angular.js", ... ];
// External style dependencies
var dependencyStylesheets = ["bower_components/angular-ui-grid/ui-grid.css", 
  "bower_components/bootstrap/dist/css/bootstrap.css", ... ];
// External font dependencies
var bootstrapFonts = ["bower_components/bootstrap/dist/fonts/*.*"];
// Stylesheet for this application
var customStylesheets = ["wwwroot/components/styles/styles.scss"];
// TypeScript sources
var typescriptFiles = ["wwwroot/**/*.ts"];

// Delete build targets to clean up
gulp.task("clean", function () {
  del.sync(["wwwroot/scripts/**/*.*"]);
  del.sync(["wwwroot/styles/*.*"]);
  ...
});

// Combine and minify all external scripts
gulp.task("dependencyScriptsAndStyles", [], function () {
  // External scripts
  gulp.src(dependencyScripts)
    .pipe(newer("wwwroot/scripts/dependencies.min.js"))
    .pipe(uglify())
    .pipe(concat("dependencies.min.js"))
    .pipe(gulp.dest("wwwroot/scripts/"));

  // External styles
  gulp.src(dependencyStylesheets)
    .pipe(newer("wwwroot/styles/dependencies.min.css"))
    .pipe(minifycss())
    .pipe(concat("dependencies.min.css"))
    .pipe(gulp.dest("wwwroot/styles/"));
  ...
});

// Process SASS sources and generate CSS
gulp.task("sass", [], function () {
  var sassSettings = { sourcemap: true,
    sourcemapPath: "wwwroot/components/styles" };

  // Generate minified CSS version
  gulp.src(customStylesheets)
    .pipe(newer("wwwroot/styles/styles.min.css"))
    .pipe(sass(sassSettings))
    .pipe(minifycss())
    .pipe(concat("styles.min.css"))
    .pipe(gulp.dest("wwwroot/styles/"));
  ...
});

// Process TypeScript files
gulp.task("typescript", [], function () {
  return gulp.src(typescriptFiles)
    .pipe(newer("wwwroot/scripts/application.js"))
    .pipe(sourcemaps.init())
    .pipe(ts({
      noImplicitAny: true,
      out: "application.js"
    }))
    .pipe(sourcemaps.write("./maps"))
    .pipe(gulp.dest("wwwroot/scripts"));
});

// Watch tasks for SASS and TypeScript sources
gulp.task("sass:watch", function () {
  gulp.watch("styles/*.scss", ["sass"]);
});
gulp.task("typescript:watch", function () {
  gulp.watch(["wwwroot/*.ts", "wwwroot/**/*.ts"], ["typescript"]);
});

// Set a default tasks
gulp.task("default", ["clean", "sass", "typescript", 
  "dependencyScriptsAndStyles"], function () { });
end

gulp in Visual Studio 2015

Visual Studio hat in der Version 2015 ein neues Fenster dazu bekommen: Den Task Runner Explorer. Dort klinkt sich die neue gulp-Integration von Visual Studio ein. Abbildung 4 zeigt den Task Runner Explorer mit dem gulpfile aus Listing 1. Der Task Runner Explorer steht übrigens zur nachträglichen Installation auch für Visual Studio 2013 Update 3 zur Verfügung.

Abb. 4: gulp-Unterstützung in Visual Studio 2015

Abb. 4: gulp-Unterstützung in Visual Studio 2015

Besonders beachtenswert sind die Bindings. Man kann gulp-Tasks mit Events wie Before Build oder Project Open verknüpfen. Technisch werden diese Bindings als Kommentare im gulpfile vermerkt (Listing 1, Zeile 1). Bindet man gulp.watch an Project Open, dann startet Visual Studio die entsprechenden Watch-Prozesse automatisch beim Laden des Projekts im Hintergrund. Die Ausgaben sieht man im oben schon erwähnten Task Runner Explorer. Abbildung 5 zeigt einen solchen Prozess (typescript:watch aus Listing 1).

Abb. 5: Gulp-Watch-Prozess in Visual Studio 2015

Abb. 5: Gulp-Watch-Prozess in Visual Studio 2015

Fazit: Es gibt Vor- und Nachteile

Die Änderungen bei der Webentwicklung bringen eine Menge Vor-, aber auch einige Nachteile. Wenn Sie gewohnt sind, dass Visual Studio ein „one stop shop“ ist und alle notwendigen Tools enthält, erscheint Ihnen die Fülle an neuen Tools womöglich unnötig komplex und verwirrend. Personen mit .NET-Hintergrund fragen sich vielleicht, wozu sie sich mit Node.js und JavaScript herumplagen müssen, obwohl sie eigentlich nur C# verwenden möchten. Entwickler, die nur selten Webprojekte machen, haben es durch die Menge an Möglichkeiten und Tools schwer, von Anfang an produktiv zu arbeiten. Sie müssen Zeit zum Aufsetzen der Projektumgebung einplanen.

Nimmt man sich jedoch die Zeit, die neuen Werkzeuge etwas kennenzulernen, erkennt man rasch das Potenzial. Die Communitys, die hinter Node.js, npm, Bower, gulp und Co. stecken, sind sehr innovativ. Durch den Schwenk von Microsoft profitieren wir jetzt in Visual Studio endlich auch davon.

Plattformunabhängigkeit ist ein zweiter Gewinn, der für die neue Welt spricht. Windows und Linux sind schon lange keine Gegensätze mehr. In vielen Unternehmen existieren sie nebeneinander. Man nimmt das System, das für die jeweilige Aufgabe am besten geeignet ist. Viele Entwickler bevorzugen im Bereich der Webentwicklung Linux und Mac OS. Durch die neuen Tools sind verschiedene Plattformen im selben Team möglich.

Microsoft macht den Einstieg und die Verwendung der neuen Tools darüber hinaus durch Integration in das Visual-Studio-UI relativ leicht. In dieser Hinsicht stehen wir erst am Anfang. Es ist zu erwarten, dass die Integration im Lauf der Zeit noch besser wird als sie heute schon ist.

Aufmacherbild: web development via Shutterstock.com / Urheberrecht: Sabelskaya

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -