Matt hat uns allen erzählt, wir sollten mehr JavaScript nutzen. Aus diesem Grund – und auch generell der Interesse halber – lese ich gerade das Buch Professionell entwickeln mit JavaScript. Darin befindet sich auch ein Kapitel über Grunt und Gulp. Zeit sich das etwas genauer anzuschauen.
TL;DR
- Build-Tools sind Helfer-Scripte, die Schritte wie z.B. die Minimierung von CSS- oder JS-Dateien automatisieren.
- Grunt sowie Gulp sind so genannte Task-Runner. Sie führen Aufgaben aus.
- Beide Tools werden mit einer JavaScript-Datei konfiguriert.
- Grunt richtet sich nach dem CommonJS-Modulsystem während Gulp einen Pipelining-Ansatz verfolgt.
- Grunt ist in größeren Projekten eventuell unübersichtlicher als Gulp.
- Grunt ist eventuell etwas langsamer als Gulp. Vor allem dann, wenn viele Aufgaben abgearbeitet werden müssen.
- Das Plugin-Verzeichnis von Grunt ist etwas größer als das von Gulp.
Was sind Build-Tools?
Jeder Programmierer kennt das: es gibt Dinge, die immer wieder getan werden müssen. Beim Programmieren eines WordPress Plugins wäre das zum Beispiel das Erstellen der Unterordner, wie
- images
- css
- js
- languages
Oder: man schreibt CSS und JS-Dateien und möchte sie später minimiert im Plugin mitliefern. Für letzteres gibt es Websiten wie z.B. jscompressor.com. Allerdings wären wir keine Programmierer, wenn wir nicht schauen, dass wir alles automatisieren würden. Aus diesem Grunt gibt es die so genannten Build-Tools wie Grunt oder eben Gulp.
Diese Tools werden auch Task-Runner genannt. Warum? Weil sie eben genau das tun. Beide Systeme arbeiten ähnlich: in einer Datei wird beschrieben welche Aufgabe wann erledigt werden soll.
Interessant ist, dass beide Build-Tools mit npm (dem Node Packet Manager) installiert werden können. npm wiederum kommt standardmäßig mit node.js daher. Das bedeutet auch: beide Tools sind in JavaScript geschrieben. Das ist natürlich für alle die sich gerade mit JavaScript bekannt machen ein Gewinn.
Wie funktioniert Grunt?
Installation von Grunt lokal und im Projekt
Das Entwicklerteam hinter Grunt schlägt vor, Grunt nicht global sondern lediglich per Projekt zu installieren. Dadurch hat jedes Projekt seine eigene Grunt-Version. Die Installation geht wie folgt vonstatten. Das –save-dev sorgt dafür, dass Grunt nur als Entwicklungsabhängigkeit (in die package.json) hinzugefügt wird.
npm install grunt --save-dev
Der Nachteil hier ist natürlich, dass Grunt dann nicht in der Kommandozeile aufgerufen werden kann. Aus diesem Grunt gibt es die so genannte Grunt CLI. Sie kann wie folgt installiert werden:
npm install -g grunt-cli
Das -g bedeutet hier “global”.
Gruntfile.js – die Konfigurationsdatei
Nun müssen die Aufgaben definiert werden. Das klappt bei Grunt über die so genannte Gruntfile.js. Anhand der Dateiendung sieht man schon: es handelt sich um eine JavaScript-Datei (nicht um eine JSON-Datei). Die Gruntfile.js liegt meist im Wurzelverzeichnis des Projekts.
'use strict'; module.exports = function(grunt) { grunt.initConfig({ // ... }); grunt.loadNpmTasks( '...' ); grunt.registerTask( 'default', [ '...' ]); };
Die eigentliche Konfiguration geht in drei Schritten:
- Über initConfig() können Projekt- und Task-Konfigurationen vorgenommen werden,
- über loadNpmTask() werden vorhandene Plugins und Tasks geladen und
- über registerTask() werden eigene Tasks definiert.
Damit lassen sich letztlich beliebig komplexe Aufgaben erstellen die dann von Grunt abgearbeitet werden.
Grunt-Plugins
Interessant wird Grunt aber natürlich erst durch die Installation von Plugins. Denn wer will schon seine eigenen Aufgaben direkt in JavaScript selbst schreiben? Letztlich würde das zu einem nicht überschaubaren Mehraufwand führen. Eine Übersicht aller Plugins findet man unter http://gruntjs.com/plugins.
Installieren wir beispielsweise das Plugin grunt-contrib-cssmin welches – wie uns der Name schon verrät – CSS-Dateien minimiert:
npm install grunt-contrib-cssmin --save-dev
Nun wird das Plugin entsprechend konfiguriert. Hier im Beispiel werden die Dateien foo.css und bar.css zu einer Datei namens out.css zusammengefasst:
'use strict'; module.exports = function(grunt) { grunt.initConfig({ cssmin: { options: { shorthandCompacting: false, roundingPrecision: -1 }, target: { files: { 'output.css': ['foo.css', 'bar.css'] } } } }); grunt.loadNpmTasks( 'grunt-contrib-cssmin' ); grunt.registerTask( 'default', [ 'cssmin' ]); };
Über die Kommandozeile lässt sich nun der Task ausführen:
grunt cssmin
Wie funktioniert Gulp?
Installation von Gulp
Im Gegensatz zu Grunt wird Gulp sofort global installiert. Und zwar ebenfalls über npm wie folgt:
npm install -g gulp
Wer einen Packet-Managener nutzt kann gulp dann zum Abhängigskeitsbaum der Developer-Umgebung hinzufügen:
npm install -save-dev gulp
gulpfile.js – Die Konfigurationsdatei
Ähnlich wie bei Grunt wird Gulp über eine JavaScript-Datei konfiguriert um entsprechende Aufgaben durchzuführen. Und genau hier zeigt Gulp seine Stärke. Denn gerade in größeren Projekten kann die Konfigurationsdatei von Grunt schon ziemlich stark anwachsen. Kritische Stimme sagen, dass letzteres einfach zu konfigurationslastig wäre. Deshalb wurde Gulp entwickelt. Es verfolgt einen so genannten Pipelining-Ansatz. Was das heißt, werden wir gleich sehen. Hier die Grunt-Konfigurationsdatei:
var gulp = require('gulp'); gulp.task('default', function() { // place code for your default task here }); gulp.task('default', ['...']);
Gulp-Plugins
Wie sollte es anders sein? Auch für Gulp gibt es Plugins. Zu finden unter http://gulpjs.com/plugins/. Wir probieren hier das Plugin combine-css und fügen es unserer Abhängigkeit hinzu:
npm install combine-css --save-dev
Nun ergänzen wir die Konfigurationsdatei:
var gulp = require('gulp'); var combineCSS = require('combine-css'); gulp.task('combine', function() { gulp.src('./css/*.css') .pipe(combineCSS({ lengthLimit: 256,//2KB prefix: '_m-', selectorLimit: 4080 })) .pipe(gulp.dest('./combinedCSS')); }); gulp.task('default', ['combine']);
Hier werden alle Dateien mit der Endung .css zu einer Datei zusammengefasst. Schön zu erkennen ist die pipe()-Funktion die man letztlich endlos weiterführen könnte.
Gulp führt man am Ende einfach durch den Aufruf von
gulp
auf.
Soll ich nun Grunt oder Gulp für mein WordPress Projekt nutzen?
Im Grunde gilt: eigentlich ist es egal. Denn nützlich ist immer genau das, was auf das Projekt und zum Team passt. Ich persönlich würde zu Gulp tendieren. Und zwar aus den folgenden zwei Gründen:
- Grunt kann in größeren Projekten eine sehr unübersichtliche Konfigurationsdatei erzeugen. Der Pipelining-Ansatz von Gulp gefällt mir besser weil auch der Code einfacher zu lesen ist.
- Grunt soll langsamer sein als Gulp. Und zwar liegt es daran, wie Grunt die automatische Erledigung von Scripten verarbeitet. Bei Grunt werden Dateien zuerst auf die Festplatte zwischengespeichert, dann die Aufgaben darauf erledigt, dann wieder gespeichert. Gulp nutzt so genannte Node-Streams und erledigt alles im Speicher. Nur das Endresultat wird sofort in eine Datei gespeichert. Sicherlich ist der spürbare Vorteile nur marginal. Zumindest bei kleineren Projekten, wie auch dieser Test zeigt.
Einen Nachteil hat Gulp dann aber doch noch. Grunt gibt es schon länger auf dem Markt. Deshalb gibt es dafür mehr Plugins. Möchte man nun ein Plugin nutzen welches nur für Grunt verfügbar ist, muss man Grunt nutzen.