Die Automatisierung von bestimmten Workflows, d.h. von fundamentalen und immer wiederkehrenden Arbeitsschritten, ist in der Softwareentwicklung ein alter Hut. Testläufe und komplette Buildprozesse wiederholt manuell durchzuführen würde nicht nur viel Zeit in Anspruch nehmen, sondern wäre vor allem auch viel fehleranfälliger als automatisierte Verfahren. Auch in der Webentwicklung werden mittlerweile Workflows wie das Kompilieren von CSS, das Minifizieren des Source-Codes, statische Code-Analysen (Linting) und das Ausführen von Unit- und Selenuim-Tests als automatische Prozesse gestaltet.
Ich stelle im Folgenden den JavaScript-Task-Runner Grunt als adäquates Tool für die Automatisierung von Arbeitsschritten im Rahmen der Frontend-Entwicklung vor.
Die Frage nach der richtigen Technologie
Die für mich entscheidene Frage lautet in diesem Zusammenhang: Mit welcher Technologie kann eine Automatisierung am besten realisiert werden? Ob überhaupt bei der Frontend-Entwicklung bestimmte Prozesse automatisiert werden sollten steht nicht zur Diskussion. Und als Frontend-Developer beantworte ich die Frage zügig und eindeutig: Es soll JavaScript sein.
Wie lange ist es her, dass man als Frontend-Developer einfache Websites baute? Genauso selten ist es inzwischen geworden, dass man bloße HTML-Oberflächen entwickeln muss, die direkt und komplett vom Backend gesteuert werden. Stattdessen geht es bei unserer Arbeit immer häufiger um relativ komplexe Web-Applikationen, Web-Clients, die ausschließlich von JavaScript angetrieben werden und die über externe Services und APIs Datenverarbeitung betreiben – und das möglichst auf allen zur Verfügung stehenden Endgeräten.
Wenn man also heutzutage bei der Entwicklung von Web-Frontends ohnehin schon enorm viel JavaScript einsetzt, liegt es doch auf der Hand mit JavaScript auch seine Workflow-Automatisierung zu implementieren, anstatt sich deswegen zusätzliche Plattformen wie Java, Ruby oder PHP als Abhängigkeit ins (Teil-) Projekt zu holen.
Grunt – der JavaScript-Task-Runner
Das passende Werkzeug, was sich hier anbietet, ist Grunt. Grunt ist ein Task-Runner für JavaScript und erfüllt damit eine ähnliche Rolle wie Maven und Ant in Java oder Phing im PHP-Umfeld.
Grunt basiert auf Node.js. Wir reden daher im Fall von Grunt über JavaScript, dass nicht in einem Browser läuft, sondern vielmehr per Konsole auf einer Entwicklungsmaschine oder einem Server ausgeführt wird.
Neben dem eigentlichen Task-Runner besteht Grunt noch aus einem Kommando-Zeilen-Tool, der grunt-cli. Zusätzlich gibt es eine sehr große Anzahl von verschiedenen Grunt-Plugins. Teilweise werden diese Plugins durch die Entwickler von Grunt selbst zur Verfügung gestellt. Vor allem aber sind die Plugins im Rahmen der sehr großen Grunt-Community entwickelt worden und per NPM, dem Package-Manager von Node.js, abrufbar. Grunt liegt aktuell in Version 0.4.5 vor, grunt-cli in Version 0.1.13.
Installation von Grunt
Als Voraussetzung für Grunt muss Node.js und NPM auf dem System bereits vorhanden sein. Ist dies der Fall, kann die Installation von Grunt in zwei Schritten erfolgen. Zuerst muss grunt-cli per NPM global installiert werden:
$ npm install --global grunt-cli
Dann wird Grunt selbst einem Projekt als lokale Dependency hinzugefügt:
$ npm install grunt
Besser und üblicher ist es aber, dies per package.json, der Konfigurationsdatei für NPM, zu tun:
{ "dependencies": { "grunt": "0.4.5" } }
Die Konfiguration von Grunt-Tasks
Die eigentliche Aufgabe, die bei der Konfiguration von Grunt zu bewältigen ist, besteht nun darin, die Workflows, von denen weiter oben die Rede war, in die Form von sogenannten Grunt-Tasks zu gießen. Das erfolgt innerhalb der Datei Gruntfile.js die zwingend diesen Namen tragen muss und auf der obersten Ebene des Projektes abgelegt werden sollte:
module.exports = function (grunt) { grunt.initConfig({ uglify: { ... }, cssmin: { ... } }); };
Das Beispiel zeigt das grobe Schema für die Konfiguration von zwei Grunt-Tasks zur Minifizierung von JavaScipt-Code und CSS. Die Details der Konfiguration sind immer abhängig vom verwendeten Grunt-Plugin. Hier stehen die Bezeichner uglify und cssmin für grunt-contrib-uglify und grunt-contrib-cssmin, zwei Plugins aus der grunt-contrib Suite. Vor allem beim ersten Kontakt mit Grunt ist diese Sammlung von Plugins sehr sinnvoll um gleich mehrere Tools für einige der häufigsten Aufgaben kennenzulernen, z.B. für Linting, SASS, LESS, Unit-Testing, Bildoptimierung und verschiedene Datei-Operationen.
Sind die notwendigen Arbeitsschritte in Tasks übersetzt, können dann – ebenfalls im Rahmen von Gruntfile.js – bestimmte Tasks zusammengefasst und für die Ausführung per Konsole mit einem Alias registriert werden:
grunt.registerTask('minify', [ 'uglify', 'cssmin' ]);
Damit ist der Task uglify und der Task cssmin zu einem selbst definierten Task zusammengefasst und gleichzeitig mit dem Namen minify registriert worden. Auf der Konsole kann jetzt mit dem folgenden Kommando der Workflow, die Minifizierung von JS und CSS, ausgeführt werden:
$ grunt minify
Eine Alternative zu Grunt – Gulp
Seit Kurzem gibt es eine sehr interessante Alternative zu Grunt. Es handelt sich dabei um Gulp.js, ein ebenfalls in Node.js geschriebenes Build-System für JavaScript-Projekte. Anders als das aktuelle Grunt nutzt Gulp intensiv die sogenannte Stream API von Node.js. Dadurch ergibt sich eine Steigerung der Ausführungsgeschwindigkeit von Tasks. Außerdem, die Konfiguration der Tasks ist simpler, da die Ausgabe eines Streams einfach in den nächsten Stream per Pipe hineingereicht wird. Damit nutzt Gulp also wesentlich besser die Möglichkeiten die Node.js bietet – und attraktiv macht.
Nun wird sich aber auch Grunt noch weiterentwickeln. Für die nächsten Versionen von Grunt sind unter anderem Änderungen hinsichtlich der Verwendung von Pipes geplant. Und natürlich spricht die große Community hinter Grunt und die entsprechende Auswahl an Plugins derzeit noch dafür auch weiterhin JavaScript-Entwicklung mit Grunt zu automatisieren.
Was noch? Scaffolding mit Grunt!
Mit Grunt lassen sich also bestimmte Arbeitsschritte bei der Entwicklung von Web-Frontends automatisieren und absichern. Das ist nicht nur eine Verbesserung der Effizienz beim Progammieren, sondern auch eine erhebliche Steigerung der Qualität der gesamten Applikation, da Code-Analysen und Tests nicht nur sporadisch, sondern regelmäßig im Verlauf der Entwicklung durchgeführt werden.
Es geht aber noch mehr: auf der Basis von Grunt kann ein komplettes Grundgerüst für eine Frontend-Applikation, ein sogenanntes Scaffold, quasi auf Knopfdruck generiert werden. Die bekanntesten Tools hierfür sind die Generatoren von Yeoman die auf Grunt aufsetzen. Es existieren für alle prominenten, aber auch weniger bekannten Frontend- und Javascript-Libraries Yeoman-Generatoren.
Ich selbst habe während der Arbeit an Web-Aplikationen mit AngularJS einen solchen Generator entwickelt: generator-ng-scaffold. Grunt wird bei diesem Code-Generator auf zwei Ebenen eingesetzt. Auf der ersten Ebene wird mit Grunt die Grundstruktur einer AngularJS-App angelegt, eine modulare Datei- und Verzeichnisstruktur und grundlegende JavaScript-Dateien und HTML-Templates. Zu dieser Ebene zählen auch weitere Tasks, mit denen der Boilerplate-Code z.B. für ein neues Modul generiert wird. Auf der zweiten Ebene, im Rahmen der entstandenen Basis-Applikation, spielt Grunt dann die Rolle, von der in diesem Artikel die ganze Zeit die Rede ist: Grunt ermöglicht die Automatisierung bestimmter Schritte der weiteren Entwicklung der Applikation.
Schreibe einen Kommentar