Im Folgenden finden Sie eine systematische Sprachreferenz basierend auf der Original-Dokumentation. Der Einstieg in die online verfügbaren Informationen ist Github.
Doctype
Der typische HTML 5-Doctype wird direkt folgendermaßen geschrieben:
doctype html
Das erzeugte HTML sieht dann folgendermaßen aus:
<!DOCTYPE html>
Kurzschreibweisen
Wegen der häufigen Nutzung von Doctypes gibt es ein paar Kurzschreibweisen.
doctype html
Das erzeugte HTML sieht dann folgendermaßen aus:
<!DOCTYPE html>
doctype xml
Das erzeugte HTML sieht dann folgendermaßen aus:
<?xml version="1.0" encoding="utf-8" ?>
doctype transitional
Das erzeugte HTML sieht dann folgendermaßen aus:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
doctype strict
Das erzeugte HTML sieht dann folgendermaßen aus:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
doctype frameset
Das erzeugte HTML sieht dann folgendermaßen aus:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
doctype 1.1
Das erzeugte HTML sieht dann folgendermaßen aus:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
doctype basic
Das erzeugte HTML sieht dann folgendermaßen aus:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">
doctype mobile
Das erzeugte HTML sieht dann folgendermaßen aus:
<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">
Eigene Doctypes
Falls davon abweichende Doctypes notwendig sind, lässt sich folgende Syntax nutzen:
doctype html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN"
Folgendes HTML wird daraus erstellt:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN">
Optionen
Die Doctypes sind nicht nur eine Information für den Browser. Sie sollten unbedingt die Pug-Version nehmen, denn diese wirken sich auch auf den HTML-Generator aus, beispielsweise auf den Umgang mit schließenden Tags.
Hier der direkte Aufruf des Renderers mit dem Doctype ‚XHTML‘:
var pug = require('pug');
// Übersetzen
var fn = pug.compile('img(src="foo.png")',
{ doctype: 'xml' });
// Rendern
var html = fn({});
Folgendes HTML wird daraus erstellt:
<img src="foo.png"></img>
Wird dagegen HTML erzeugt, wird das Tag nicht geschlossen:
// Übersetzen
var fn = pug.compile('img(src="foo.png")',
{ doctype: 'html' });
// Rendern
var html = fn({});
Folgendes HTML wird daraus erstellt:
<img src="foo.png">
Attribute
Attribute sehen aus wie in HTML, die Argumente sind allerdings JavaScript, sodass hier einfach dynamisch gearbeitet werden kann.
W> ### Serverseitiges JavaScript
W> Beachten Sie, dass das JavaScript in Argumenten auf dem Server ausgeführt wird und aus Sicht des Clients statisches HTML gesendet wird.
a(href='google.com') Google
a(class='button', href='google.com') Google
Übersetzt sieht das folgendermaßen aus:
<a href="google.com">Google</a><a href="google.com" class="button">Google</a>
Alle üblichen JavaScript-Ausdrücke funktionieren problemlos. Sie werden mit -
abgetrennt, damit Pug sie nicht als HTML interpretiert:
- var authenticated = true
body(class=authenticated ? 'auth' : 'anon')
Übersetzt sieht das folgendermaßen aus:
<body class="auth"></body>
Mehrere Attribute lassen sich zur Verbesserung der Lesbarkeit auf mehrere Zeilen aufteilen:
input(
type='checkbox'
name='agreement'
checked
)
Übersetzt nach HTML sieht das folgendermaßen aus:
<input type="checkbox" name="agreement" checked="checked"/>
Nicht codierte Attribute
Standardmäßig werden alle Attribute codiert, d.h. Sonderzeichen werden durch entsprechende Entitäten ersetzt (<
durch > und >
durch < usw.). Mit den Zuweisungszeichen =
und !=
lässt sich das Verhalten steuern:
div(escaped="<code>")
div(unescaped!="<code>")
In HTML sieht das folgendermaßen aus:
<div escaped="<code>"></div>
<div unescaped="<code>"></div>
W> ### Vorsicht!
W> Es ist gefährlich bei Benutzereingaben, die an Sichten weitergeleitet werden, das Kodieren abzuschalten. Nutzer können sonst aktiven Code auf den Server einschleusen.
Logische-Attribute
Logische (boolean) Attribute werden in Pug als Funktionen dargestellt, die Argumente verarbeiten können, die ihrerseits true
oder false
ergeben. Wird kein Argument angegeben, ist der Standard true
.
input(type='checkbox', checked)
input(type='checkbox', checked=true)
input(type='checkbox', checked=false)
input(type='checkbox', checked=true.toString())
Übersetzt sieht das folgendermaßen aus:
<input type="checkbox" checked="checked"/>
<input type="checkbox" checked="checked"/>
<input type="checkbox"/>
<input type="checkbox" checked="true"/>
Wenn der Doctype des Dokuments HTML ist, werden die verkürzten Attribute benutzt, wie sie alle Browser verstehen:
doctype html
input(type='checkbox', checked)
input(type='checkbox', checked=true)
input(type='checkbox', checked=false)
input(type='checkbox', checked=true && 'checked')
Übersetzt sieht das folgendermaßen aus:
<!DOCTYPE html>
<input type="checkbox" checked>
<input type="checkbox" checked>
<input type="checkbox">
<input type="checkbox" checked="checked">
Stil-Attribute
Das style
-Attribut ist etwas komplexer, weil die Parameter ein Stil-Objekt darstellen. Im Gegensatz zur reinen HTML-Version, die nur als Zeichenkette gelesen werden kann, verarbeitet Pug hier in der Tat ein JSON-Objekt.
a(style={color: 'red', background: 'green'})
Dies sieht in HTML dann folgendermaßen aus:
<a style="color:red;background:green"></a>
I> ### JSON
I> JSON steht für JavaScript Object Notation. Es handelt sich um ein kompaktes Datenformat in für Mensch und Maschine einfach lesbarer Textform zum Zweck des Datenaustauschs zwischen Anwendungen. Jedes gültige JSON-Dokument soll gültiges JavaScript sein. Wird auf dem Server und auf dem Client mit JavaScript gearbeitet, handelt es sich bei JSON quasi um das natürliche Format zur Datenübertragung und Objektdefinition.
&-Attribute
Diese spezielle Form, genannt „und-Attribute“ (engl. „and attributes“) wird benutzt, um ein Objekt in Attribute zu zerlegen:
div#foo(data-bar="foo")&attributes({'data-foo': 'bar'})
In HTML wird dann daraus folgendes:
<div id="foo" data-bar="foo" data-foo="bar"></div>
Dabei muss es sich nicht um ein Objekt-Literal handeln, eine Variable die ein Objekt liefert eignet sich ebenso.
- var attributes = {'data-foo': 'bar'};
div#foo(data-bar="foo")&attributes(attributes)
Hier entsteht dasselbe HTML draus:
<div id="foo" data-bar="foo" data-foo="bar"></div>
W> Diese Funktion codiert HTML nicht. Wenn die Daten aus einer Benutzereingabe stammen ist eine explizite Untersuchung auf eingebettete Codes notwendig. Vergleichen Sie dazu auch den Umgang mit Mixins, die das Codieren immer übernehmen.
Umgang mit CSS-Klassen
CSS-Klassen werden durch Attribute oder Literale beschrieben.
Das class-Attribut
Das class
-Attribut kann wie jedes Attribut mit einer Zeichenkette benutzt werden. Nun kommt es häufig vor, dass mehrere Klassennamen gesetzt werden. Dafür sind auch Arrays erlaubt.
- var classes = ['btn', 'btn-default']
a(class=classes)
a.bing(class=classes class=['bing'])
Wie in Zeile 3 gezeigt, kann das Atribut wiederholt werden. Pug kombiniert die Einträge dann. In HTML wird dann daraus folgendes:
<a class="btn btn-default"></a>
<a class="btn btn-default bing"></a>
Wenn Klassennamen über Bedingungen gesetzt werden, muss meist eine separate Logik her. In Pug eignet sich dafür ein Objekt-Mapping:
- var curUrl = '/about'
a(class={active: curUrl === '/'} href='/') Home
a(class={active: curUrl === '/about'} href='/about') Über uns
Dies sieht in HTML dann folgendermaßen aus:
<a href="/">Home</a>
<a href="/about" class="active">Über uns</a>
Das Class-Literal
Noch einfacher ist die direkte Nutzung der Literale aus CSS:
a.button
Dies sieht in HTML dann folgendermaßen aus:
<a class="button"></a>
Eine Besonderheit bei den Literalen ist das <div>
-Tag. Dies ist der Standard, wenn kein Element angegeben wird:
.content
In HTML wird dann daraus folgendes:
<div class="content"></div>
ID-Literal
IDs nutzen die #idname-Syntax:
a#main-link
Dies sieht in HTML dann folgendermaßen aus:
<a id="main-link"></a>
Da das div
-Element sehr häufig benutzt wird, können Sie es weglassen:
#content
In HTML wird dann daraus folgendes:
<div id="content"></div>
Befehle
Befehle bringen interaktive Abschnitte in die Vorlage. Sie ähneln den Möglichkeiten von JavaScript, werden jedoch vor der Skript-Ebene verarbeitet. HTML kann direkt eingebettet werden.
Fallunterscheidung (case)
case
ist eine Prozessanweisung und entspricht dem switch
in JavaScript. Die case
-Zweige in JavaScript werden bei Pug als when
geschrieben:
- var friends = 10
case friends
when 0
p Du hast keine Freunde
when 1
p Du hast einen Freund
default
p Du hast #{friends} Freunde
In HTML wird dann daraus folgendes:
<p>Du hast 10 Freunde</p>
Weiterleitung zum nächsten Fall
Ebenso wie in JavaScript fällt die Anweisung zum nächsten Zweig durch, wenn keine Anweisung folgt:
- var friends = 0
case friends
when 0
when 1
p Du hast kaum Freunde
default
p Du hast #{friends} Freunde
In HTML wird dann daraus folgendes:
<p>Du hast kaum Freunde</p>
Erweiterung von Blöcken
Statt der mehrzeiligen Schreibweise können kurze Texte auf derselben Zeile platziert werden und sind dann auf diese Zeile begrenzt:
- var friends = 1
case friends
when 0: p Du hast keinen Freund
when 1: p Du hast einen Freund
default: p Du hast #{friends} Freunde
Das HTML sieht dann folgendermaßen aus:
<p>Du hast einen Freund</p>
Bedingungen (if)
Bedingungen sind ein elementarer Baustein in pug. Gegenüber JavaScript ist die Schreibweise geringfügig vereinfacht — so können Sie die Klammern um die Bedingung weglassen.
- var user = { description: 'Mustertext' }
- var authorised = false
#user
if user.description
h2 Beschreibung
p.description= user.description
else if authorised
h2 Beschreibung
p.description.
Benutzer hat keine Beschreibung,
füge eine hinzu...
else
h1 Beschreibung
p.description Benutzer hat keine Beschreibung
Die Eingabedaten bestimmen dann, welches HTML entsteht:
<div id="user">
<h2>Beschreibung</h2>
<p class="description">Mustertext</p>
</div>
Es gibt weiterhin das Schlüsselwort unless
für negierte Bedingungen:
unless user.isAnonymous
p Du bist als #{user.name} angemeldet
Dies ist vollkommen identisch zum folgenden Ausdruck:
if !user.isAnonymous
p Du bist als #{user.name} angemeldet
Iterationen
Mit each
und while
stehen zwei Möglichkeiten bereit, Schleifen zu bilden.
each
Die Anwendung von each
ist weitgehend intuitiv:
ul
each val in [1, 2, 3, 4, 5]
li= val
Das HTML wird auf Basis des Arrays auf dem Server gebildet:
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
Mit zwei Parametern besteht Zugriff auf den Index und den Laufwert:
ul
each val, index in ['zero', 'one', 'two']
li= index + ': ' + val
Das HTML zeigt, dass der Index 0-basiert ist:
<ul>
<li>0: zero</li>
<li>1: one</li>
<li>2: two</li>
</ul>
Werden Hashes (Objekt-Maps) benutzt, so lassen sich Index und Wert noch genauer bestimmen:
ul
each val, index in {1:'one',2:'two',3:'three'}
li= index + ': ' + val
Das HTML zeigt, dass der Index vom Quellobjekt bestimmt ist:
<ul>
<li>1: one</li>
<li>2: two</li>
<li>3: three</li>
</ul>
Statt der direkten Angabe lässt sich natürlich jeder JavaScript-Ausdruck benutzen, der eine passende Struktur erzeugt oder enthält:
- var values = [];
ul
each val in values.length ? values : ['Keine Werte']
li= val
Da das Array im Beispiel leer ist, wird folgendes HTML erzeugt:
<ul>
<li>Keine Werte</li>
</ul>
T> ### Alias-Namen
T> Das Schlüsselwort for
kann als Alias für each
benutzt werden.
while
Eine Schleife mit while
verfügt über eine Abbruchbedingung. Die Schleife wird durchlaufen. solange der Ausdruck true
ergibt.
- var n = 0
ul
while n < 4
li= n++
Das dynamisch erzeugte HTML sieht nun folgendermaßen aus:
<ul>
<li>0</li>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
JavaScript-Code
Mit Pug können JavaScript-Fragmente direkt in die Seite geschrieben werden. Diese Teile werden dann serverseitig ausgeführt. Es gibt dabei drei Arten von Code:
- Ungepufferte Codes
- Die Ergebnisse beim Verarbeiten werden sofort in die Ausgabe geschrieben.
- Gepufferte Codes
- Die Ergebnisse beim Verarbeiten werden zuerst in einen Puffer geschrieben und am Ende der Anweisung komplett gesendet.
- Gepufferte und nicht codierte Codes
- Die Ergebnisse beim Verarbeiten werden zuerst in einen Puffer geschrieben und am Ende der Anweisung komplett gesendet. Dabei erfolgt keine Codierung der Ausgabe.
Ungepufferte Codes
Ungepuffert und auch nicht codiert sieht das folgendermaßen aus:
- for (var x = 0; x < 3; x++)
li item
W> ### Vorsicht!
W> Wie in den vorangegangenen Beispielen sollten Sie Vorsicht bei der Umsetzung von Benutzereingaben walten lassen, um zu verhindern, dass in solche Konstrukte Code eingeschleust wird. Der eingeschleuste JavaScript-Code würde serverseitig ausgeführt werden.
Im HTML entsteht aus dem letzten Beispiel folgendes:
<li>item</li>
<li>item</li>
<li>item</li>
Dies funktioniert auch mit Blöcken (das -
-Zeichen ist alleinstehend abgesetzt und der folgende Text eingerückt):
-
list = ["Uno", "Dos", "Tres",
"Cuatro", "Cinco", "Seis"]
each item in list
li= item
Auch diese Schleife generiert pures HTML:
<li>Uno</li>
<li>Dos</li>
<li>Tres</li>
<li>Cuatro</li>
<li>Cinco</li>
<li>Seis</li>
Gepufferte Code
Der gepufferte Teil startet mit einem =
-Zeichen und gibt das Ergebnis der Berechnung in JavaScript aus. Hier die codierte Variante (beachten Sie die Einrückung auf Zeile 2):
p
= 'Dieser Code ist <kodiert>!'
Im HTML sehen Sie, wie die Sonderzeichen konvertiert wurden:
<p>Dieser Code ist <kodiert>!</p>
JavaScript-Ausdrücke lassen sich auch hier einsetzen:
p= 'Dieser Code ist' + ' <kodiert>!'
Es ergibt sich dasselbe Ergebnis wie im vorherigen Beispiel:
<p>Dieser Code ist <kodiert>!</p>
Gepufferte und nicht codierte Codes
Die Codierung startet wieder mit dem !=
-Operator. Beachten Sie auch hier, dass dies in Bezug auf Daten aus Benutzereingaben nicht sicher ist.
p
!= 'Dieser Code ist <strong>nicht</strong> kodiert!'
Das folgende HTML wird daraus erstellt:
<p>Dieser Code ist <strong>nicht</strong> kodiert!
</p>
Auch in dieser Nutzung können JavaScript-Ausdrücke eingesetzt werden:
p!= 'Dieser Code ist' + ' <strong>nicht</strong> kodiert!'
Das folgende HTML wird daraus erstellt:
<p>Dieser Code ist <strong>nicht</strong> kodiert!</p>
Kommentare
Kommentare werden wie in JavaScript geschrieben, werden dann jedoch in HTML-Kommentare konvertiert, also nicht komplett entfernt:
// Hier folgt etwas HTML:
p foo
p bar
Das folgende HTML wird daraus erstellt:
<!-- Hier folgt etwas HTML: -->
<p>foo</p>
<p>bar</p>
Wird hinter das Kommentarzeichen ein Strich gesetzt, wird der Kommentar entfernt und im HTML nicht wiederholt:
//- Dies ist nicht für die Öffentlichkeit
p foo
p bar
Das folgende HTML wird daraus erstellt:
<p>foo</p>
<p>bar</p>
Kommentarblöcke
Soll sich ein Kommentar über mehrere Zeilen erstrecken, so wird das Kommentarzeichen alleine auf eine Zeile gestellt:
body
//
So viel Text wie
Sie mögen
Das folgende HTML wird daraus erstellt:
<body>
<!--
So viel Text wie
Sie mögen
-->
</body>
Bedingte Kommentare
Der Internet Explorer kann Abschnitte bedingt ausführen, um abwärtskompatiblen HTML-Code zu schreiben. Pug hat dafür keine spezielle Syntax. Da jeder nicht weiter erkannte Text aber unverändert ausgegeben wird werden Zeilen, die mit dem <
-Zeichen beginnen, direkt ins HTML transportiert:
<!--[if IE 8]>
<html lang="en" class="lt-ie9">
<![endif]-->
<!--[if gt IE 8]><!-->
<html lang="en">
<!--<![endif]-->
Erben von Vorlagen
Zum Erben von Vorlagen wird das Schlüsselwort extends
benutzt. Damit lassen sich auch vordefinierte Bereiche der Layout-Seite gezielt überschreiben. Zuerst die Layout-Seite:
{title=“Datei: layout.pug“}
doctype html
html
head
block title
title Default title
body
block content
Die eigentliche Seite nutzt (erbt) nun diese Layout-Seite. Der Bereich block
und darin der Bereich title
wird überschrieben. Die Angaben sind freiwillig und wenn sie nicht vorhanden wären, würde der Inhalt der Layout-Seite angezeigt werden.
{title=“Datei: index.pug“}
extends layout
block title
title Meine Artikel
block content
h1 Hier steht der Inhalt
Das finale HTML sieht nun folgendermaßen aus:
<!doctype html>
<html>
<head>
<title>Meine Artikel</title>
</head>
<body>
<h1>Hier steht der Inhalt</h1>
</body>
</html>
{title=“Ausgabe der Musterseite“}
T> ### Komplexere Layouts
T> Die Vererbung der Layout-Seiten kann über mehrere Stufen gehen, d.h. in einer Layout-Seite kann eine weitere aufgerufen werden. So lassen sich komplexere verschachtelte Layouts entwerfen.
Details zum Vererben von Vorlagen
Das einfache Vererben von Vorlagen kann erweitert werden, indem mit block
Bereiche festgelegt werden, die gezielt überschrieben werden können. Ein „Block“ ist dabei pug-Code, der ersetzt werden kann. Der Vorgang ist rekursiv.
Wenn der Platzhalter mit Inhalt bestückt ist, fungiert dieser als Standard. Betrachten Sie die folgende Layout-Seite:
{title=“Datei: layout.pug“}
html
head
title My Site - #{title}
block scripts
script(src='/jquery.js')
body
block content
block foot
#footer
p Inhalt der Fußzeile
Diese wird nun mittels extends
benutzt. Die Seite index.pug im folgenden Beispiel überschreibt dabei die Blöcke scripts und content. Der Block foot bleibt dagegen unverändert und wird aus der Layout-Seite übernommen.
{title=“Datei: index.pug“}
extends layout
block scripts
script(src='scripts/jquery.js')
script(src='scripts/data.js')
block content
h1= title
each pet in pets
include pet
In einem Block können weitere Blöcke definiert werden, die bei weiteren Ableitungen verschachtelter Layout-Seiten wiederum überschrieben werden. Die weitere Layout-Seite sub-layout.pug wird folgendermaßen definiert:
{title=“Datei: sub-layout.pug“}
extends layout
block content
.sidebar
block sidebar
p nothing
.primary
block primary
p nothing
Die Seite page-b.pug nutzt diese abgeleitete Layout-Seite nun:
{title=“Datei: page-b.pug“}
extends sub-layout
block content
.sidebar
block sidebar
p nothing
.primary
block primary
p nothing
Die Blöcke sidebar und primary werden hier überschrieben.
Blöcken Inhalt voran- und hintenanstellen
Neben dem blanken Ersetzen lassen sich Inhalte auch voranstellen (prepend
) oder ergänzen (append
). Bei der Definition ändert sich erstmal nichts:
html
head
block head
script(src='/vendor/jquery.js')
script(src='/vendor/bootstrap.js')
body
block content
Weitere Skripte lassen sich nun wie folgt ergänzen:
extends layout
block append head
script(src='/scripts/data.js')
Das Schlüsselwort block
ist bei der Benutzung von prepend
oder append
optional:
extends layout
append head
script(src='/scripts/data.js')
T> ### Dateierweiterung
T> In diesem Beispiel wurde die Dateierweiterung .pug weggelassen. Diese ist optional, wenn der Standard .pug benutzt wird.
Filter
Filter dienen dazu, innerhalb des Quelltextes andere Sprachen zu nutzen. Typische Beispiele sind Markdown und CoffeeScript.
:markdown
# Markdown
I often like including markdown documents.
script
:coffee-script
console.log 'This is coffee script'
Der Sprachblock wird mit dem :
-Zeichen eingeleitet und entsprechend interpretiert. Das vorangegangene Beispiel sieht in HTML wie folgt aus:
<h1>Markdown</h1>
<p>I often like including markdown documents.</p>
<script>console.log('This is coffee script')</script>
W> ### Ausführzeitpunkt
W> Filter werden beim Übersetzen der Seite ausgeführt. Innerhalb des Filters können deshalb keine dynamischen Ausdrücke stehen. Die Ausführung ist dafür sehr schnell.
Partielle Seiten
Komplexe Seiten lassen sich in Teile — partielle Seiten — zerlegen. Das Einbinden erfolgt mit dem Schlüsselwort includes
und der Angabe des Dateinamens, gegebenenfalls mit dem relativen Pfad.
{title=“Datei: index.pug“}
doctype html
html
include ./parts/head.pug
body
h1 Meine Seite
p Welcome to my super lame site.
include ./includes/foot.pug
{title=“Datei: parts/head.pug“}
head
title Meine Seite
script(src='/javascripts/jquery.js')
script(src='/javascripts/app.js')
{title=“Datei: parts/foot.pug“}
#footer
p Copyright (c) foobar
Daraus entsteht folgendes HTML:
<!doctype html>
<html>
<head>
<title>My Site</title>
<script src='/javascripts/jquery.js'></script>
<script src='/javascripts/app.js'></script>
</head>
<body>
<h1>My Site</h1>
<p>Welcome to my super lame site.</p>
<div id="footer">
<p>Copyright (c) foobar</p>
</div>
</body>
</html>
Text einbinden
Partielle Seiten müssen nicht nur Pug sein, auch einfacher Text kann benutzt werden. Pug erkennt dies automatisch:
{title=“index.pug“}
doctype html
html
head
style
include style.css
body
h1 My Site
p Welcome to my super lame site.
script
include script.js
{title=“style.css“}
/* style.css */
h1 { color: red; }
{title=“script.js“}
// script.js
console.log('You are awesome');
Daraus entsteht folgendes HTML:
<!doctype html>
<html>
<head>
<style>
/* style.css */
h1 { color: red; }
</style>
</head>
<body>
<h1>My Site</h1>
<p>Welcome to my super lame site.</p>
<script>
// script.js
console.log('You are awesome');
</script>
</body>
</html>
Kombination aus Filtern und partiellen Seiten
Bei der Kombination aus Filtern und partiellen Seiten werden Seiten eingebunden, die Inhalte in anderen Sprachen enthalten.
{title=“Datei: index.pug“}
doctype html
html
head
title Ein Artikel
body
include:markdown article.md
Die eingeschlossene Seite wird hier als Markdown interpretiert:
{title=“Datei: article.md“}
# Überschrift in Markdown
Dieser Artikel wurde in Markdown erstellt
Daraus entsteht folgendes HTML:
<!doctype html>
<html>
<head>
<title>Ein Artikel</title>
</head>
<body>
<h1>Überschrift in Markdown</h1>
<p>Dieser Artikel wurde in Markdown erstellt.</p>
</body>
</html>
Vor allem die Kombination mit Markdown ist interessant, weil bereits vorliegende Inhalte unverändert übernommen werden können.
Interpolationen
Interpolationen ersetzen Variablen in Zeichenfolgen. Vergleichbare Techniken kennt wohl fast jede Programmiersprache. Pug kennt folgende Operatoren:
- Codierte Zeichenketten-Interpolation
- Nicht codierte Zeichenketten-Interpolation
- Tag-Interpolation
Codierte Zeichenketten-Interpolation
In der folgenden Vorlage werden einige Variablen definiert und dann in Ausdrücken eingesetzt, ohne erneut auf JavaScript-Syntax zuzugreifen:
- var title = "Einführung in Node.js";
- var author = "Joerg";
- var version = "<span>0.11</span>";
h1= title
p Zusammengestellt von #{author}
p #{version}
Das folgende HTML zeigt das Ergebnis der Interpolation:
<h1>Einführung in Node.js</h1>
<p>Zusammengestellt von Joerg</p>
<p> Für die Version: <span>0.11!</span></p>
Der Code zwischen #{
und }
wird ausgewertet, codiert und als gepuffertes Ergebnis an die Ausgabe gesendet. Der Ausdruck selbst kann wiederum JavaScript sein, sodass sogar hier komplexere Ausdrücke entstehen können.
- var msg = "ziemlich cool";
p Dies ist #{msg.toUpperCase()}
Daraus entsteht in diesem Fall ziemlich cooles HTML:
<p>Dies ist ZIEMLICH COOL</p>
Nicht codierte Zeichenketten-Interpolation
Falls Sicherheit nicht notwendig ist oder HTML gewünscht ist, geht auch hier wieder die nicht codierte Variante:
- var riskyQuote = "<em>Node braucht pug.</em>";
.quote
p Joerg: !{riskyQuote}
Das HTML wird unverändert ausgegeben:
<div class="quote">
<p>Joerg: <em>Node braucht pug.</em></p>
</div>
Tag-Interpolation
Interpolationen lassen sich auch direkt in Tags einsetzen. Hierzu wird #[]
benutzt.
p.
Wenn Sie sich den Quellcode auf #[a(target="_blank", href="https://github.com/pugjs/pug/blob/master/docs/views/reference/interpolation.pug") GitHub],
ansehen, finden Sie viele Stellen wo die Interpolation benutzt wird.
Hieraus ensteht recht kompaktes HTML:
<p>Wenn Sie sich den Quellcode auf <a target="_blank" href="https://github.com/pugjs/pug/blob/master/docs/views/reference/interpolation.pug"> GitHub</a>,
ansehen, finden Sie viele Stellen wo die Interpolation benutzt wird.
</p>
Der Renderer nutzt intern seinen Puffer zur Ablage und zum Weiterleiten, sodass dies besser ist als direkt HTML einzubinden.
Mixins (Funktionen)
Mixins erzeugen wiederverwendbare Blöcke aus Pug-Code. Damit lassen sich endlose Wiederholungen gleicher HTML-Bausteine vermeiden. Besonders im Zusammenhang mit Bootstrap lassen sich so komplexere Konstrukte vorbereiten und dann jederzeit einsetzen.
Ein Mixin (lies: Funktion) wird folgendermaßen deklariert:
mixin list
ul
li foo
li bar
li baz
Die Benutzung basiert auf einem speziellen Operator:
+list
+list
Die Benutzung wird mit dem +
-Zeichen eingeleitet. Im HTML ist davon nichts mehr zu finden:
<ul>
<li>foo</li>
<li>bar</li>
<li>baz</li>
</ul>
<ul>
<li>foo</li>
<li>bar</li>
<li>baz</li>
</ul>
Mixins sind JavaScript-Funktionen und können wie diese mit Parametern versehen werden:
mixin pet(name)
li.pet= name
ul
+pet('Katze')
+pet('Hund')
+pet('Vogel')
Folgendes HTML entsteht daraus:
<ul>
<li class="pet">Katze</li>
<li class="pet">Hund</li>
<li class="pet">Vogel</li>
</ul>
Mixin-Blöcke
Mixins können eine Block mit Pug-Code aufnehmen und gewinnen damit weiter an Dynamik:
mixin article(title)
.article
.article-wrapper
h1= title
if block
block
else
p Keine Inhalte
+article('Hallo pug')
+article('Hallo pug')
p Dies ist ein
p Artikel zu Node.js
Folgendes HTML entsteht daraus:
<div class="article">
<div class="article-wrapper">
<h1>Hallo pug</h1>
<p>Keine Inhalte</p>
</div>
</div>
<div class="article">
<div class="article-wrapper">
<h1>Hallo pug</h1>
<p>Dies ist ein</p>
<p>Artikel zu Node.js</p>
</div>
</div>
Mixin-Attribute
Ähnlich wie bei JavaScript-Funktionen können Mixins Parameter über ein implizites attributes
-Objekt aufnehmen:
mixin link(href, name)
//- attributes == {class: "btn"}
a(class!=attributes.class, href=href)= name
+link('/foo', 'foo')(class="btn")
Folgendes HTML entsteht daraus:
<a href="/foo" class="btn">foo</a>
T> Die Werte werden wieder automatisch codiert. Ist das nicht gewünscht, muss !=
benutzt werden. Eine Kombination mit den &attributes
ist ebenso möglich.
mixin link(href, name)
a(href=href)&attributes(attributes)= name
+link('/foo', 'foo')(class="btn")
Folgendes HTML entsteht daraus:
<a href="/foo" class="btn">foo</a>
Weitere Argumente
Ist die Anzahl der Argumente nur teilweise variabel, lässt sich eine Definition der Art „der ganze Rest“ aufbauen:
mixin list(id, ...items)
ul(id=id)
each item in items
li= item
+list('my-list', 1, 2, 3, 4)
Folgendes HTML entsteht daraus:
<ul id="my-list">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
Umgang mit Text
Einfacher Text wird nicht interpretiert und unverändert ausgegeben, auch wenn darin Steuerzeichen enthalten sind.
Text verbinden
Der |
-Operator („pipe“) setzt vorhergehende Zeilen mit Text einfach fort.
| Einfacher Text kann <strong>html</strong> enthalten
p
| Er muss immer alleine auf einer Zeile stehen
Der Text kommt unverändert in der HTML-Seite an:
Einfacher Text kann <strong>html</strong> enthalten
<p>Er muss immer alleine auf einer Zeile stehen</p>
Inline im Tag
Tags in Tags sind in HTML an der Tagesordnung. Denn in fast jedem Blockelement sind diverse Inline-Elemente zu finden (<span>
im <div>
). Text nach einem Element wird unverändert übernommen und kann HTML enthalten. Das ist oftmals einfacher, als die komplette Hierarchie zu definieren:
p Einfacher Text kann <strong>HTML</strong> haben
Das HTML kommt unverändert in der Seite an:
<p>Einfacher Text kann <strong>HTML</strong> haben</p>
Block im Tag
Oft werden große Blöcke mit Text benötigt. Skripte oder längere Stil-Definitionen sind gute Beispiele dafür. Hier wird selten Interaktivität verlangt. Um solch einen Block einzuleiten, wird dem Element-Befehl ein Punkt .
nachgestellt:
script.
if (usingpug)
console.log('you are awesome')
else
console.log('use pug')
Der Inhalt kommt unverändert in der Seite an:
<script>
if (usingpug)
console.log('you are awesome')
else
console.log('use pug')
</script>
Umgang mit Tags
Tags werden lediglich durch Ihren Namen beschrieben, ohne die Markup-Klammern. Die Hierarchie wird durch die Einrückung (zwei Leerzeichen) festgelegt.
ul
li Item A
li Item B
li Item C
Aus diesem Beispiel entsteht gültiges HTML:
<ul>
<li>Item A</li>
<li>Item B</li>
<li>Item C</li>
</ul>
Wenn der Doctype dies verlangt werden selbstschließende Elemente automatisch erzeugt. Für das Element img
sieht das folgendermaßen aus:
img
Hier entsteht gültiges HTML mit schließendem Tag:
<img/>
Erweiterungen von Blöcken
Verschachtelte Blöcke lassen, solange keine Inhalte folgen, auch in einer Zeile definieren. Dies erfolgt durch den :
-Operator. Dies spart Platz bei häufigen typischen Kombinationen, beispielsweise mit Hyperlinks:
a: img
Aus diesem Beispiel entsteht gültiges HTML wie folgt:
<a><img/></a>
Selbstschließende Tags
Einige Tags, wie img
, meta
und link
enthalten nie Inhalt. Sie sind deshalb selbstschließend, ausgenommen mit dem XML-Doctype. Solle dies unabhängig vom Doctype angezeigt werden, kann dies mit einem abschließenden /
-Zeichen erfolgen.
meta/
link(rel='stylesheet')/
Aus diesem Beispiel entsteht folgendes HTML:
<meta/>
<link rel="stylesheet"/>
Die Pug-API
Pug ist ein Paket das neben der Verarbeitung der Vorlagen einige Funktionen als Programmierschnittstelle (API) bereitstellt. Diese API wird nachfolgend kurz beschrieben.
API-Optionen
Jede Methode der API akzeptiert ein Optionen, die als JSON-Struktur übergeben werden:
{
filename: string,
doctype: string,
pretty: boolean | string,
self: boolean,
debug: boolean,
compileDebug: boolean,
cache: boolean,
compiler: class,
parser: class,
globals: Array.<string>
}
Die einzelnen Parameter haben folgende Bedeutung:
- filename
- Der Dateiname; wird beispielsweise in Ausnahmen angezeigt
- doctype
- Der Doctype, wenn dieser nicht als Teil einer Vorlage angegeben werden soll
- pretty
- Zeigt an, ob Leerzeichen zum ausgegebenen HTML hinzugefügt werden sollen, um lesbaren Code zu erzeugen. Wenn eine Zeichenkette angegeben wird, ist dies der Wert, der zum Einrücken benutzt wird, z.B.
\t
. - self
self
-Namensraum für lokale Variable (standardmäßigfalse
)- debug
- Protokolliert Ausgaben nach
stdout
- compileDebug
- Der Quellcode wird in die gerendete Ausgabe übertragen
- cache
- Funktionen werden gecachet. Schlüssel ist der Dateiname der Vorlage.
- compiler
- Ein alternativer Compiler kann angegeben werden.
- parser
- Ein alternativer Parser kann angegeben werden.
- globals
- Globale Variablen, die in allen Vorlagen bekanntgegeben werden
API-Funktionen
In allen Funktionen ist der Parameter options
das zuvor beschriebene Options-Objekt. Nicht alle Optionen sind in allen Fällen sinnvoll.
pug.compile(source, options)
Diese Funktion übersetzt Pug-Code, sodass dieser dann mehrfach mit verschiedene Werten ausgeführt werden kann. Gibt eine Funktion zurück, die ausgeführt werden kann. Der Befehl auf Zeile 2 erstellt die Funktion, auf Zeile 3 wird diese dann ausgeführt.
var pug = require('pug');
var fn = pug.compile('p pug ist cool!', options);
var html = fn(locals);
Dieses Skript erzeugt folgende Ausgabe:
<p>pug ist cool!</p>
pug.compileFile(path, options)
Diese Funktion übersetzt Pug-Code aus einer Datei, sodass dieser dann mehrfach mit verschiedenen Werten ausgeführt werden kann. Gibt eine Funktion zurück, die ausgeführt werden kann. sourcepath
ist der Pfad zur Pug-Datei. Der Befehl auf Zeile 2 erstellt die Funktion, auf Zeile 3 wird diese dann ausgeführt.
var pug = require('pug');
var fn = pug.compileFile('views/index.pug', options);
var html = fn(locals);
Dieses Skript erzeugt folgende Ausgabe, wenn die Datei index.pug den Text „p pug ist cool!“ enthält:
<p>pug ist cool!</p>
pug.compileClient(source, options)
Hier wird eine JavaScript-Funktion gerendert, die dann später clientseitig ausgeführt werden kann und dort das erstellte HTML erzeugt.
var pug = require('pug');
// Funktion erstellen
var fn = pug.compileClient('p pug ist cool!', options);
// Rendern der Funktion
var html = fn(locals);
Die Rückgabe ist dann JavaScript:
function template(locals) {
return "<p>pug ist cool!</p>";
}
pug.compileClientWithDependenciesTracked (source, options)
Diese Methode entspricht der vorhergehende methode compileClient
, erzeugt jedoch ein Objekt, das folgende Struktur hat:
{
'body': 'function (locals) {...}',
'dependencies': ['filename.pug']
}
Damit können Änderungen an Quelldateien überwacht werden. Ansonsten ist die einfache Variante zu bevorzugen.
pug.compileFileClient(path, options)
Hier wird eine JavaScript-Funktion gerendert, die dann später clientseitig ausgeführt werden kann und dort das erstellte HTML erzeugt. Die Quelle muss als Datei vorliegen.
Das Options-Objekt hat einen weiteren Parameter name
. Diese bestimmt den Namen der Funktion, die erzeugt wird und auf dem Client aufgerufen werden kann. Hier ein Beispiel mit einer Quelldatei pugFile.pug:
{title: „Datei: pugFile.pug“}
h1 Dies ist eine Vorlage
h2 Von #{author}
Diese wird nun dynamisch übersetzt (Zeile 4):
var fs = require('fs');
var pug = require('pug');
var jsOut = pug.compileFileClient('/views/pugFile.pug',
{
name: "templateFunction"
});
I> ### fs
I> Das Beispiel nutzt zum Dateizugriff das Standardmodul „fs“ aus der node.js-Distribution.
Nehmen Sie an, Sie wollen alle Ihre Vorlagen in eine einzige Datei übersetzen und diese dann an den Client übertragen. Dann kann die Ausgabe des letzten Beispiels jsOut folgendermaßen gespeichert werden:
fs.writeFileSync("templates.js", jsOut);
Die Datei templates.js, die daraus entsteht, enthält dann die oben definierte Funktion templateFunction:
{title: „Datei: templates.js“}
function templateFunction(locals) {
var buf = [];
var pug_mixins = {};
var pug_interp;
var locals_for_with = (locals || {});
(function (author) {
buf.push("<h1>Dies ist eine Vorlage</h1><h2>Von "
+ (pug.escape((pug_interp = author) == null ? '' : pug_interp))
+ "</h2>");
}.call(this, "author" in locals_for_with ?
locals_for_with.author : typeof author !== "undefined" ?
author : undefined)
);
return buf.join("");
}
Damit das funktioniert, muss auch die Laufzeitumgebung von Pug verfügbar sein. Sie steht unter dem Namen runtime.js zur Verfügung. Im HTML des Clients sieht das dann folgendermaßen aus:
<!DOCTYPE html>
<html>
<head>
<script src="/runtime.js"></script>
<script src="/templates.js"></script>
</head>
<body>
<h1>Dies ist eine Vorlage</h1>
<script type="text/javascript">
var html = window.templateFunction({author: "Joerg"});
var div = document.createElement("div");
div.innerHTML = html;
document.body.appendChild(div);
</script>
</body>
</html>
pug.render(source, options)
Diese Funktion rendert direkt in HTML:
var pug = require('pug');
var html = pug.render('p Pug ist cool!', options);
Das HTML sieht nun so aus:
<p>Pug ist cool!</p>
pug.renderFile(filename, options)
Auch diese Funktion rendert direkt in HTML, nutzt aber als Eingabe eine Datei:
var pug = require('pug');
var html = pug.renderFile('views/file.pug', options);
Die Kommandozeile
Die Kommandozeile kann Hilfsfunktionen direkt ausführen, beispielsweise Seiten vorab in statisches HTML übersetzen.
Installation
Die Installation erfolgt via npm (-g steht für global):
$ npm install pug -g
I> ### CLI
I> Kommandzeilenwerkzeuge werden oft als „CLI“ bezeichnet — Command Line Interface.
Benutzung und Optionen
Die Benutzung der Kommandozeile sieht folgendermaßen aus:
$ pug [options] [dir|file ...]
{title=“Tabelle: Optionen Pug-CLI“}
Optionen | |
---|---|
-h, --help |
Hilfe zur Benutzung |
-V, --version |
Version der Bibliothek |
-O, --obj <path|str> |
JavaScript-Optionen oder JSON-Datei mit einem passenden Objekt darin |
-o, --out <dir> |
Ausgabeverzeichnis für das HTML |
-p, --path <path> |
Dateipfad zum Auflösen von includes |
-P, --pretty |
HTML Ausgabe wird lesbar gestaltet |
-c, --client |
Übersetzungsfunktion für die clientseitige runtime.js |
-n, --name <str> |
Der Name des übersetzten Templates (erfordert –client) |
-D, --no-debug |
Ohne Debugger übersetzen (kleinere Funktionen) |
-w, --watch |
Überwacht Dateien auf Änderungen und rendert neu |
-E, --extension <ext> |
Gibt die Dateierweiterung für die Ausgabe an |
--name-after-file |
Name des Templates nach dem letzten Segment des Dateipfades beim Lesen der Vorlage |
|
(erfordert –client, überschrieben durch –name) |
--doctype <str> |
Bestimmt den Doctype auf der Kommandzeile (sinnvoll, wenn das Template nichts enthält) |
Anwendungsbeispiele für die Kommandozeile
Übersetzen Sie Vorlagen lokal wie folgt:
$ pug templates
Erzeugen Sie zwei HTML-Dateien , „foo.html“ und „bar.html“:
$ pug {foo,bar}.pug
Pug-Ergebnisse können über stdio
ausgegeben werden:
$ pug <my.pug> my.html
Eine Umleitung auf Pug erfolgt durch das Pipe-Symbol:
$ echo "h1 pug!" | pug
Rendern Sie die Verzeichnisse „foo“ und „bar“ nach /tmp:
$ pug foo bar --out /tmp