labuero

< frontend developer >

grunt.js – Einer für alles

Handlebars, LESS, requireJS, responsive Images, die Anzahl der Tools und Best Practices in der immer komplexer werdenden Welt der Frontend Entwicklung ist schier unüberschaubar groß geworden. Und jedes Tool, jedes Vorgehen verlangt seinen eigenen Workflow. Grunt bedeutet sowohl grunzen als auch Arbeitstier womit sowohl Logo als auch die Aufgabe des Tools erklärt wären. Hiermit können wir fast alles was einem im Arbeitsalltag beim Umgang mit HTML, CSS und Javascript begegnet, unter einem Dach automatisieren. Im dem folgenden Tutorial versuche ich euch den Einstieg, mit der Einrichtung von Grunt zusammen mit einem SASS Prozess, zu vereinfachen.

grunt-banner

In meinem Projektordner habe ich die Unterordner „distribution“ und „develop“ der zusätzlich noch einen weiteren Unterordner „sass“ mit einigen .scss Dateien enthält.

|- develop
|– sass
|— .scss
|
|- distribution

Wer möchte, der kann sich diesen Ordner hier herunterladen. Enthalten sind das Ergebnis des Tutorials und ein fast leerer Projektordner zum mitmachen.

Unterschiede zur Version 3

Eine große Änderung in Version 4 ist, dass grunt nun in zwei Teile aufgeteilt ist. Zum einen haben wir den Hauptprozess, der im Projektordner abgelegt wird. Zum anderen existiert jetzt ein Tool namens grunt-cli, welches wir global auf unserem System installieren. Dieser tut nichts weiter, als grunt zu starten. Dies hat den Vorteil, dass wir Versionsunabhängig auch in älterne Projekten den build Prozess anstoßen können und nicht irgendwann in Kompalibilitätsprobleme rennen, weil wir auf unserem System bereits eine neuere Version installiert haben, wir in unserem Projekt aber noch auf eine ältere Version setzen. In diesem Zug bringt grunt auch keine Plugins mehr mit. Diese installieren wir alle einzeln.

Installation:

Als erstes benötigen wir node.js welches es Installationsdatei zum Download sowohl für Windows und Mac gibt. http://nodejs.org/download/
Nach der Installation haben wir mit node nichts weiter zu tun. Es tut nun still seinen Dienst im Hintergrund.
Alles weitere passiert in der Console bzw. Terminal.

Zur Installation des cli tools tippen wir folgendes ein.

$ npm install -g grunt-cli

npm steht dabei für Node Packaged Modules, ein globales Archiv in dem alle node Module gehostet werden.
Mit der Option -g wird das Module global installiert. Somit steht der grunt Befehl später in jedem Unterordner zur Verfügung.

Schritt zwei, wir legen eine package.json Datei in unserem Projektordner an. Darin enthalten sind ein paar Basis Informationen zum Projekt und später die verwendeten Module.

{
  "name": "gruntdemo",
  "version": "0.1.0"
}

Das war es auch sc
hon. Man kann noch sehr viel mehr machen mit der package.json. Autoren eintragen, Repositories verlinken, Versionsnummer, usw. und diese Infos später auch wieder auslesen und weiterverwenden. Allein mit dieser Datei kann ebenfalls die grunt Installation jederzeit wieder hergestellt werden. Dazu später noch etwas mehr. Uns soll diese minimale Datei reichen.

Um grunt zu installieren, navigieren wir per Console/Terminal in unser Projektverzeichniss und hacken folgendes in die Console.

$ npm install grunt --save-dev

Der Zusatz –save-dev, sorgt dafür, dass grunt als Abhängigkeit für dieses Projekt eingetragen wird. Wenn ihr diesen Befehl ausgeführt habt, schaut mal in die package.json. Dort sollte nun folgendes stehen.

{
  "name": "gruntdemo",
  "version": "0.1.0",
  "devDependencies": {
    "grunt": "^0.4.5"
  }
}

Im Ordner taucht jetzt auch ein zusätzlicher Ordner namens node_modules auf, in dem sich grunt befindet. Alle zukünftigen Plugins werden ebenfalls dort abgelegt.

Tipp: Nutzt ihr eine Versionsverwaltung z.B. git, dann setzt diesen Ordner auf die ignore Liste. Schnell kommen viele tausende Dateien und mehrer MB zusammen, die ihr nicht mit einchecken müsst.

Installieren von Plugins:

Auf der Seite http://gruntjs.com/plugins finden wir alle möglichen Plugins, zu diesem Zeitpunkt sind es ganze 3,873. Bei eurer Suche werden euch häufig Plugins angezeigt, die den Zusatz contrib- haben und mit einem Stern versehen sind. Dies sind Plugins, die offiziell vom grunt-team gepflegt werden und somit, wenn sie euren Anforderungen entsprechen, auch in die engere Wahl gezogen werden sollten.

Wir suchen nach SASS und finden grunt-sass: https://www.npmjs.org/package/grunt-sass

Warum nehme ich nicht das offizielle grunt Sass Plugin obwohl ich es doch gerade noch empfohlen habe? Zum Einen ist dieses Plugin deutlich schneller und es hat keine Abhängigkeiten die wir für dieses Tutorial extra installieren müssten wie z.B. ruby.

Die Installation von Plugins sieht genauso aus, wie das installieren von grunt selbst.
$ npm install --save-dev grunt-sass

In der package.json wird das Plugin als Dependency eingtragen und der node_modules Ordner enthält wieder ein paar Dateien mehr.

Tipp: Das installieren des grunt Hauptmodules, kann man sich auch sparen und direkt mit der Installation der Plugins beginnen. Jedes Plugin lädt seine eigenen Abhängigkeiten bei Bedarf nach, solange diese auch per npm installierbar sind, und jedes Plugin hat, man mag es kaum glauben, eine Abhängigkeit auf grunt selbst.

Konfiguration der Task in der gruntfile.js:

Das Herzstück ist die gruntfile.js in der alle Aufgaben konfiguriert werden.
Kopieren wir den Block in die gruntfile.js im Hauptordner und schauen uns die Konfiguration genauer an.

module.exports = function(grunt) {
  grunt.initConfig({

    sass: {       
      develop: {
        options: {
          sourceMap: true,
          outputStyle: nested
        },
        files: {
          'develop/css/main.css': 'develop/sass/main.scss'
        }
      }
    }

  })
}

sass: { ...

Jedes Plugin hat seinen eigenen Wrapper, einfachheitshalber mit dem Namen des Plugins.

develop: { ...

In jeder Pluginkonfiguration kann man mehrere Untertask anlegen. Einen für die Entwicklung, in der man z.B. nicht möchte, dass die Dateien minifziert werden um noch vernünftig debuggen zu können. Und einen fürs deployment, bei der man neben dem minifizieren zusätzlich die Datei noch in einen gänzlich anderen Ordner kopieren will.

options: { ...

Welche Optionen man hat, erfährt man auf der Plugin Seite
https://www.npmjs.org/package/grunt-sass

files: { ...
Der Name ist Programm. Ziel und Quelldatei werden hier festgelegt.
In meiner main.sass Datei sind alle anderen SASS Dateien per @import eingetragen, weswegen ich nur diese als Quelle angeben muss.

Das passt soweit schon ganz gut. Bevor wir grunt allerdings zum malochen schicken können, müssen wir jedes Plugin zuerst anmelden. Diese Zeile hängen wir zwischen config und den wrapper.

grunt.loadNpmTasks('grunt-sass');

Alles installiert, angemeldet und konfiguriert, fast geschafft.
Zu guter letzt wird noch eingestellt, was aus unserer gruntfile alles ausgeführt werden soll, wenn wir den Prozess anstoßen. In vielen Projekten hat man nie nur einen Task, weswegen man auch nicht wahllos alles was eingestellt und konfiguriert wurde, ausführen möchte. Aktuell ist es noch relativ einfach.

grunt.registerTask('default', ['sass']);

Default ist der Task, der ausgeführt wird, wenn wir einfach nur $ grunt aufrufen. In dem array dahinter, werden alle Prozesse gelistet, die nacheinander ausgeführt werden.

module.exports = function(grunt) {
  grunt.initConfig({ 

    sass: {       
      develop: {
        options: {
          sourceMap: true
        },
        files: {
          'develop/css/main.css': 'develop/sass/main.scss'
        }
    },
  })

  grunt.loadNpmTasks('grunt-sass');

  grunt.registerTask('default', ['sass']);

}

Probieren wir das mal aus, und tippen in unsere console:
$ grunt.
In meinem Demo Projekt lasse ich einmal den kompletten Bootstrap3 SASS Portierung compilieren in weniger als einer Sekunden. Der fehlende CSS Ordner wird automatisch erstellt und darin taucht die CSS Datei und die Sourcemap Datei auf. Großartig!

Tipp: zu 90% erstelle ich meine grunt Prozesse nur durch Copy&Paste, aus alten Projekten und von den Dokuseiten der Plugins. Ich passe oft lediglich nur den Pfad zu den Ordnern und hin und wieder die Optionen etwas an.

In Step zwei wollen wir das Ganze für unser deployment vorbereiten. Dafür benötigen wir die CSS Datei minifiziert und in einem anderen Ordner. Wir legen also einen zweiten Task innerhalb des SASS Task an – sagte ich bereits, das grunt konfigurieren viel Copy&Paste mit ein paar Anpassungen ist? Wir kopieren also die Konfiguration für develop, setzten sie dahinter und ändern Namen und Pfade. Zusätzlich nehmen wir noch die Option für den outputStyle mit auf und stellen diese auf 'compressed'.

Anschließend registrieren wir einen neuen Task, der später alle nötigen Schritte für unser deployment beinhalten soll. Da wir im SASS Task nun zwei Aufgaben haben, müssen wir natürlich einstellen, welcher der beiden jeweils ausgeführt werden soll, was durch einen einfachen Doppelpunkt geschied.

grunt.registerTask('default', ['sass:develop']);
grunt.registerTask('deployment', ['sass:distribution']);

Alles zusammen:

module.exports = function(grunt) {
  grunt.initConfig({ 

  sass: {       
    develop: {
      options: {
        sourceMap: true
      },
      files: {
        'develop/css/main.css': 'develop/sass/main.scss'
      }
    },
    distribution: {
      options: {
        sourceMap: true,
        outputStyle: ‘compressed’
      },
      files: {
        'distribution/css/main.css': 'develop/sass/main.scss'
      }
    },

  })

  grunt.loadNpmTasks('grunt-sass');

  grunt.registerTask('default', ['sass:develop']);
  grunt.registerTask('deployment', ['sass:distribution']);

}

Um den deployment Prozess anzustoßen, müssen wir diesmal grunt deployment in die Console tippen. Tada! Und schon landet eine minfizirete CSS Datei in unserem Distributions Ordner, denn wir später ausliefern könnten.

Wärend der Entwicklunsphase wäre es etwas mühsam, nach jeder Änderung den default Prozess von Hand anzustoßen, weswegen wir uns einen watcher installieren, der dies automatisch tut.
Diesen hier: https://www.npmjs.org/package/grunt-contrib-watch

Installieren:
npm install grunt-contrib-watch --save-dev
Und das Plugin wird ebenfalls in unser packages.json eingetragen.

Plugin in unsere gruntfile.js registrieren:
grunt.loadNpmTasks('grunt-contrib-watch');

Und unsere Konfiguration:

watch: {
  sass: {
    files: ['develop/sass/**/*.scss'],
    tasks: ['sass:develop']
  },
},

Drumherum unser watch task, damit grunt auch weiß, um was es hier geht, und innerhalb die zu überwachenden Dateien plus die dazugehörige Aufgabe.
In files geben wir die Dateien die es zu überwachen gilt an. Mit den Wildcards **/*.scss geben wir an, dass alle .scss Dateien in diesem Ordner und zusätzlich allen Unterordner überwacht werden sollen. In Task stellen wir die bei einer Änderung auzuführenden Prozesse ein. In diesem Fall unseren sass:develop Task.

Unsere gruntfile sieht mittlerweile so aus:

module.exports = function(grunt) {
  grunt.initConfig({ 

    sass: {       
      develop: {
        options: {
          sourceMap: true
       },
       files: {
         'develop/css/main.css': 'develop/sass/main.scss'
        }
      },
      distribution: {
        options: {
          sourceMap: true,
          outputStyle: ‘compressed’
        },
        files: {
          distribution/css/main.css': 'develop/sass/main.scss'
        }
      },
      watch: {
        sass: {
          files: ['develop/sass/**/*.scss'],
    	  tasks: ['sass:develop']
        },
      },
  })

  grunt.loadNpmTasks('grunt-sass');
  grunt.loadNpmTasks('grunt-contrib-watch');

  grunt.registerTask('default', ['sass:develop']);
  grunt.registerTask('deployment', ['sass:distribution']);

}

Den Watch Prozess starten wir diesmal händisch und hängen ihn nicht mit in unseren default Task.

grunt watch

Dieses Consolenfenster ist nun erstmal busy und wenn wir in einer der SASS Dateien eine Kleinigkeit ändern und speichern, herrscht hier sofort behändes treiben.

Grunt in Projekten:

Ich sagte bereits, dass man den Ordner node_modules nicht mit einchecken soll. Wir haben nach unserem kleinen Tutorial immerhin schon 34MB und 2908 Dateien mit denen wir unser Versionierungssystem nicht belasten müssen. Es genügt, wenn wir unseren Kollegen die gruntfile.js und die package.json mitgeben.
Mit dem Befehl
$ npm install
werden automatisch alle Abhängigkieten ausgelesen und installiert. Wird der grunt Prozess erweitert, müssen die Kollegen lediglich die package.json aktualisieren
$ npm-update
aufrufen und ihr seit wieder auf dem neusten Stand. Wenn ihr es probieren möchtet, löscht euren node_modules Ordner und ruft den update Befehl auf.

Was kann grunt noch:

Die Frage müsste lauten, was kann grunt nicht? Simple Aufgaben wie das kopieren von Dateien, linten und minifzieren von Javascript, optimieren von Bildern, erstellen von Webfonts aus SVG Grafiken,  für jede Template Engine gibt es ein Plugin und selbst das starten eines Webservers inklusive Live Reload stellt kein Problem dar. Und sobald das Internet of Thinks Einzug gehalten hat, gibt es nach jedem erfolgreichen Deployment automatisch einen Kaffee.

Links:

nodejs.org   – Der Unterbau des Ganzen.
gruntjs.com –  Anlaufstelle für die Doku und Plugins
8 ways improve your grunt setup – Tipps um grunt pflegbar und performant zu halten.
Grunt is not weird and hard – Sehr gutes Tutorial, falls hier Fragen offen geblieben sind.

3 Kommentare

  1. Jannick

    Sehr schönes Einstiegstutorial!
    Ich muss mich auch dringend jetzt langsam mal mit Grunt beschäftigen, der Artikel war ein super Einstieg dafür! 🙂

  2. Kevin

    Schönes Tutorial!
    Leider enthält deine Code-Beispiele einige Fehler weswegen es sich nicht compilieren lässt.
    Was für Anfänger ohne große Kenntnisse es erschwert anzuwenden.

    Grüße,
    Kevin

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.