Nunjucks nennt sich selbst „Eine reichhaltige und mächtige Template-Sprache für JavaScript“, was ziemlich treffend klingt. Es ist nicht absichtlich super leichtgewichtig wie Mustache oder das etwas robustere (aber immer noch recht leichte) Handlebars. Es ist eine vollwertige Sprache, vollgepackt mit allem, was man beim Schreiben von Templates gebrauchen könnte.
Man *kann* es im Browser ausführen, aber man sollte es wahrscheinlich nicht. Dies ist dafür gedacht, in Node.js ausgeführt und zum serverseitigen Kompilieren von Templates verwendet zu werden.
Anders ausgedrückt: Es ist ein richtig schicker HTML-Präprozessor. Schauen wir uns einige Features an, die ich an Nunjucks besonders cool finde.
Ehrliche Warnung: Das ist sehr subjektiv und basiert auf nur geringer Erfahrung! Ich nutze hier nur etwa 10% dessen, wozu Nunjucks fähig ist!

Nunjucks ist ein Node-Ding, also installiert man es mit npm und arbeitet damit über die Kommandozeile, Build-Tools und diese ganze Welt.
Hier ist ein einzelner Screenshot, der zeigt, wie ich ein Node-Skript ausführe, das ein Nunjucks-Template rendert

nunjucks.render() in die Konsole ausgibt1. Es ist nur HTML
Beachten Sie, dass die Datei, die wir an nunjucks.render() übergeben haben, eigentlich nur HTML mit einer {{ handlebars }}-ähnlichen Template-Syntax war. Ich habe sie `index.njk` genannt, aber das ist nicht wirklich notwendig, ich mag es einfach, explizit bezüglich der Absicht zu sein.
Ich wette, es gibt eine gute Anzahl von Front-End-Entwicklern, die es bevorzugen, in HTML zu arbeiten, selbst wenn das HTML letztendlich verarbeitet wird. Ich mag Pug manchmal, aber es ist eine eigenständige, whitespace-abhängige Sprache. Nunjucks zu bevorzugen ist so ähnlich wie ERB gegenüber HAML zu bevorzugen.
Hier ist ein perfekt legitimes Template
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>{{ page_title }}</title>
</head>
<body>
{% for feature in features %}
<div class="module">
<h3>{{ feature.name }}</h3>
<p>{{ feature.description }}</p>
</div>
{% endfor %}
</body>
</html>
Was sind features? Daten! Man übergibt sie an die render Funktion.
nunjucks.render(
'index.njk', {
page_title: "Cool Product",
features: [
{
name: "Speed",
description: "It's fast."
},
{
name: "Reliability",
description: "You can count on it."
},
{
name: "Security",
description: "You don't have to worry about it."
}
]
}
);
Man kann sich vorstellen, dass diese Daten aus einer Datenbank oder einer API stammen, da bin ich mir sicher. Man kann Daten auch direkt in der View definieren, wenn nötig.
<div>
{% set foo = "bar" %}
{{ foo }}
</div>
2. Includes
Manchmal nutze ich eine Sprache *nur für die Includes*. Zum Beispiel hat CodeKit eine Sprache, die quasi nur für Includes da ist, weil sie wissen, wie nützlich diese sind.
So einfach sind Includes in Nunjucks
<body>
{% include "_header.njk" %}
<main>
...
</main>
{% include "_footer.njk" %}
</body>
3. Extends / Blocks
Extends heben Includes auf die nächste Stufe. Extends erlauben es Ihnen, ein Template-Dokument mit „Blocks“ darin zu definieren, die dazu dienen, Inhaltsblöcke aufzunehmen.
Hier ist ein Template mit einigen Includes, aber auch einem Block genau in der Mitte
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>{{ page_title }}</title>
</head>
<body>
{% include "parts/_header.njk" %}
{% block main %}
This is the default content
{% endblock %}
{% include "parts/_footer.njk" %}
</body>
</html>
Nun kann jede andere Datei dieses Template erweitern und muss sich nicht um den ganzen Boilerplate-HTML kümmern, der wahrscheinlich bei allen Seiten der Website dabei ist. Unser `index.njk` wird beispielsweise
{% extends "parts/_template.njk" %}
{% block main %}
{% for feature in features %}
<div class="module">
<h3>{{ feature.name }}</h3>
<p>{{ feature.description }}</p>
</div>
{% endfor %}
{% endblock %}
Ich wette, Sie können sich vorstellen, wie das Ausfüllen aussieht. Vielleicht mehrere Templates für verschiedene Arten von Seiten. Mehr Blöcke geben Ihnen die Möglichkeit, zusätzliche Stylesheets oder Skripte einzufügen. Mehr Blöcke für Bereiche der Website, wie das, was in die Seitenleiste und den Footer kommt.
4. Makros
Wo wir gerade beim Thema sind, Templates auf die nächste Stufe zu heben, Makros tun das noch einmal.
Makros sind wie **Imports mit Parametern**. Wie Funktionen! Man gibt ihnen einige Werte und sie geben einem etwas zurück.
Stellen Sie sich ein Modul vor, das drei Werte aufnimmt. Zur Veranschaulichung, sagen wir eine „Farbprobe“ (als ob wir eine Pattern-Bibliothek erstellen würden), die den Farbwert, den Namen und Notizen aufnimmt.
Wir könnten das so aufbauen
{% macro cardSwatch(colorName, colorValue, colorNotes) %}
<div class="color-swatch-tile">
<div class="color-swatch"
style="background-color: {{ colorValue }};">
</div>
<div class="color-name">
{{ colorName }}
</div>
<div class="color-notes">
{{ colorNotes }}
</div>
</div>
{% endmacro %}
Jetzt kann ich das immer wieder verwenden
{{ cardSwatch("brandColor", "#f06d06", "Our main color.") }}
{{ cardSwatch("brandHighlight", "#d0b000", "For callouts and highlights.") }}
{{ cardSwatch("grayDark", "#333333", "For things like code block backgrounds.") }}
Noch besser, ich kann die Makros in eigene Dateien verschieben und sie bei Bedarf importieren. Hier importiere ich ein macro, extend ein Template und iteriere durch colors Daten, wobei ich ein macro aufrufe
{% from "macros/swatch.njk" import swatch %}
{% extends "parts/_template.njk" %}
{% block main %}
{% for color in colors %}
{{ swatch(color.color_name, color.color_value, color.color_notes) }}
{% endfor %}
{% endblock %}
CodePen Projects unterstützt Nunjucks
Ja, in der Tat! Was schön ist, denn es erfordert keinerlei Einrichtung. (Sie kennen doch CodePen Projects, oder?) Benennen Sie einfach eine Datei mit der Endung `.njk` und CodePen weiß, dass es diese als Nunjucks verarbeiten soll.

Nunjucks mit Gulp
Wenn Sie lokal mit Nunjucks arbeiten, werden Sie fast sicher ein Build-Tool wie Gulp benötigen, um die Dateien zu verarbeiten. Glücklicherweise gibt es gulp-nunjucks, um es noch einfacher zu machen.
gulp.task('default', () =>
gulp.src('index.html')
.pipe(nunjucks.compile({
my_data: "is here"
}))
.pipe(gulp.dest('dist'))
);
Repo
Ich habe einen erstellt, während ich für die Erstellung dieses Artikels mit Nunjucks gespielt habe.
Das sieht sehr nach Twig aus. Nett!
Es gibt TwigJS: https://github.com/twigjs/twig.js :)
Das liegt daran, dass Nunjucks, Swig und Twig von Pythons Jinja inspiriert sind.
Tatsächlich versucht Nunjucks, ein ziemlich exakter Port von Jinja2 nach JavaScript zu sein. Nun, das ist etwas, das in dem Artikel erwähnt werden sollte.
Wenn Sie nach einem Front-End-JS-Template suchen, das viele ähnliche Funktionen bietet, werfen Sie einen Blick auf JSRender.
http://www.jsviews.com/#jsrplaying
Ist es nicht einfach schön, wie ähnlich clientseitige Anwendungsframeworks und serverseitige Templating-Frameworks sein können? Ich meine, schauen Sie sich nur dieses Makro-Beispiel an. Man könnte sie genauso gut Komponenten nennen, denn das sind sie! :)
(Die Schönheit schließt sich mit isomorphen Frameworks tatsächlich im Kreis. Bekommt noch jemand Gänsehaut bei dem Gedanken daran?)
Sie sind *keine* Komponenten, lassen Sie sich davon nicht täuschen. Makros sind nichts weiter als parametrisierte Strings, das ist alles. Was Sie hineinpacken, könnte sogar einfacher Text, JSON, Python-Code oder was auch immer Sie wollen sein. (Obwohl Nunjucks so konzipiert ist, dass interpolierte Werte für HTML maskiert werden.)
Was schlimmer ist, ist, dass man Komponenten leicht testen kann, während das Testen von Makros ein ganz anderes Paar Schuhe ist.
Nur weil es ein parametrisierter String ist, heißt das nicht, dass wir ihn nicht als Komponente betrachten können.
const Addition = (a, b) => `${a} + ${b} = ${a + b}`
Hier ist ein weiterer parametrisierter String. Man könnte argumentieren, dass es nur eine Funktion ist, die einen String zurückgibt (genau wie Nunjucks Makros!), aber wissen Sie, was ich sehe? Eine Komponente! :)
Diese Parallelen zu ziehen, macht die Webentwicklung so schön.
Nun, genauer gesagt sind Makros einfach Funktionen, die beim Rendern immer ausgeben. Das ist alles. Sie können damit machen, was Sie wollen. Sogar CSS schreiben.
Nunjucks Makros als Komponenten sind noch einfacher zu testen, weil sie meist statisch sind (mit wenigen Ausnahmen, wenn man auf der Client-Seite etwas asynchrones tut oder Nebeneffekte mit Makros auslöst).
Deshalb ist das Testen sehr trivial.
Wenn sich jemand fragt, wie das geht, hier ist ein Beispiel.
Hier teste ich tatsächlich benutzerdefinierte globale Funktionen von Nunjucks, aber man kann sich vorstellen, dass es für Makros genauso funktionieren wird.
Wenn wir zum Beispiel eine „Komponente“
blogPostPreviewhabenVielleicht gefällt Ihnen der Ansatz von https://atmin.github.io/funponent
Snapshot-Tests sind eine sehr einfache Art von Tests, die nicht immer das sind, was man will. Tatsächlich würde ich sagen, dass sie *selten* das sind, was man will, denn da Makros „statisch“ sind, bringen diese Art von Tests wenig bis keinen Mehrwert. Es ist, als hätte man einen Test wie
it('sollte einfach funktionieren', ...).Aber es gibt mehr als das. Wie erreicht man die Code-Abdeckung bei Ihren Makro-Tests? Wie wendet man Linting oder andere Methoden zur Qualitätsprüfung an?
Snapshot-Tests sind eine sehr effiziente Methode für Regressionstests.
Wenn Ihre Komponenten reine Funktionen sind, was mit Redux (nicht unbedingt mit React) oder Ähnlichem erreichbar ist, um den Zustand zu entkoppeln, dann sammeln Sie bei der Weiterentwicklung Ihrer Komponente neue Eingaben und resultierende Snapshots und refaktorieren Sie mit der Gewissheit, nichts kaputt gemacht zu haben.
Sie können auch Ihre Reducer mit Snapshots testen (sie sind reine Funktionen).
Makros können voll funktionsfähige Komponenten sein. Werfen Sie einfach etwas wie Pjax hinein und lassen Sie den Server den Client-Zustand vollständig verwalten. Das funktioniert für stark dynamische Interaktionen nicht effizient, aber eine riesige Anzahl von Apps kann diesen Ansatz nutzen und viel Implementierungskomplexität vermeiden.
Das kann nützlich sein, wenn ein Makro komplexe Logik und mehrere Zustände hat. Was sonst würde man in einem Tool testen wollen, das nur gerendertes HTML ausgibt?
Das ist eher eine Frage der Werkzeuge. Soweit ich weiß, gibt es derzeit keine Abdeckungswerkzeuge für Nunjucks (obwohl es möglich ist, eines zu schreiben) und keine Linting-Werkzeuge. Das stimmt.
Ich glaube nicht, dass ein Abdeckungswerkzeug für eine Template-Sprache wirklich nötig ist, es sei denn, man ist verrückt und steckt zu viel Logik in Templates.
Aber ja, ich würde gerne ein Linting-Tool sehen, definitiv.
Wir haben tatsächlich eine Version davon für unsere Sportpreis-Website verwendet. Super einfach für das Frontend zu bedienen.
Ich empfehle die Verwendung fortgeschrittener Template-Sprachen wie Nunjucks (oder Twig, Swig oder Jinja2, die im Grunde alle dasselbe sind) eigentlich nicht, weil sie einfach *zu* mächtig sind.
Man könnte beobachten, dass es so etwas wie „zu mächtig“ nicht gibt, da man bestimmte Funktionen einfach nicht verwenden kann, aber die einfache Tatsache, dass man diese Dinge tun *kann*, wird Sie wahrscheinlich dazu bringen, diese Dinge tatsächlich *zu tun*.
Nun, was ist falsch an Nunjucks? Es erlaubt Ihnen, *Logik* in Ihren Templates zu schreiben. Denken Sie darüber nach: Anstatt das Template mit allen benötigten Werten zu füllen, erlaubt Nunjucks Ihnen, Rohdaten zu manipulieren und diese Werte zu extrahieren. Das Problem hierbei ist, dass es viel schwieriger zu debuggen und zu testen ist.
Makros sind definitiv ein No-Go für mich. Aber auch sein kompliziertes System von Blöcken, Erweiterungen, Einbettungen und Imports ist einfach zu viel. Ganz zu schweigen davon, all dies mit benutzerdefinierten Filtern, Funktionen und Prüfungen zu erweitern.
Das wurde mir bei der Arbeit mit Symfony bewusst, das standardmäßig Twig verwendet. Himmel, an diesem Punkt kann man direkt PHP verwenden, das tatsächlich als Templating-Engine geboren wurde!
Als ich zu Handlebars wechselte, nachdem ich mich daran gewöhnt hatte, wurde alles einfacher (und ich kann die Sprache immer noch erweitern, obwohl ich das nur in sehr wenigen Fällen tue).
Von der GitHub-Seite
Ich gehe zu pugjs
Cool! Ich kann es kaum erwarten, wenn wir anfangen, unsere JS-Konfigurationen über Kommentar-Annotationen wie Symfony zu machen :)
Das ist erstaunlich! Ich warte schon viele Jahre darauf! Danke, Chris!
Danke dafür, ich wollte mit Nunjucks anfangen, fand aber die Dokumentation etwas viel. Ihr Leitfaden ist großartig!
Ich hatte Nunjucks gefunden, als ich nach einer Template-Sprache für meinen Gulp E-Mail-Templating-Workflow suchte, und mir war nicht bewusst, wie leistungsfähig es ist, bis ich anfing, mit Makros zu experimentieren. So nützlich!
Ich bin froh, dass es endlich auf CSS-Tricks vorgestellt wurde.
Nunjucks ist ein extrem leistungsfähiges Templating, das auf soliden und kampferprobten Ideen von Jinja2 basiert.
Tatsächlich wurde es unter der Leitung von Carl Meyer irgendwann zu einem sehr exakten Port von Jinja2, bis hin zu dem Punkt, dass dieselben Templates sowohl in JS- als auch in Python-Umgebungen verwendet werden konnten.
Selbst wenn es aktive Betreuer fehlen, können wir immer noch keine bessere Alternative finden.
Nunjucks mag auf den ersten Blick im Vergleich zu anderen bekannten Template-Sprachen unscheinbar wirken (abgesehen von der recht eleganten Syntax und einigen netten Features wie dem Entpacken bei Schleifen), aber je tiefer Sie eintauchen, desto schwieriger wird es, zu anderen Template-Sprachen zurückzukehren.
Und es ist eine der wenigen *asynchronen* Template-Sprachen. Das kann manchmal ein Deal-Breaker sein, besonders wenn das Templating auf der Client-Seite verwendet wird und man mit vielen asynchronen Aufgaben umgehen muss.
Nunjucks ist ziemlich gut an die Arbeit im Browser angepasst und wurde ursprünglich als Client-Side-Templating-Sprache entwickelt.
Nunjucks kann vorkompiliert werden, sodass Sie den Compiler in der Produktion weglassen und fast reines JavaScript als Ihre Templates mit einem ziemlich kleinen Fußabdruck ausführen können.
Aber natürlich würden React oder VueJS für einige komplexe Aufgaben im modernen Zeitalter viel mehr Vorteile und weniger Kopfschmerzen bieten.
Nun, tatsächlich sind sie Funktionen, die einfach immer ausgeben (wenn etwas auszugeben ist).
Das bedeutet, dass sie nicht nur zur Ausgabe von HTML verwendet werden können, sondern auch, um Nebeneffekte aufzurufen oder Daten zu ändern (wenn man verrückt genug ist). Lohnt es sich, das zu tun? Das ist eine ganz andere Geschichte.
Aber offensichtlich ist der direkteste Weg, sie zu nutzen, sie als Inkarnation einer Komponente zu betrachten. Wir nutzen diesen Ansatz aktiv in Kotsu, wie in den eingebauten Kotsu-Komponenten zu sehen ist.
Tatsächlich ermutige ich dazu, die Kotsu-Templates zu erkunden, denn im Laufe der Zeit haben sie viel Erfahrung bei der Entwicklung auf Basis von Nunjucks gesammelt. Zum Beispiel können Sie Gettext-basiertes l10n sehen, das auf Nunjucks Globals basiert, oder nahtlos integriertes Markdown.
Zur Inspiration lohnt sich auch ein Blick auf die Nunjucks-Erweiterungen, die wir in Kotsu verwenden. In komplexen Projekten sind einige davon von unschätzbarem Wert.
Ich wünschte, ich könnte unsere kommerziellen Projekte auf Basis von Nunjucks zeigen, aber leider kann ich nur andeuten, wie es auf einer statisch generierten Website mit einem großen Katalog von Produkten aussehen könnte.
Unsere Liste von Komponenten
Und hier ist, wie sauber das Layout einer Kategorieseite aussieht, die eine sehr komplexe Tabelle mit Produkten generiert, die viele datengesteuerte Informationen enthält.
Alle Kategorieseiten erweitern diese einfach und stellen zusätzliche Informationen zum Kontext bereit, um die Seite mit den gewünschten Daten zu rendern (wir verwenden dafür Front Matter, aber es kann auch ohne gemacht werden).
Oben sind Nunjucks globale Funktionen in Form von Selektoren zu sehen, die Daten und komplexe Berechnungen (die aus der Template-Engine herausgehalten werden sollten) von der Node-App in Nunjucks übergeben.
Und so sehen die Selektoren aus, die einfach nur reines JavaScript (CoffeeScript) sind.
Ich hoffe, das gibt einigen Leuten Inspiration, die sich fragen, was genau mit Nunjucks gemacht werden kann und wie es in einem echten Projekt aussieht :)
Ups, das Posting-Formular hat alle Bilder mit Markdown
![]()gestrippt.Ich poste noch einmal, mit einfachen URLs zu den Screenshots.
Unsere Liste von Komponenten: https://vgy.me/eZXlWq.png
Und hier ist, wie sauber das Layout einer Kategorieseite aussieht, die eine sehr komplexe Tabelle mit Produkten generiert, die viele datengesteuerte Informationen enthält: https://vgy.me/bh6N5r.png
Alle Kategorieseiten erweitern diese einfach und stellen zusätzliche Informationen zum Kontext bereit, um die Seite mit den gewünschten Daten zu rendern (wir verwenden dafür Front Matter, aber es kann auch ohne gemacht werden): https://vgy.me/tIBxQZ.png
Oben sind Nunjucks globale Funktionen in Form von Selektoren zu sehen, die Daten und komplexe Berechnungen (die aus der Template-Engine herausgehalten werden sollten) von der Node-App in Nunjucks übergeben: https://vgy.me/GKf05L.png
Und so sehen die Selektoren aus, die einfach nur reines JavaScript (CoffeeScript) sind: https://vgy.me/uO8i5Z.png
Ich hoffe, das gibt einigen Leuten Inspiration, die sich fragen, was genau mit Nunjucks gemacht werden kann und wie es in einem echten Projekt aussieht :)