Stand: 12.05.2019

In diesem Kapitel geht es um Werkzeuge, die das Arbeiten an Webseiten erleichtern.

11.1 Terminal/Shell

Ein Terminal (auch Command Shell, kurz Shell, oder einfach nur Konsole) ist ein Fenster, in dem man Befehle für das Betriebssystem eingeben kann. Man befindet sich beim Start des Terminals in einem bestimmten Verzeichnis und wechselt über Kommandos in andere Verzeichnisse, kann dort Programme starten/löschen, neue Verzeichnisse anlegen und vieles mehr.

Wir benötigen ein Terminal für unsere Arbeit mit Node und Grunt. Die erste Frage lautet natürlich: Wie starte ich ein Terminal? Gleich dannach die Frage: Welche Befehle gibt es? Dies ist unterschiedlich für Windows- und Mac-Rechner.

11.1.1 Mac OS

Auf einem Mac starten Sie ein Terminal wie folgt:

Es öffnet sich ein Fenster, wo Sie Befehle eingeben können.

Verzeichnisse und Dateien

Mit pwd können Sie nachsehen, in welchem Verzeichnis Sie sich befinden. Das ist z.B.

/Users/schmidt

Mit ls sehen Sie, welche Programme und Unterverzeichnisse im aktuellen Verzeichnis liegen. Mit dem Modifikator "-l" bekommen Sie eine Detailansicht (Listenansicht). Mit dem Modifkator "-a" sehen Sie auch "versteckte" Dateien (Dateien, die mit einem Punkt beginnen). Das heißt es gibt die folgenden Varianten:

ls
ls -l
ls -a

Oder auch die Kombination von "-l" und "-a":

ls -al

Mit cd wechseln Sie in ein Unterverzeichnis. Mit cd .. wechseln Sie in das Elternverzeichnis.

Mit mkdir erstellen Sie ein neues Unterverzeichnis, z.B.

mkdir foo

erstellt im aktuellen Verzeichnis ein neues Unterverzeichnis "foo".

Mit rm können Sie Dateien und Verzeichnisse löschen. Eine Datei "bar.txt" löschen Sie so:

rm bar.txt

Um ein komplettes Verzeichnis zu löschen, verwenden Sie den Modifikator "-R" (steht für "rekursiv", d.h. alle enthaltenen Unterverzeichnisse werden auch gelöscht):

rm -R foo

Sollte Sie ständig Rückfragen bekommen, ob Sie wirklich etwas löschen wollen, können Sie mit "-i" (für ignore) diese Rückfragen deaktivieren:

rm -i bar.txt
rm -iR foo

Mit mv (move) können Sie Dateien umbenennen

mv bar.txt neues_bar.txt

oder in ein anderes Verzeichnis verschieben

mv bar.txt /some/other/folder/

Sie können ebenso ganze Verzeichnisse verschieben.

Textdateien betrachten

Um sich schnell Textdateien anzuschauen - z.B. eine Konfigurationsdatei wie "package.json" - gibt es den Befehl less (die alte Version des Befehls heißt more):

less package.json

Die Textdatei wird angezeigt. Wenn Sie sehr lang ist, kann man mit der Leertaste weiterscrollen. Mit u (up) und d (down) kann man seitenweise scrollen, mit den Cursortasten (hoch/runter) zeilenweise.

Mit q beendet man die Anzeige.

11.1.2 Windows

Auf einem Windows-Rechner starten Sie ein Terminal wie folgt:

Es öffnet sich ein Fenster, wo Sie Befehle eingeben können. Gezeigt wird immer das aktuelle Verzeichnis und dahinter der Cursor, z.B.

C:\Users\Schmidt>

Verzeichnisse und Dateien

Mit dir sehen Sie, welche Programme und Unterverzeichnisse im aktuellen Verzeichnis liegen.

Mit cd (change directory) wechseln Sie in ein Unterverzeichnis. Mit cd .. wechseln Sie in das Elternverzeichnis.

Mit mkdir (make directory) erzeugen Sie ein neues Unterverzeichnis.

Mit rename ändern Sie den Namen einer Datei oder eines Verzeichnisses.

Mit move verschieben Sie eine Datei oder ein Verzeichnis.

Mit del löschen Sie eine Datei.

Textdateien betrachten

Um sich schnell Textdateien anzuschauen - z.B. eine Konfigurationsdatei wie "package.json" - gibt es den Befehl type:

type package.json

11.2 Node

Node.js ist ein sehr beliebtes - praktisch nicht mehr wegzudenkendes - Framework in der Webentwicklung. Tatsächlich kommt es auch der Entwicklung von Servern, also aus dem Backend-Bereich. Warum benötigen wir es dennoch an dieser Stelle, wo wir uns doch (noch) ausschließlich mit Frontend-Entwicklung beschäftigen?

11.2.1 Node Package Manager

Der Grund ist der Node Package Manager, kurz NPM. Dieses Tool ist ein Teil des Node.js-Frameworks und erlaubt das einfache Installieren von Softwarepaketen. Insbesondere werden Abhängigkeiten verwaltet, da heutzutage jedes Softwarepaket die Installation von mehreren anderen Softwarepaketen voraussetzt. Hinzu kommen Anforderungen an die jeweilige Version des vorausgesetzten Pakets. Dem NPM kann man einfach sagen "installiere Paket X (in aktueller Version)" und es werden automatisch die Pakete A, B, C installiert, die X benötigt, und zwar in der korrekten Version.

11.2.2 Node installieren

Besuchen Sie die Node.js-Webseite, um Node.js zu installieren.

11.2.3 Node-Projekt erstellen

Ein Node-Projekt wird in einem eigenen Verzeichnis verwaltet. Erstellen Sie ein neues Verzeichnis "myproject" und gehen Sie in das Verzeichnis.

Sie machen das Verzeichnis zu einem Node-Projekt, indem Sie eingeben:

npm init

Node stellt Ihnen jetzt einige Fragen (name, version, ...), die Sie einfach immer mit ENTER beantworten können. Sie können die Infos später anpassen.

Das Verzeichnis "myproject" ist ein also Node-Projekt.

package.json

In dem Projektverzeichnis liegt nach "npm init" eine Konfigurationsdatei namens package.json, wo die gerade abgefragten Infos (name, version, ...) hinterlegt sind. Noch wichtiger: Node merkt sich in dieser Datei alle Software-Abhängigkeiten für dieses Projekt, d.h. welche anderen Programme installiert werden müssen, um dieses Projekt auszuführen zu können.

Schauen wir uns die Datei an:

{
  "name": "myproject",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

Wenn Sie mit npm ein Paket/Plugin installieren, befinden sich die entsprechenden Dateien in einem Unterverzeichnis namens node_modules.

Mit npm install können Sie in Zukunft jederzeit Pakete nachinstallieren lassen, die von der Konfigurationsdatei gefordert werden und derzeit noch nicht installiert sind.

Hinweis (Windows): Auf Windows-Rechnern müssen Sie den Pfad PATH erweitern, damit Windows die Kommandos von neu installierten Paketen findet. Hier ein Beispiel (ersetzen Sie den Pfad mit Ihrem Pfad):

PATH=%PATH%;C:\users\kipp\AppData\Roaming\npm

Sie können den Pfad kontrollieren mit

echo %PATH%

11.3 CSS-Präprozessoren (Less)

Mit "CSS-Präprozessor" bezieht man sich auf eine Sprache, die so ähnlich ist wie CSS, aber etwas mehr Möglichkeiten bietet. Ein Beispiel ist die Sprache Less. Less kann man sich als erweitertes CSS vorstellen. Statt mit einer CSS-Datei arbeitet man mit einer LESS-Datei, um die HTML-Seiten zu stylen. Diese Less-Datei wird dann von einem Präprozessor in eine ganz normale CSS-Datei übersetzt, bevor man wie gewohn HTML+CSS auf den Server hochlädt.

Sie können sich auf der Less-Homepage einen guten Überblick über Less verschaffen.

Alternativen zu Less sind:

Mit einer Google-Suche zu "Less sass" oder "less sass stylus" können Sie viele Artikel finden, die diese Technologien im Detail vergleichen. Wir haben uns hier für Less entschieden, weil die Ähnlichkeit zum originalen CSS am größten ist. Vom Funktionsumfang sind die Technologien aber ähnlich.

11.3.1 Grundprinzipien

Less bietet drei wichtige Erweiterungen für CSS an:

Wir schauen uns jedes Feature separat an. Erst im Anschluss beschäftigen wir uns mit der Frage, wie man denn den Less-Code einbindet.

Variablen

In Less kann man Variablen benutzen, um häufige Angaben zentral zu speichern. Eine häufige Anwendung ist das Speichern von Farben, die ja an verschiedenen Stellen (Flächen und Schrift) zur Anwendung kommen. Bei Änderung des Farbschemas muss man in CSS immer verschiedene Stellen anpassen, was natürlich auch leicht zu Fehlern führt.

Variablen in Less werden mit einem @ markiert und wie folgt verwendet:

@hintergrund: #000;
@schrift: yellow;
@spezial: red;

body {
  background-color: @hintergrund;
  color: @schrift;
}

h1 {
  color: @spezial;
}

Bei der Umwandlung von Less in CSS werden diese Variablen einfach überall eingesetzt.

Hinweis: Seit CSS3 gibt es auch im ganz regulären CSS Variablen. Die Schreibweise ist nicht ganz so schön wie in Less, aber wenn man nur Variablen benötigt, ist es sicher sinnvoll, den Mechanismus von CSS zu verwenden. Mehr Infos z.B. bei w3schools oder Mozilla.

Verschachtelung

Wenn Sie in CSS stylen, dann definieren Sie häufig Regeln für einen bestimmten Bereich, z.B. für das Hauptmenü in nav. Dann haben Sie eine Reihe von Regeln, hier nur ein kleines Beispiel:

nav h1 {
  font-size: 90%;
}

nav a {
  text-decoration: none;
  color: blue;
}

Um die Zusammengehörigkeit zu kennzeichnen und somit die weitere Arbeit zu erleichtern, können Sie Verschachtelung anwenden:

nav {

  h1 {
    font-size: 90%;
  }

  a {
    text-decoration: none;
    color: blue;
  }

}

Sie können natürlich auch noch weiter (tiefer) verschachteln. Bei der Umwandlung von Less in CSS werden wieder viele Einzelregeln (wie oben) erzeugt.

Zu beachten ist der Umgang mit Pseudoelementen, also z.B. a:hover. Hier muss bei Verschachtelung ein Verweis auf das umgebende Element mit & eingefügt werden.

Beispiel:

a:hover {
  color: red;
}

a:visited {
  color: grey;
}

wird zu

a {
  &:hover {
    color: red;
  }

  &:visited {
    color: grey;
  }
}

Das Zeichen & ist generell ein Verweis auf das umgebende Element (auch: Elternelement).

Mixins

Mixins sind im Grunde so etwas wie Funktionen, die also ein Stückchen CSS-Code auslagern, so dass es wiederholt verwendet werden kann. Zusätzlich kann man diese Codeteile parametrisieren.

Ein typisches Beispiel ist folgender (CSS-)Code:

#box1 {
     -moz-border-radius: 4px;
  -webkit-border-radius: 4px;
       -o-border-radius: 4px;
          border-radius: 4px;
}

#box2 {
     -moz-border-radius: 21px;
  -webkit-border-radius: 21px;
       -o-border-radius: 21px;
          border-radius: 21px;
}

Hier wollen wir runde Ecken erzeugen. Die vielen Eigenschaften sind Sicherheitsmechanismen, um ältere Browser anzusprechen, die das Feature border-radius noch nicht in der Form implementiert haben.

Um uns die vier Zeilen bei jedem Vorkommen zu ersparen, definieren wir ein Mixin mit einem Parameter (für den Kurvenradius):

.myradius (@radius: 4px) {
     -moz-border-radius: @radius;
  -webkit-border-radius: @radius;
       -o-border-radius: @radius;
          border-radius: @radius;
}

Sie sehen, dass wir dem Mixin einen Namen geben .myradius und einen Parameter @radius und übrigens auch einen Standardwert 4px für den Fall, dass kein Parameter beim Aufruf übergeben wird.

Wir können den ursprünglichen Code dann in Less so formulieren:

#box1 {
  .myradius;
}

#box2 {
  .myradius(21px);
}

Auch hier werden die Aufrufe bei der Umwandlung in CSS durch den Code in der Mixin-Definition ersetzt, so dass ein CSS resultiert, das so aussieht wie unser Ausgangspunkt oben.

11.3.2 Einbinden

Ein Browser kann LESS nicht verstehen, sondern nur CSS. Also muss Ihre LESS-Datei umgewandelt werden. Die Frage ist: wo wird diese Umwandlung vollzogen?

Client-seitig einbinden

Die bequemste Möglichkeit, LESS einzubinden, ist, die Umwandlung dem Client zu überlassen, also dem Browser desjenigen, der die Seite angefordert hat. Das nennt man auch Client-seitige Einbindung:

Client-seitige Einbindung von LESS

Dazu müssen wir dem Browser allerdings eine Umwandlungssoftware (= Compiler) mitgeben - in Form einer JavaScript-Bibliothek. Diese nennt sich less.js. Man kann sie z.B. bei GitHub runterladen.

In der HTML-Datei muss man sowohl die Less-Datei als auch den Compiler "less.js" verlinken:

<link rel="stylesheet/less" type="text/css" href="styles.less" />
<script src="less.js" type="text/javascript"></script>

Diese Methode hat den Vorteil, dass Sie jederzeit Ihre LESS-Datei ändern können, ohne sich Sorgen zu machen, ob die Änderung auch im CSS erscheint. Da die LESS-Datei bei jedem Aufruf der Seite von jedem Client neu übersetzt wird, wird auch jede neue Änderung immer berücksichtigt.

Die Methode hat aber auch klare Nachteile: Die Methode ist erstens unökonomisch. Jeder Browser muss die LESS-Datei erneut umwandeln. Doch eigentlich müsste man die LESS-Datei doch nur dann, wenn Sie vom Webseitenbetreiber geändert wird, einmal in CSS umwandeln. Selbst derselbe Browser, der die Seite zum zweiten Mal lädt, muss die LESS-Datei nochmal umwandeln. Zweitens erfordert die Methode eine externe Bibliothek auf der Client-Seite, die jedesmal an den Browser des Clients geschickt wird und damit - z.B. auf mobilen Endgeräten - wertvolle Bandbreite verschluckt. Das ist, als ob man eine Seite eigentlich auf englisch darstellen will - stattdessen verschickt man sie auf deutsch und schickt jedesmal ein Wörterbuch mit.

Das bringt uns zur zweiten Möglichkeit, LESS einzubinden.

Server-seitig einbinden

Die zweite (und sinnvollere) Möglichkeit, LESS einzubinden, ist es, auf dem Server die Umwandlung von LESS zu CSS durchzuführen, und immer nur die CSS-Datei zu schicken. Das nennt man auch Server-seitige Einbindung (der Server ist Ihr Rechner):

Server-seitige Einbindung von LESS

Zu beachten ist hier, dass Sie jedesmal, wenn Sie die LESS-Datei ändern, die Umwandlung erneut durchführen müssen.

Das heißt, in der HTML-Datei ist die Einbindung wie mit 'normalen' CSS-Dateien:

<link href="css/style.css" rel="stylesheet">

Sie benötigen hier keine JavaScript-Bibliothek, die Sie dem Client mitgeben.

Sie müssen aber auf Ihrem Rechner einen Compiler haben, mit dem Sie die Umwandlung durchführen können. Also installieren Sie einen Less-Compiler auf Ihrem Rechner (= Server). Dieser Compiler heißt lessc (das "c" steht für Compiler) und kann mit Node installiert werden.

Haben Sie Node.js installiert, können Sie folgendes eingeben:

npm install -g less

Das -g steht für "global" und heißt, dass Sie anschließend das Less in allen Verzeichnissen ausführen können.

Hinweis (MacOS, Linux): Es kann sein, dass Sie nicht als Admin auf Ihrem Konto arbeiten. Dann hilft es ein sudo davor zu packen, um nur für dieses Kommando als "super user" (su) tätig zu sein (sudo steht für "superuser do").

sudo npm install -g less

Sie müssen anschließend noch Ihr Passwort eingeben.

Haben Sie die Installation erfolgreich vollzogen, können Sie den Compiler lessc benutzen, um Ihre Datei style.less in eine CSS-Datei namens style.css zu übersetzen:

lessc style.less style.css

Wie Sie sehen, müssen Sie sowohl den Namen der LESS-Datei als auch den Namen den neuen CSS-Datei angeben.

Hinweis (Windows): Auf Windows-Rechnern müssen Sie den Pfad PATH erweitern, damit Windows das Kommando "lessc" findet (s.o.), zum Beispiel so

PATH=%PATH%;C:\users\kipp\AppData\Roaming\npm

11.3.3 Übung

Schauen Sie sich die folgende Seite an: Homepage.

Es handelt sich um die vereinfachte Startseite dieses Skripts. Laden Sie sich aus dem Browser sowohl die HTML-Seite als auch die CSS-Datei runter und vereinfachen Sie die CSS-Datei mit Hilfe von LESS.

Die HTML-Seite bekommen Sie mit Rechtsklick auf den Link oben und "Ziel speichern unter...". Die CSS-Datei bekommen Sie, wenn Sie sich den Quelltext im Browser anschauen und dort auf den Link zur CSS-Datei klicken.

11.4 Tasks automatisieren (Grunt)

Grunt ist ein Werkzeug, das es erlaubt, eine Reihe von Aufgaben (Tasks) zu automatisieren, z.B. die Verwendung von Precompiler (Less/Sass) oder das Minifizieren von Dateien. Auch ganz einfache Aufgaben wie das Verschieben, Kopieren, Umbenennen und Löschen von Dateien lässt sich in Grunt definieren.

Grunt funktioniert modular: für jeden möglichen Task gibt es ein sogenanntes Plugin. Man installiert nur genau die Plugins, die man benötigt. In einer Konfigurationsdatei gibt man an, welche Plugins installiert sein müssen und welcher Tasks wann und wie genau ausgeführt werden soll.

Ein Tool wie Grunt ist bei einem größeren Webseiten-Projekt unvermeidlich. Üblicherweise hält man alle Dateien, die man ständig verändert, in einem eigenen Ordner src (sources) und lässt sich von Grunt die auslieferungsfähige Version der Webseite in einen anderen Ordner dist (distribution) generieren. Diese Trennung ist enorm wichtig.

Grunt wird auch als Task Runner bezeichnet. Dies geschieht in der Sprache JavaScript. Eine Alternative zu Grunt ist Gulp. Java-Entwickler kennen das Tool Ant, das eine ähnliche Funktion im Java-Entwicklungs-Workflow hat.

11.4.1 Installation

Zunächst müssen wir Grunt installieren. Dazu sollten Sie bereits Node.js und damit den Packagemanager npm installiert haben (s.o.).

Sobald Sie Node.js installiert haben, öffnen Sie ein Terminal und schreiben:

npm install -g grunt-cli

Das "cli" steht für command line interface und heißt nur, dass Sie Grunt über das Terminal (über commands) bedienen werden.

Das "-g" bedeutet, dass die Installation global (und nicht nur für dieses Projekt) gültig ist, d.h. Sie müssen die obige Zeile nie wieder auf diesem Rechner/System ausführen.

Mac User: Es kann sein, dass Sie ein sudo ganz an den Anfang setzen und anschließend Ihr Passwort eingeben müssen.

11.4.2 Projekt

Erstellen Sie ein neues Node-Projekt wie im Abschnitt "Node-Projekt erstellen" beschrieben (s.o.). Wir gehen davon aus, dass das Projekt "myproject" heißt.

Sie haben in dem Verzeichnis jetzt eine Datei "package.json".

Jetzt installieren Sie in dieses Projekt Grunt und geben mit "--save-dev" an, dass in "package.json" verzeichnet werden soll, dass dieses Projekt Grunt benötigt.

npm install grunt --save-dev

(bei einer Fehlermeldung wieder sudo verwenden.)

In "package.json" sehen Sie jetzt die Abhängigkeit:

"devDependencies": {
    "grunt": "^1.0.3",
}

Datei Gruntfile.js

Grunt soll ja verschiedene Dienste, genannt Tasks, bei Ihrer Webentwicklung automatisieren. Diese Tasks werden in einer Konfigurationsdatei definiert: Gruntfile.js

Erstellen Sie eine Textdatei "Gruntfile.js", die zunächst folgendes enthält:

module.exports = function(grunt) {

  // ein einziger Task
  grunt.registerTask('default', 'Einfacher Task', function() {
   grunt.log.writeln('Hello world').ok();
  });

};

Sie sehen hier eine "Hülle" ("module.exports ..."), in der alle Grunt-relevanten Informationen stehen.

Außerdem ist hier ein einziger Task definiert. Dieser Default-Task wird ausgeführt, wenn man "grunt" auf dem Terminal eingibt.

Der Task besteht aus

In Grunt heißt ein solcher Task Basic Task.

Tippen Sie jetzt auf der Konsole:

grunt

Sie sollten sehen:

Running "default" task
Hello world
OK

Done.

Verzeichnisstruktur

Für unsere Beispiele legen wir folgende Unterverzeichnisse an:

src
dist

Im Verzeichnis src (source) legen wir die Dateien ab, mit denen wir aktiv arbeiten, z.B. HTML-Dateien oder LESS-Dateien.

Im Verzeichnis dist (distribution) kommen dann die Dateien, die teilweise von Grunt generiert werden. Wenn Grunt durchgelaufen ist, sollte ist dist die fertige Webseite liegen, die man dann hochladen kann.

11.4.3 Tasks

Nachdem wir Grunt lediglich zum Laufen gebracht haben, bauen wir jetzt echte Tasks ein.

Erster Task: LESS

Mit unserem ersten Task möchten wir unsere LESS-Datei/en automatisch in CSS-Dateien umwandeln. Dazu müssen wir ein Plugin installieren, das diesen Task zur Verfügung stellt. Im nächsten Schritt konfigurieren wir den Task, d.h. wir sagen, welche Datei genau umgewandelt werden soll und wie diese nach der Umwandlung heißen soll.

Wir installieren zunächst das LESS-Plugin für Grunt (siehe auch grunt-contrib-less):

npm install grunt-contrib-less --save-dev

Das "--save-dev" sorgt dafür, dass in "package.json" verzeichnet wird, dass wir das LESS-Plugin benötigen (und in welcher Version). Wenn Sie sich package.json ansehen, sehen Sie einen neuen Eintrag unter "devDependencies":

{
  "name": "myproject",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "grunt": "^1.0.3",
    "grunt-contrib-less": "^2.0.0"
  }
}

Wie bereits erwähnt werden die Dateien des Plugins in einem Unterverzeichnis namens node_modules ablegt.

Jetzt erweitern wir unser Gruntfile und sehen im wesentlichen drei Teile:

Teil 1 enthält die Konfiguration der Tasks. In unserem Fall wird hier gesagt, welches LESS-File in welches CSS-File gewandelt werden soll.

Teil 2 besteht aus Befehlen zum Laden notwendiger Plugins. Diese Plugins müssen zuvor mit npm installiert worden sein. In Teil 2 werden diese Plugins lediglich in Grunt geladen.

Teil 3 baut dann verschiedene Tasks zu einem neuen Task 'default' zusammen. In Grunt heißt ein solcher Task Alias Task. Hier besteht der Task nur aus einem Task (LESS), man kann aber eine Liste von mehreren Tasks in den eckigen Klammern angeben, die dann hintereinander aufgerufen werden.

Im Gruntfile sieht das so aus:

module.exports = function(grunt) {

  // (1) Konfiguration der Tasks
  grunt.initConfig({

    // Verwende Abhängigkeiten aus Projektkonfiguration
    pkg: grunt.file.readJSON('package.json'),

    // Less-Dateien in CSS umwandeln
    less: {
      build: {
        files: {
          'dist/css/style.css': 'src/less/style.less'
        }
      }
    }

  });

  // (2) Laden der Plugins
  grunt.loadNpmTasks('grunt-contrib-less');

  // (3) Alias-Task definieren
  grunt.registerTask('default', ['less']);

};

Bevor Sie das ganze testen, müssen Sie noch ein Verzeichnis src/less anlegen und dort eine LESS-Datei style.less hinterlegen, z.B.

@hintergrund: #000;
@schrift: yellow;
@spezial: red;

body {
  background-color: @hintergrund;
  color: @schrift;
}

h1 {
  color: @spezial;
}

Wenn Sie jetzt Grunt starten:

grunt

sehen Sie diese Ausgabe

Running "less:build" (less) task
>> 1 stylesheet created.

Done.

Außerdem sollten Sie die CSS-Datei "style.css" vorfinden:

body {
  background-color: #000;
  color: yellow;
}
h1 {
  color: red;
}

Zweiter Task: Minifizieren

Als nächstes möchten wir das CSS-File "minifizieren", d.h. es werden Leerzeichen und Zeilenumbrüche rausgeworfen, um Speicher zu sparen.

Zunächst installieren Sie das Plugin "cssmin" für Grunt (siehe auch grunt-contrib-cssmin):

npm install grunt-contrib-cssmin --save-dev

In "package.json" sehen Sie eine neue Abhängigkeit:

"devDependencies": {
  "grunt": "^1.0.3",
  "grunt-contrib-cssmin": "^3.0.0",
  "grunt-contrib-less": "^2.0.0"
}

Jetzt müssen wir unseren Task im "Gruntfile.js" an drei Stellen einbauen:

  1. Im ersten Teil legen wir die Konfiguration für den Task "cssmin" an und spezifizieren Ausgangsdatei/en (src) und Zieldatei (dest).
  2. Im zweiten Teil laden wir das Plugin "cssmin"
  3. Im dritten Teil fügen wir den Task "cssmin" zum Alias-Task hinzu; hier spielt die Reihenfolge eine Rolle, denn genau so werden die Tasks hintereinander ausgeführt
module.exports = function(grunt) {

  // (1) Konfiguration
  grunt.initConfig({

    // Verwende Abhängigkeiten aus Projektkonfiguration
    pkg: grunt.file.readJSON('package.json'),

    // Less-Dateien in CSS umwandeln
    less: {
      build: {
        files: {
          'dist/css/style.css': 'src/less/style.less'
        }
      }
    },

    // CSS-Datei minifizieren
    cssmin : {
        target : {
            src : ["dist/css/style.css"],
            dest : "dist/css/style.min.css"
        }
    }

  });

  // (2) Plugins
  grunt.loadNpmTasks('grunt-contrib-less');
  grunt.loadNpmTasks('grunt-contrib-cssmin');

  // (3) Taskdefinition
  grunt.registerTask('default', ['less', 'cssmin']);
};

Starten Sie Grunt

grunt

Auf der Konsole sehen Sie, wie viele Dateien umgewandelt wurden, und wie viel Speicherplatz gespart wurde.

Running "less:build" (less) task
>> 1 stylesheet created.

Running "cssmin:target" (cssmin) task
>> 1 file created. 73 B → 51 B

Done.

Wenn Sie sich "style.min.css" ansehen (z.B. mit less), sehen Sie das minifizierte CSS auf einer einzigen Zeile:

body{background-color:#000;color:#ff0}h1{color:red}

Dritter Task: Kopieren

Jetzt möchten wir noch unsere HTML-Dateien, die wir im Verzeichnis src verwalten, ins Verzeichnis dist einfach rüberkopieren. Dazu benötigen wir das Plugin copy (siehe auch grunt-contrib-copy):

npm install grunt-contrib-copy --save-dev

Wir passen anschließend unser Gruntfile an. Die Konfiguration sieht so aus:

copy: {
  main: {
    expand: true,
    cwd: 'src',
    src: '*html',
    dest: 'dist/',
  },
}

Das Laden so:

grunt.loadNpmTasks('grunt-contrib-copy');

Und unser neuer Default-Taks beinhaltet das Kopieren:

grunt.registerTask('default', ['less', 'cssmin', 'copy']);

Vierter Task: Löschen

Zu guter letzt setzen wir einen Task vor alle anderen: wir löschen das Verzeichnis dist zu Beginn unseres Prozesses, um sicherzugehen, dass sich keine Altlasten in diesem Verzeichnis ansammeln.

Dazu installieren wir das Plugin clean (siehe auch grunt-contrib-clean):

npm install grunt-contrib-clean --save-dev

Und passen unser Gruntfile an. Hier nochmal in voller Schönheit:

module.exports = function(grunt) {

  // (1)
  grunt.initConfig({

    // Verwende Abhängigkeiten aus Projektkonfiguration
    pkg: grunt.file.readJSON('package.json'),

    // Verzeichnis "dist" komplett löschen
    clean: ["dist/"],

    // Less-Dateien in CSS umwandeln
    less: {
      build: {
        files: {
          'dist/css/style.css': 'src/less/style.less'
        }
      }
    },

    // CSS-Datei minifizieren
    cssmin : {
        target : {
            src : ["dist/css/style.css"],
            dest : "dist/css/style.min.css"
        }
    },

    // HTML-Dateien kopieren
    copy: {
      main: {
        expand: true,
        cwd: 'src',
        src: '*html',
        dest: 'dist/',
      },
    }

  });

  // (2)
  grunt.loadNpmTasks('grunt-contrib-less');
  grunt.loadNpmTasks('grunt-contrib-cssmin');
  grunt.loadNpmTasks('grunt-contrib-copy');
  grunt.loadNpmTasks('grunt-contrib-clean');

  // (3)
  grunt.registerTask('default', ['clean', 'less', 'cssmin', 'copy']);
};

Beim Aufruf von Grunt sehen wir noch Informationen zu den Kopier- und Löschvorgängen:

Running "clean:0" (clean) task
>> 1 path cleaned.

Running "less:build" (less) task
>> 1 stylesheet created.

Running "cssmin:target" (cssmin) task
>> 1 file created. 73 B → 51 B

Running "copy:main" (copy) task
Copied 1 file

Done.

Tasks separat aufrufen

Sie können Grunt auch mit einem spezifischen Task aufrufen:

grunt clean

Dies ruft z.B. nur das "clean" auf:

Running "clean:0" (clean) task
>> 1 path cleaned.

Done.

11.4.4 Mehrseitige Website zusammenbauen

Ein typisches Problem bei mehrseitigen Websites ist, dass der grobe Rahmen (Kopf, Fuß, Navigation) bei allen Seiten (fast) gleich ist und nur die Inhalte (z.B. alles innerhalb von <body>) verschieden.

Mit Assemble können Sie elegant zwischen dem groben Rahmen, genannt "Layout", und den Inhalten, genannte "Pages", trennen. Mit einem Mechanismus, der Handlebars gennant wird, können Sie auch den Rahmen für einzelne Seiten anpassen (typisches Beispiel: der Seitentitle unter <title> sollte bei jeder Seite anders lauten).

Wir zeigen hier anhand eines einfachen Beispiels, wie ein solches Projekt aussehen könnte.

Wir erzeugen zunächste ein Node-Projekt in einem eigenen Verzeichnis:

npm init

Anschließend installieren wird Grunt:

npm install grunt --save-dev

Zusätzlich benötigen wir das Plugin "grunt-assemble":

npm install grunt-assemble --save-dev

Jetzt erstellen wir Layout und Beispielseiten. Richten Sie zunächst folgende Verzeichnisstruktur ein:

src
src/layouts
src/pages

Layout

Das Layout definieren wir in der Datei "src/layouts/default.hbs".

<!DOCTYPE html>
<html lang="de" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>{{ title }}</title>
  </head>
  <body>
    {{> body}}
  </body>
</html>

Dabei verwenden Sie an zwei Stellen Platzhalter: {{ title }} für den Seitentitel und {{> body}} für den Body. Diese Platzhalter sind in Handlebars-Syntax geschrieben (handlebars, weil die geschweiften Klammern wie Fahrradlenker aussehen) und funktionieren so ähnlich wie Variablen. Dort werden später Inhalte eingefügt.

Seiten

Die Seiten enthalten die wesentlichen Inhalte der späteren HTML-Seiten. Wir erstellen hier zwei Beispielseiten.

Erstellen Sie zunächst eine Datei "src/pages/index.hbs". Im oberen Bereich können Variablen gesetzt werden. Hier wird lediglich die Variable "title" gesetzt. Im Hauptbereich befindet sich dann der Text, der oben in {{> body}} eingesetzt wird:

---
title: Start
---
<h1>Das ist die Startseite</h1>

<p>
  Lorem ipsum dolor sit amet, ...
</p>

Grunt wird diese zwei Komponenten später in das Layout einfügen, so dass die folgende HTML-Datei "index.html" entsteht:

<!DOCTYPE html>
<html lang="de" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>Start</title>
  </head>
  <body>
  <h1>Das ist die Startseite</h1>

  <p>
    Lorem ipsum dolor sit amet, ...
  </p>
  </body>
</html>

Wir erstellen noch eine zweite Datei "src/pages/kontakt.hbs". Hier definieren wird einen anderen Titel und Seiteninhalt.

---
title: Kontakt
---
<h1>Kontakt</h1>

<p>
  Sie finden mich ...
</p>

Auch hier setzt Grunt später die Inhalte in die Layoutdatei, so dass eine HTML-Seite "kontakt.html" entsteht.

Grunt konfigurieren

Grunt soll jetzt die Layout-Datei nehmen

src/layout/default.hbs

und für jede Seiten-Datei aus

src/pages/index.hbs
src/pages/kontakt.hbs

eine HTML-Datei erzeugen, die dann in den Ordner dist geschrieben wird:

dist/index.html
dist/kontakt.html

Wir konfigurieren das wie folgt im Gruntfile:

module.exports = function(grunt) {

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),

        assemble: {
            options: {
                layout: "src/layouts/default.hbs",
                flatten: true
            },
            pages: {
                files: {
                    'dist/': ['src/pages/*.hbs']
                }
            }
        }
    });

    grunt.loadNpmTasks('grunt-assemble');

    grunt.registerTask('default', ['assemble']);
};

Wenn Sie Grunt aufrufen, sehen Sie:

Running "assemble:pages" (assemble) task
Assembling dist/index.html OK
Assembling dist/kontakt.html OK
>> 2 pages assembled.

Done.

Im Verzeichnis dist können Sie jetzt die resultierenden HTML-Seiten sehen.

Markdown

Wenn Sie schnell Ihre Seiten schreiben möchten, können Sie Markdown verwenden. Markdown bietet eine vereinfachte Syntax für häufige Formatierungen wie Überschriften und Hervorhebungen.

Die Startseite können Sie dann so schreiben. Der Bereich, in dem Markdown verwendet wird, wird mit zwei Handlebars-Helpern markiert:

---
title: Start
---
{{#markdown}}
# Das ist die Startseite

Lorem ipsum dolor sit amet, ...
{{/markdown}}

Eine Übersicht über die Markdown-Syntax finden Sie auf dem Markdown Cheatsheet der Assemble-Webseite.