Apprendre Express.js : Moteur de Template Pug
Composant essentiel de tout framework web, le moteur de template permet d'isoler proprement la partie interface de votre application. Zoom sur Pug.
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 !' })
});