Introduction à Pug

Pug est un moteur de templates implémenté en JavaScript qui permet de générer dynamiquement du HTML, à l'instar de Thymeleaf en Java et Twig en PHP. Sa syntaxe est inspirée de Haml. Elle est donc minimaliste et basée sur les indentations.

Depuis plusieurs années, j'utilise Pug pour structurer mes composants front. La syntaxe très proche des sélecteurs CSS et la légèreté syntaxique me plaisent beaucoup. C'est pourquoi je vous propose de découvrir quelques fonctionnalités de ce moteur de templates.

Cet article n'a pas pour but d'être exhaustif. Vous pouvez consulter site officiel, si vous souhaitez en apprendre plus sur le langage.

Anciennement "Jade"

Avant, Pug s'appelait Jade. Seulement Jade est devenu une marque déposée et comme le domaine de la marque est très proche (les deux réfèrent au monde logiciel), les responsables du dépôt sur Github ont choisi de le renommer.

Si vous utilisiez Jade et que vous souhaitez migrer vers Pug, voici la liste des changements : https://github.com/pugjs/pug/issues/2305

Tester les exemples

Pour tester chez vous les exemples de cet article, vous pouvez le faire en ligne avec des outils comme Codepen ou encore installer directement Pug sur votre environnement.

Installer la commande pug

npm install pug-cli -g

ou

yarn global add pug-cli

Pour compiler un fichier (exemple : example.pug en example.html), on utilise :

pug -P example.pug

Ici, on utilise le mode pretty avec la l'option -P, afin de rendre le résultat plus lisible. Pour connaître les différentes options de la commande, il suffit de lancer pug --help

Un moteur de templates complet

Comme de nombreux langages, il propose des structures de contrôle (if, unless, each, case…), de l'inclusion, un système de layouts par héritage de template.

La syntaxe

Le nom des balises dans Pug est représenté par des sélecteurs inspirés de la syntaxe du CSS. De plus, sa syntaxe dépendante des indentations la rend plus condensée, plus lisible et moins sujette à des problématiques d'absence de balise fermante.

En voici un exemple :

article#article-1
  h2 Class and id
  .class Class
  #id Id

on obtient le HTML suivant :

<article id="article-1">
    <h2>Class and id</h2>
    <div class="class">Class</div>
    <div id="id">Id</div>
</article>

Une balise div est implicitement ajoutée lorsqu'elle n'est pas associée au sélecteur css.

Les mixins

Pour réutiliser des portions de templates à plusieurs endroits sans réécrire la structure ni les paramètres, il existe les mixins.

Exemple de mixin représentant une icône avec un texte, une image un lien :

mixin textIcon(text, image, url)
  a(href=url).text-icon
    figure
      img(src=image, alt=text + ' icon').icon
      figcaption.text=text

L'utilisation d'un mixin se fait en préfixant son nom par un +. Dans notre cas, c'est +textIcon :

.icon-list
  +textIcon('Chrome', '/images/chrome-logo.png', 'https://www.google.fr/chrome/index.html')
  +textIcon('Firefox', '/images/firefox-logo.png', 'https://www.mozilla.org/fr/firefox')
  +textIcon('Edge', '/images/edge-logo.png', 'https://www.microsoft.com/fr-fr/windows/microsoft-edge')
  +textIcon('Safari', '/images/safari-logo.png', 'https://www.apple.com/fr/safari')

Ce qui donne en HTML :

<div class="icon-list">
    <a class="text-icon" href="https://www.google.fr/chrome/index.html">
        <figure>
            <img class="icon" src="/images/chrome-logo.png" alt="Chrome icon" />
            <figcaption class="text">Chrome</figcaption>
        </figure>
    </a>
    <a class="text-icon" href="https://www.mozilla.org/fr/firefox">
        <figure>
            <img class="icon" src="/images/firefox-logo.png" alt="Firefox icon" />
            <figcaption class="text">Firefox</figcaption>
        </figure>
    </a>
    <a class="text-icon" href="https://www.microsoft.com/fr-fr/windows/microsoft-edge">
        <figure>
            <img class="icon" src="/images/edge-logo.png" alt="Edge icon" />
            <figcaption class="text">Edge</figcaption>
        </figure>
    </a>
    <a class="text-icon" href="https://www.apple.com/fr/safari">
        <figure>
            <img class="icon" src="/images/safari-logo.png" alt="Safari icon" />
            <figcaption class="text">Safari</figcaption>
        </figure>
    </a>
</div>

La classe mixin de notre exemple prenait des arguments. Il est possible de n'en mettre aucun ou de définir une zone (un block) pouvant contenir d'autres éléments :

Prenons l'exemple d'une modal :

mixin modal(title)
  .modal
      h2.title=title
      .content
        block

Et une utilisation avec un paragraphe et une liste :

.modal-list
  +modal('A paragraph')
    p A paragraph
  +modal('A list')
    ul
      li First element
      li Second element

Donne le HTML suivant :

<div class="modal-list">
    <div class="modal">
        <h2 class="title">A paragraph</h2>
        <div class="content">
            <p>A paragraph</p>
        </div>
    </div>
    <div class="modal">
        <h2 class="title">A list</h2>
        <div class="content">
            <ul>
                <li>First element</li>
                <li>Second element</li>
            </ul>
        </div>
    </div>
</div>

On peut voir que la structure du contenu est libre. Ce qui est pratique pour une modal ou tout autre conteneur générique.

Vue.js avec Pug

Le framework Vue.js permet d'utiliser les templates de Pug via les modules pug-plain-loader et pug (npm install -D pug-plain-loader pug). Voici un exemple simple :

<template lang="pug">
    .custom-component
        h2 {{title}}
        other-component(:value="value")
</template>
<script lang="ts" src="./custom-component.ts"></script> 

Le même code avec le langage de template HTML donne :

<template>
    <div class="custom-component">
        <h2>{{title}}</h2>
        <other-component :value="value"></other-component>
    </div>
</template>
<script lang="ts" src="./custom-component.ts"></script> 

On remarque que la présence de l'attribut du template lang="pug" suffit pour définir la syntaxe.

Diverses utilisations de Pug

Pour ma part, j'utilise Pug pour implémenter des composants graphiques. Je profite ainsi de la syntaxe proche du CSS et j'évite les oublis de balises fermantes.

Les mixins sont une excellente réponse à des méthodologies comme Atomic Design, puisqu'ils permettent de réutiliser les atomes, molécules et organismes.

Enfin, le framework JavaScript Vue.js permet l'utilisation du langage.

Je vous encourage à votre tour d'essayer Pug et peut-être même de l'adopter pour vos vues.

Pug se prête bien à la création de composants en Atomic Design dans la pratique. Je vous invite à lire l'article du lien précédant sur le sujet.