Formation Express JS | Intégrer le Moteur de Template Pug avec Express JS
Explorez Pug, un moteur de template puissant pour créer des interfaces web claires et structurées au sein de vos applications Node/Express.
Qu’est-ce qu’un moteur de templates ?
Définition
Les moteurs de templates, ou “moteurs de modèles” sont des langages qui permettent de générer dynamiquement du HTML.
Vous pouvez ainsi définir des templates pour votre application, qui peuvent ensuite être remplis dynamiquement avec des données provenant de votre base de données ou d’autres sources de données.
Ce dynamisme est rendu possible via de nombreuses fonctionnalités, notamment algorithmiques :
- Variables ;
- Structures conditionnelles (
if
,else if
,else
,switch
) ; - Structures itératives (
each
,for
,while
…) ; - Inclusions ;
- Héritage de template ;
- Etc.
L’utilisation d’un moteur de template est généralement considérée comme essentielle dans un framework web, car elle permet de séparer clairement le code logique de l’application de la présentation visuelle de l’interface.
Principaux moteurs de templates
Du côté de Node.js et d’Express, on fait souvent référence à :
- Pug ;
- Ejs ;
- Handlebars ;
- Hogan ;
- Twig (implémentation JavaScript du célèbre moteur de template PHP #symfony) ;
- Etc.
Intéressons-nous de plus près au plus célèbre d’entre eux, j’ai nommé Pug !
Pug : la référence Node.js
Anciennement connu sous le nom de « Jade », ce moteur de template a été renommé « Pug » suite à des problèmes juridiques.
Pug est un moteur de templates implémenté en JavaScript dont la syntaxe minimaliste est inspirée de Haml.
Un template Pug est un fichier portant l’extension .pug
, basée sur une syntaxe proche des sélecteurs CSS (et par extension des raccourcis Emmet).
section#about
h2 About me
.grid
.col-4
img(src='https://picsum.photos/500', alt='Image de démonstration')
.col-8
p Paragraphe 1
p Paragraphe 2
Cet extrait Pug correspond au HTML suivant :
<section id="about">
<h2>About me</h2>
<div class="grid">
<div class="col-4">
<img src="https://picsum.photos/500" alt="Image de démonstration">
</div>
<div class="col-8">
<p>Paragraphe 1</p>
<p>Paragraphe 2</p>
</div>
</div>
</section>
Voici les grands points à retenir :
Indentation | L’indentation indique l’imbrication / la hiérarchie entre les éléments. Il est important de ne pas mélanger espaces et tabulations. |
---|---|
Raccourcis (sélecteurs CSS) | On crée des éléments à la manière des sélections CSS : p pour <p></p> , #about pour id="about" , .grid pour class="grid" , img(src='https://monsite.com/img/demo.png', alt='Image de démonstration') pour <img src="https://monsite.com/img/demo.png" alt="Image de démonstration"> |
Écrire du texte | Le premier espace noté derrière une balise HTML indique que le contenu qui suit est du texte. p Paragraphe 1 pour <p>Paragraphe 1</p> |
Installation de Pug
Comme tout paquet, pug
est téléchargeable via votre gestionnaire de paquet favori. Voici la commande npm
:
npm install pug
Initialisation de Pug
Une fois installé, il est important d’initialiser Pug dans votre application Express, sans quoi il ne serait pas exploitable.
Utiliser la méthode app.set()
afin de définir le moteur de template à utiliser :
app.set('view engine', 'pug');
Par défaut, les templates Pug seront à placer dans le dossier 📁 views
, situé à la racine du projet. Si vous souhaitez travailler avec un autre répertoire de vues, vous avez la possibilité de définir ce dernier en utilisant une nouvelle fois la méthode app.set()
.
app.set('views', './templates');
On définit ici le dossier 📁 templates
comme étant celui qui contiendra nos templates Pug.
Avec le module path
Il n’est pas rare de voir des extraits de projet Node / Express exploitant le module path
. Ce module propose tout un tas de méthodes utiles pour travailler avec des chemins.
const path = require('path');
app.set('views', path.join(__dirname, 'templates'));
Dynamiser ses templates
Comme tout moteur de template digne de ce nom, Pug implémente des structures dynamiques telles que les variables, la notion d’héritage et d’inclusion, des boucles et des conditions.
Variables
La plupart du temps, on utilise dans les templates des variables transmises par l’application (récupération d’éléments en base de données), mais nous avons parfois besoin, dans un souci algorithmique, d’en déclarer directement dans nos templates.
Déclaration
La déclaration d’une variable se fait avec le mot clé var
:
- var msg = "Hello world!";
- var tva = 0.2;
- var fruits = ["Pomme", "Poire", "Banane"];
Affichage
Il est aisé d’afficher des variables transmises par l’application (au niveau des routes) ou déclaré directement dans nos templates.
Affichage du contenu de la variable uniquement avec =
h1= title
p= message
Affichage interpolé (concaténé) avec #{}
p Publié par #{author}
Ecriture dans un attribut HTML (sans les guillemets ""
)
img(src=article.image, alt="Blablabla...")
Héritage
Pug prend en charge l’héritage de templates.
Cela signifie qu’au sein d’un template, il est possible de spécifier des zones, appelées blocs, dans lesquelles un template enfant va pouvoir injecter du contenu.
- Ces zones de contenu dynamiques se déclarent avec le mot-clé
block
. - Pour spécifier qu’un template hérite d’un autre, on utilise le mot-clé
extends
.
Parent
doctype html
html
head
title #{title} - Nom du site
meta(charset='UTF-8')
body
include includes/_header.pug
block content
include includes/_footer.pug
Enfant
extends layout.pug
block content
section.section.is-dark
h1= title
p Lorem ipsum dolor sit amet...
Il est également possible de définir un contenu par défaut dans un bloc parent. Ce contenu s’affichera si le template enfant ne vient pas insérer du contenu au sein du bloc en question.
block content
p Paragraphe par défaut
Inclusions
Les inclusions permettent d’intégrer des templates dans d’autres templates.
Ceci est très utile pour intégrer des composants communs (= partials) appelés plusieurs fois comme des headers, footers, sidebars, etc., ou encore pour les isoler. Cela permet entre autres de respecter le principe du DRY (Dont Repeat Yourself).
Une inclusion s’effectue avec le mot-clé include
en spécifiant en suivant le chemin vers le fichier.
html
head
body
include includes/_header.pug
main
include includes/_footer.pug
Ici on va chercher les fichiers 📄 views/includes/_header.pug
et 📄 views/includes/_footer.pug
.
Boucles
Pug propose deux types de boucles : each
et while
.
Each
La boucle each
est très utile pour boucler sur des objets (provenant généralement de l’application) afin d’en afficher les caractéristiques.
section.products
h1 Produits
each product in products
article.product
img(src=product.image, alt=product.alt)
h2= product.title
p= product.description
else
p Aucun produits...
Voici le HTML généré :
<section class="products">
<h1>Produits</h1>
<article class="product">
<img src="/img/produit1.png" alt="Produit 1">
<h2>Produit 1</h2>
<p>Description du produit...</p>
</article>
<article class="product">
<img src="/img/produit2.png" alt="Produit 2">
<h2>Produit 2</h2>
<p>Description du produit...</p>
</article>
...
</div>
While
La boucle while
est quant à elle très utile dans des problématiques plus algorithmiques (calculs, etc), ou du moins pour des boucles pour lesquelles on ne connaît pas à l’avance le nombre d’itérations à effectuer.
- var n = 0;
ul
while n < 3
li= n++
Voici le HTML généré :
<ul>
<li>0</li>
<li>1</li>
<li>2</li>
</ul>
Conditions (if
, else if
et else
)
Comme tout moteur de template digne de ce nom, Pug dispose d’un système de conditions si - sinon si - sinon. En voici quelques exemples :
if user.authenticated
a(href='https://monsite.com/logout') logout
else
a(href='https://monsite.com/login') login
if student.note < 8
p Refusé.
else if student.note >= 8 && student.note <MdxCode 10
p Rattrapage.
else
p Admis.
Vous pourrez également retrouver l’équivalent switch sur la documentation officielle.
Retourner un template Pug
Pour retourner un template, il faut se placer dans une route de l’application et retourner avec la méthode res.render()
le template Pug en question.
app.get('/contact', function (req, res) {
res.render('contact', { title: 'Contact', message: 'Une question ? Contactez-moi via ce formulaire !' })
});