1. Einführung in Pug

Pug ist eine Template-Engine für Express, der Middlware- und Routing-Lösung für Node.js. Sie ist der Standard für Express. Wenn Sie sich also intensiv mit Node.js und Express auseinandersetzen, führt kein Weg an Pug vorbei.

1.1 Übersicht

Pug nutzt eine vereinfachte Darstellung der HTML-Seite durch simple Textbefehle. Praktischerweise entsprechen diese den Namen der HTML-Tags. Da HTML eine Hierarchie aufbaut und Pug keine schließenden Tags kennt, muss die Baumstruktur anders entstehen. Pug nutzt dazu Einrückungen im Texteditor. 2 Leerzeichen zeigen an, dass das folgende Element ein Kindelement ist.

Vorbereitung

Pug setzt voraus, dass Sie mit node.js arbeiten und die Middleware Express nutzen. Der einfachste Weg zu einer funktionierenden Umgebung geht über ein schrittweises Abarbeiten der Bausteine einer node.js-Installation.

Damit steht die Umgebung, und der Beschäftigung mit Pug steht nichts im Weg.

Installationsanleitung

Zur Installation gibt es wenig Besonderheiten. Pug benötigt Express. Falls dies mit der Videoanleitung bereits installiert wurde, kann dieser Schritt überprungen werden. Ansonsten folgen Sie der Schrittfolge hier.

Installieren Sie nun das Pug-Paket. Ich habe meine Projekte unter /home/joerg/Apps und für dieses Bändchen dann unter *Pug* abgelegt. Legen Sie dann einen Ordner views an, in dem eine erste Testseite entstehen wird (sie befinden sich in Apps):

1 mkdir Pug
2 cd Pug
3 npm install express
4 npm install Pug
5 npm init
6 npm install express --save
7 mkdir views
Abbildung: Beschreibung der Applikation
Abbildung: Beschreibung der Applikation

npm init erstellt die Node.js-Applikation. Dabei wird eine Paket-Datei erzeugt, deren Werte interaktiv abgefragt werden. Die erzeugte Paket-Datei kann noch manuell angepasst werden.

Legen Sie in dem neu erstellten Applikationsverzeichnis *Pug* eine Datei mit dem Namen index.js an. Sie hat folgenden Inhalt:

1 var express = require('express');
2 var app = express();
3 
4 app.get('/', function (req, res) {
5   res.send('Hallo Express!');
6 });
7 
8 var server = app.listen(3000, function () {});

Starten Sie nun den Node-Server:

1 npm start
Abbildung: Start der Applikation
Abbildung: Start der Applikation

Geben Sie nun im Browser auf dem Entwicklungssystem folgende URL ein: http://localhost:3000. Sie sollten dann die “Hallo Express!”-Ausgabe sehen.

Abbildung: Ausgabe der Seite
Abbildung: Ausgabe der Seite

1.2 Applikationsstruktur

Express bietet eine Reihe spannender Funktionen. Ich will hier jedoch nur auf Pug eingehen und deshalb ist das manuelle Erzeugen und nutzen einer View einfacher. Lesen Sie “Jörgs Webbändchen” zu Express, um mehr über die Applikationsstruktur herauszufinden.

Die einfachste Nutzung von Pug besteht aus zwei Bausteinen. Zum einen die erste View, index.pug:

Datei: index.pug
1 doctype html
2 html(lang='en')  
3   head  
4     title= title  
5   body!= body  
6     h1= title

Zum anderen wird das “Hallo Express”-Beispiel so verändert, dass nun statt des statischen Texts die View benutzt wird:

Datei: index.js
 1 var express = require('express');
 2 var app = express();
 3 app.set('view engine', '*Pug*');
 4 
 5 app.get('/', function (req, res) {
 6   res.render('index', { 
 7     title: 'Hallo *Pug*!' 
 8   });
 9 });
10 
11 var server = app.listen(3000, function () {});

Zum einen wird hier Pug als Standard vereinbart, sodass keine Dateierweiterung angegeben werden muss und das passende Modul vorab geladen werden kann. Dies passiert durch:

app.set('view engine', 'pug');

Dann wird statt res.send die Funktion res.render benutzt. Der erste Parameter ist der Name der View, der ohne Pfad (standardmäßig wird im view-Ordner gesucht) und ohne Dateierweiterung (standardmäßig wird nun *Pug* benutzt) angegeben werden kann. Der zweite Parameter ist ein Objekt, dass lokale Variablen für die View bestimmt. Jede Eigenschaft des Objekts wird als lokale Variable bereitgestellt. Im Beispiel ist das der Wert title.

1.3 Pug-Views

Statt HTML schreiben Sie ab jetzt die Ansichtsseiten in Pug. Noch einmal das eben benutzte Beispiel:

Datei: index.pug
1 doctype html
2 html(lang='en')  
3   head  
4     title= title  
5   body!= body  
6     h1= title

Auf jeder Zeile der View steht zuerst ein HTML-Tag. Statt der Schreibweise in XML-Form (<title></title>) nimmt Pug hier eine vereinfachte Darstellung.

title= title

Der linke Teil ist das HTML-Element. Es folgt ein Gleichheitszeichen, dass die Kodierung bestimmt, also die Behandlung von HTML-spezifischen Entitäten wie < oder >. Dann folgt JavaScript. Da eine lokale Variable mit dem Namen title vereinbart wurde, wird dieser Ausdruck hier hingeschrieben. Analog funktioniert das mit h1, dass unterhalb des body-Elements steht. Der Umgang mit body zielt darauf ab, dass Views üblicherweise auf Stammseiten (Layout- oder Master-Seiten) basieren und der eigentliche Inhalt über die Variable body (rechts im Ausdruck) zugeordnet wird. Da HTML aus einer Seite direkt übernommen werden soll, wird der Operator != benutzt, der nicht codiert.

Abbildung:Ausgabe durch die View
Abbildung:Ausgabe durch die View

Umgang mit Teil-Ansichten

Teil-Ansichten (partial views) erlauben das Strukturieren von Views. Eine Pug-View sieht beispielsweise folgendermaßen aus:

Datei: index.Pug
1 doctype html
2 html(lang='en')  
3   head  
4     title= title  
5   body!= body  
6     include navigation
7     h1= title

Mit dem Befehl include wird eine weitere View eingebunden, navigation.pug. Beachten Sie, dass diese ohne Anführungszeichen und Klammern angegeben wird.

Diese Navigation wird nun in einer weiteren Datei erstellt: views/navigation.pug:

Datei: navigation.pug
1 div#navigation
2   a(href='/') home
Abbildung
Abbildung

Umgang mit Layout-Seiten

Eine Layout-Seite ist ein Master, eine Stammseite deren Inhalte von Inhaltsseiten bestimmt werden. Das entspricht der Layout-Seite in ASP.NET MVC oder der Master-Seite in ASP.NET.

Eine Layout-Seite sieht beispielsweise folgendermaßen aus:

Datei: index.pug
1 doctype html
2 html(lang='en')  
3   head  
4     title= title  
5   body!= body  
6     include navigation

Dies unterscheidet sich in kaum von dem vorherigen Beispiel. Lediglich das h1-Element am Ende fehlt.

Im nächsten Schritt wird die Inhaltsseite erstellt. Sie heißt views/content.Pug**:

Datei: content.pug
1 extends index
2 
3 h1= title
4   a(href='http://www.joergkrause.de/') Jörg &lt;Is A Geek&gt;\
5  Krause

Sie verweist auf die Layout-Seite. Nun wird das Startskript angepasst, denn Pug rendert zuerst die Inhaltsseite, die ihrerseits die Layout-Seite aufruft.

Datei: index.js
 1 var express = require('express');
 2 var app = express();
 3 app.set('view engine', 'pug');
 4 
 5 app.get('/', function (req, res) {
 6   res.render('content', { 
 7     title: 'Hallo Pug!' 
 8   });
 9 });
10 
11 var server = app.listen(3000, function () {});

Beachten Sie die res.render-Funktion, die nun content statt vorher index aufruft (Zeile 5).

Jetzt kann der node-Server gestartet werden (im Ordner wo die Datei package.json steht):

npm start

Soweit der Standardport nicht anderweitig vergeben wurde zeigt der Browser die gerenderte HTML-Seite nun an:

http://127.0.0.1:3000/

Der Einstiegspunkt ist der Aufruf von res.render mit dem Argument der Inhaltsseite, content.Pug**. Die Engine sorgt dann für das Laden der Layout-Seite und die Verarbeitung. Der gesamte Vorgang findet also auf dem Server statt.

Abbildung: Ausgabe mit Layout-Seite
Abbildung: Ausgabe mit Layout-Seite

Dabei fällt auf, dass die Navigation verschwunden ist. Das ist das normale Verhalten. Denn nun wurde der Inhalt des body-Elements tatsächlich durch eine Inhaltseite geliefert und damit wird der statische Inhalt überschrieben. Freilich gibt es hier einige Optionen, dieses Verhalten zu verändern. Dies wird in der Sprachreferenz genau beschrieben.