Grunt für Profis: Automatisierte Prozesse verbessern die Team-Arbeit
Vermutlich stand jeder Entwickler schon mal vor dem Problem unterschiedlich strukturierten Codes. Oder musste sich erst in die Struktur eines Projekts einarbeiten, die jemand anderes angelegt hat. Grunt schafft Abhilfe: Einer der größten Vorteile des Task-Runners ist die Einheitlichkeit in der Code-Struktur und der Arbeitsweise innerhalb eines Teams. Grunt ermöglicht es einem Team von Entwicklern, über konfigurierte Tasks Strukturen zu etablieren und diese ohne viel Aufwand einzuhalten. Mit knapp 4.500 Plugins und einer aktiven Community, deren Mitglieder diese in regelmäßigen Abständen aktualisieren, gibt es für sehr viele Anforderungen bereits die passende Lösung.
Projekt zum Artikel |
Das gesamte Projekt des Artikels befindet sich unter folgendem Link als ZIP-Archiv: http://t3n.me/grunt-webseite-t3n40. |
Projektstrukturierung mit Grunt
Mit der Einführung von Grunt in unsere internen Entwicklungsprozesse haben wir festgestellt, dass unsere Projektstruktur noch Raum für Verbesserungen zulässt. Beim Konfigurieren von Gruntfile.js fiel beispielsweise auf, dass es durchaus Sinn ergibt, den Source-Code vom optimierten und aufgeräumten Code zu trennen, der im Produktivsystem letztlich zum Einsatz kommt.
Die Flexibilität der Grunt-Konfiguration lässt das sehr einfach zu und schafft so einen guten Überblick über die gesamte Applikation, die sich gerade in Entwicklung befindet. Beispielhaft kann eine Ordnerstruktur für eine Webseite (vereinfacht) so aussehen – wir gehen für das weitere Vorgehen immer von der hier gezeigten Struktur aus:
Beispiel für Ordnerstuktur
grunt-webseite/ | | - public_html/ | | - css/ | | - main.css // mit Grunt kompliliertes CSS | | - images/ | | - ... // mit Grunt optimierte Bilder | | - js/ | | - main.min.js // mit Grunt konkateniert und uglified | | - index.html | | - resources/ | | - images/ | | - js/ | | - lib/ | | - jquery-1.11.2.min.js | | - main.js | | - scss/ | | - _variables.scss | | - main.scss | | - config.rb // bei Nutzung von compass | | - Gruntfile.js | | - package.json
Listing 1
Wie zu sehen ist, werden die Dateien, an denen wir aktiv entwickeln, im Ordner „resources“ abgelegt.
Im Folgenden konfigurieren wir Grunt so, dass unsere Dateien fertig aufbereitet für den Produktiveinsatz im Webroot, in diesem Fall dem Ordner „public_html“, liegen. Mit dem Paketmanager Homebrew können Mac-OS-Anwender kinderleicht Packages installieren, beispielsweise „wget“ oder „imagemagick“ (welches später noch zum Einsatz kommt).
Installation Homebrew
$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
Listing 2
Installierte Plugins registrieren
Wir gehen von der package.json aus, in der wir Tasks für das Kompilieren von SCSS mit Compass, das Optimieren von JavaScript-Dateien, das Optimieren von Bildern und einen sogenannten Watch-Task hinzugefügt haben, der diese Prozesse automatisiert.
Vor der Nutzung müssen die Plugins geladen werden:
Laden der Tasks
module.exports = function(grunt){ ... // Tasks laden, herkömmliche Weise // grunt.loadNpmTasks(‘grunt-contrib-compass’); // grunt.loadNpmTasks(‘grunt-contrib-concat’); // grunt.loadNpmTasks(‘grunt-contrib-uglify’); // grunt.loadNpmTasks(‘grunt-contrib-watch’); // Tasks laden, mit dem Plugin load-grunt-tasks // https://github.com/sindresorhus/load-grunt-tasks require('load-grunt-tasks')(grunt); grunt.registerTask('default', []); };
Listing 3
Wie in der Konfiguration ersichtlich, gibt es die Standard-Methode, die installierten Tasks zu registrieren. Das geschieht über Auflistung der einzelnen Namen der Plugins. Das Plugin load-grunt-tasks lädt alle in der package.json aufgelisteten Plugins automatisch nach einem (konfigurierbaren) Pattern und macht die Gruntfile übersichtlicher.
Grunt Watch für sorgenfreie Frontend-Entwicklung
Nun konfigurieren wir unsere Tasks und legen Variablen an, die uns die spätere Anpassung der Konfiguration erleichtern.
Anlegen der Pfad-Variablen
module.exports = function(grunt) { var globalConfig = { css: '../source/css', scss: 'scss', scripts: '../source/js', scripts_src: 'js' };
Listing 4
Per globalConfig lassen sich Variablen definieren, die über das Gruntfile hinweg zur Verfügung stehen. Anstatt also an jeder Stelle den Pfad der Dateien zu schreiben, verwenden wir beispielsweise den Pfad zur SCSS-Datei so: <%= globalConfig.scss %>. Sollte sich an der Ordnerstruktur des Projekts etwas verändern, muss nur die globalConfig editiert werden.
Da wir SCSS in Verbindung mit Compass benutzen, muss vor dem Start des watch-Tasks noch analog zur Gruntfile-Konfiguration die config.rb angelegt werden.
Compass-Einstellungen
# Paths relative to Gruntfile.js http_path = "/" css_dir = "../source/css" sass_dir = "scss" images_dir = "../source/images" # relative Pfade auf Assets relative_assets = true #relative Pfade auf Assets #Alternativen :expanded, :nested oder :compact output_style = :compressed #entfernt Debugging-Kommentare line_comments = false
Listing 5
Nachdem jetzt alles konfiguriert ist, wird ein Grunt-Task gestartet. Da der watch-Task als default registriert ist, muss in der Konsole im resources-Ordner nur Folgendes eingegeben werden, um diesen zu starten:
Start des default-Tasks
$ grunt
Listing 6
Ein registrierter Task kann jeden beliebigen Namen erhalten und es können beliebig viele Tasks angelegt werden. Die Benennung watch-project anstatt default resultiert im selben Ergebnis, verlangt aber einen anderen Aufruf in der Konsole, nämlich:
Start eines Tasks mit abweichendem Namen
$ grunt watch-project
Listing 7
Es erscheint die Ausgabe „Running watch task, waiting“. Fügt man nun in einer SCSS-Datei probeweise ein paar Zeilen hinzu und speichert die Datei, registriert das der laufende Task und führt den im watch-Task eingehängten Compass-Befehl aus. Somit erhalten wir ein kompiliertes CSS-File in unserem angegeben Ziel-Ordner „public_html/css“. Das Gleiche gilt für Änderungen in den JavaScript-Dateien: Hier wird erst concat und dann uglify ausgeführt, was in main.min.js im Verzeichnis „public_html/js“ resultiert, das alle Dateien aus dem lib-Ordner enthält. In der concat-Konfiguration ist zudem unter src die Reihenfolge angegeben, in der die JavaScript-Dateien aneinander gehängt werden sollen. An den Anfang der Datei steht die jQuery-Source, erst danach folgen alle anderen Files, die sich im js-Ordner befinden. Diese Konfiguration kann wichtig sein, wenn bestimmte Libraries vor anderen geladen werden müssen.
Optimierung von Bildmaterial und Retina-Support
Nachdem Grunt nun für die Basis-Anforderung eines Web-Projekts konfiguriert ist, lassen sich nach Bedarf Stück für Stück weitere Plugins hinzufügen.
Als nützlich hat sich die Funktion erwiesen, Bildmaterial zu komprimieren und für responsive Websites oder Retina-Devices verschiedene Bildgrößen zu generieren. Dazu bedient man sich der Plugins „grunt-contrib-imagemin“ und „grunt-responsive-images“. Die Bildbearbeitung übernehmen Tools wie ImageMagick oder GraphicsMagick. Mit dem zuvor installierten Homebrew ist die Installation denkbar einfach.
Installation GraphiksMagick
$ brew install GraphicsMagick
Listing 8
Das zu optimierende Bildmaterial wird unter „resources/images“ abgelegt und das Gruntfile wie folgt erweitert.
Anschließend erfolgt die Registrierung des neuen Tasks optimize-images, der erst responsive_images und dann imagemin ausführt. Die Reihenfolge, in der die Tasks ausgeführt werden, ist in der eckigen Klammer festgelegt. Die dort auftauchenden Bezeichnungen entsprechen den Namen in grunt.initConfig({ … }).
Aufruf Task für Bildoptimierung
$ grunt optimize-images
Listing 9
Unsere Testbilder werden mit 100 Prozent Größe mit dem Suffix „@2x“ als Retina-Bild und mit 50 Prozent Größe für die herkömmliche Bildausgabe im Ordner „public_html/images“ gespeichert. Dort werden sie durch den imagemin-Task in ihrer Größe reduziert. Mit ein wenig Herumprobieren an den Qualitätseinstellungen lässt sich die richtige Kompression herausfinden, bei der noch eine ausreichende Qualität gewährleistet ist. Vorbei sind damit die Zeiten, in denen Bilder per Software mit Stapelverarbeitung oder – noch schlimmer – manuell für die Bedürfnisse im Web angepasst werden mussten.
Stressfrei Favicon und Touch-Icons erstellen
Neben dem Bereitstellen von Retina-Bildmaterial für hochauflösende Geräte fällt beim Erstellen einer Responsive oder Mobile Site nicht nur die Aufgabe an, ein Favicon, sondern auch Home-Screen-Icons zu erstellen. Mit der Vielzahl an mobilen Geräten ist auch die Anzahl der benötigten Icons gestiegen: iOS benötigt ein anderes Format als Android und das Windows Phone hat wiederum eine veränderte Optik.
Hier kommt das überaus praktische Plugin grunt-favicons zu Hilfe. Mit nur einer Ausgangsdatei, die in ausreichender Größe hinterlegt wird (erfahrungsgemäß reicht hier ein Format von 310px x 310px aus), lassen sich die benötigten Icons erstellen.
Der betreffende Task wird folgendermaßen ausgeführt:
Generieren der Touch-Icons
$ grunt generate-touch-icons
Listing 10
Das Plugin stellt im definierten Ziel-Ordner die generierten Icons bereit. Per Voreinstellung erzeugt es darüberhinaus die Datei favicon-test.html, welche bereits die passenden Meta-Tags zum Einbau in unsere Webseite enthält. Damit lassen sich per Copy & Paste und eventueller Anpassung der Bildpfade im Handumdrehen die benötigten Icons auf den mobilen Endgeräten bereitstellen.
Cross-Device-Testing mit BrowserSync
BrowserSync beschreibt seine Funktionalität selbst mit „Time-saving synchronised browser testing“ und trifft damit genau den Punkt. Mit jeder Webseite, jedem Browser und Endgerät steigt die Zeit, die zum Testen aufgebracht werden muss. BrowserSync vereinfacht diese Vorgänge insofern, als sie gleichzeitig auf verschiedenen Browsern und Geräten dieselbe Webseite anzeigt und synchronisiert. In Zusammenspiel mit Grunt ist BrowserSync so konfigurierbar, dass die Webseite bei Änderungen an einer HTML- oder CSS-Datei automatisch überall neu lädt und sogar das Scrollen und Klicken in allen Browsern synchron erfolgt. Das Plugin ermöglicht es beispielsweise, am Desktop über die Seite zu navigieren und auf einem Tablet oder Smartphone, auf welchem der Browser synchronisiert ist, die Auswirkungen zu sehen, die Webseite zu prüfen und debuggen.
Für die Verwendung dieser praktischen Funktion wird nach der Installation von grunt-browser-sync das Gruntfile entsprechend erweitert.
Beim Start des Tasks meldet das Terminal, dass BrowserSync und die Seite über den konfigurierten Proxy ausgeführt wird. Darauf zeigt es an, unter welcher URL die Seite lokal und von extern, also von Endgeräten im gleichen Netzwerk, zu erreichen ist. Die externe URL ist die lokale IP mit einer Portangabe, die standardmäßig auf 3000 gesetzt ist, sich aber anpassen lässt. Diese externe URL geben wir auf beliebig vielen mobilen Endgeräten ein, auf denen wir die Webseite testen möchten. Das Terminal listet alle synchronisierten Browser mit ihrer Version auf.
Bewegt man sich nun durch Scrollen oder das Klicken eines Links über die Seite, werden diese Aktionen auf den anderen Geräten und Browsern ebenso ausgeführt. Sogar das Ausfüllen von Formulare funktioniert gleichzeitig. Zusätzlich ist BrowserSync in der gezeigten Konfiguration so eingerichtet, dass die synchronisierten Browser automatisch neu laden, wenn eine Änderung in den CSS- oder HTML-Dateien erfolgt.
Die aktuelle Version bietet ein zusätzliches UI, das grafisch aufbereitet die Terminal-Anzeige ersetzt und weitere Aktionen und Konfigurationen ermöglicht. BrowserSync erleichtert das Testen auf unterschiedlichen Geräten somit ungemein und ist deswegen für eine Webseite mit Anforderungen an unterschiedliche Endgeräte sehr zu empfehlen.
Automatisierte Shell-Befehle
Ein letztes Beispiel, das beweist, wie flexibel Grunt einsetzbar ist: Unsere Entwicklungsumgebung setzt sich unter anderem aus Vagrant in Verbindung mit Virtualbox und git als Versionierungssystem zusammen. Der Arbeitsbeginn an einem Projekt sieht deswegen immer gleich oder zumindest sehr ähnlich aus: Den aktuellen Stand aus git pullen, Vagrant starten, den Browser öffnen und gegebenenfalls noch den Standard-Grunt-Task anstoßen. Diese simplen Tätigkeiten kann ausgezeichnet das Plugin grunt-shell übernehmen. So muss man vor Arbeitsbeginn nur noch in den resources-Ordner wechseln und folgendes Kommando eingeben:
Arbeitsumgebung vorbereiten mit der grunt-shell
$ grunt start-working
Listing 11
Anschließend kann man sich zurücklehnen und dem Terminal dabei zusehen, wie es die vorgegebenen Kommandos nacheinander ausführt.
Weiterhin lassen sich über das Shell-Plugin Installationsprozesse automatisieren. TYPO3 kann einfach als Submodule hinzugefügt und per Symlink in das eigene Projekt integriert werden. Die Anwendungsmöglichkeiten des Grunt-Shell-Plugins sind, wie in diesen kleinen Beispielen ersichtlich, sehr vielfältig und je nach Bedarf konfigurierbar.
Fazit
Grunt bietet die Möglichkeit, definierte, sich wiederholende Prozesse zu automatisieren. Gerade im Team werden damit für jeden klare Strukturen geschaffen, was zur Qualitätssicherung beiträgt. Einmal konfiguriert, verbessert sich die Effizienz in der Entwicklung, da nicht jedes Mal aufs Neue eine Lösung für den Umgang mit täglich auftretenden Aufgaben gefunden werden muss.
Durch die aktive Community und die vielen vorhandenen Plugins sind den Anwendungsbereichen von Grunt kaum Grenzen gesetzt. Nach diesem Überblick über einige nützliche Plugins und Konfigurationsmöglichkeiten sollte eine Basis geschaffen sein, sich selbst an Grunt zu versuchen und seinen Workflow massiv zu vereinfachen.
Dankeschön für diesen interessanten Artikel.
Allerdings möchte ich darauf hinweisen, dass Grunt nicht mehr weiter entwickelt wird und die meisten core Entwickler nun gulp verwenden.
Dies ist deutlich flexibler und zudem schneller.