Pug (Jade): prepare HTML interfaces on Raspberry Pi with Geany

Pug is a language to simplify the writing of HTML pages (official page of the project). Web technologies are currently in fashion. Yesterday confined to the creation of websites, it is now possible to use technologies from the Web to develop projects on computer, mini-PC ARM but also for the ESP8266. Writing HTML pages is not always easy because you have to manage the tags (and respect the tree at the time of closing). It quickly becomes a real headache when you need to edit a page and even more if you have to do it after several weeks or months, especially if you are not a web professional. In this tutorial, I propose to discover (rather quickly) the language Pug. You will also find this project on the internet under the name Jade. Jade had to change his name because of a problem of rights (surprising to be able to protect the name of a stone, finally !!!). All projects requiring a Web interface offered on DIY Projects will be written using this language.

Installation of Pug on ARM (Raspberry Pi or Orange Pi)

Pug is a Nodejs plugin. It will therefore have to be installed on your machine before going further. It is therefore possible to run it on all compatible platforms. For this tutorial, I used an Orange Pi + 2e running under Armbian (Ubuntu 16.04 LTS) but it will install without difficulty on Raspbian Pixel.

To check if Node.js and npm are installed on your system, run this command in a Terminal.

pug jade html versions nodejs npm raspberry orange pi armbian

To install Node.js, you can follow this tutorial.

Warning. There is no need to uninstall Node.js if it is already present on your distribution. Other programs may no longer work.

Once Node.js and npm are installed, all you have to do is install pug and the pug-cli command-line tool that will be used to generate the HTML files. Run the following npm command:

Sudo npm install -g pug pug

Preparation of the environment

Pug therefore requires a compilation before getting the HTML file. This is the function of the pug-cli tool that converts the pug file into HTML. This can be done directly from the Terminal with the pug command. To know all the options of the command, just run pug –help .

pug liste commandes cli

To get an output HTML file, you must pass the -O option in the form of a JSON object the desired document type {“doctype”: “html”}  followed by the source file. We must respect the double quotation marks.

Rather than invoking the compile command each time, you can automate this task. It is possible to use a task manager such as Grunt or Gulp but to start or small interface projects is a bit too complicated. What I propose here is to use the construction commands of Geany presented in this article.

If you work with Sublime Text or Textmate 2, there is a plugin that allows you to do the same thing (for a next article).

Launch Geany then go to the Build menu and open Set Construction Commands. In the first field, add a command, such as a pug. In the command field type pug -O ‘{“doctype”: “html”}’ -P ‘% f’ .

geany commande construction pug vers html

Several important remarks:

The% f parameter will be replaced with the file name at the time of the command call.
It is important to put% f in quotation marks, otherwise the command will crash if the file name contains one (or some) spaces.
The file will be generated next to the source file.
You must save the file before you can run the command
The file must have the extension pug
To call the command, simply make F8 or select the shortcut created in the Build menu.

Discover the language Pug (Jade)

Pug therefore aims to simplify the writing of HTML pages, it does very well and much more. We will discover the basics of Pug in this article, if you have more specific problems, you should find everything you need on the project site.

An example to start

Here is a quick example to begin with. We create a div in which we place a title (tag h1) and just below a list (ul) composed of 2 tags (li). No more tags management

PUG (Jade) HTML Result
div
h1 Demo PUG – Jade
p Texte
ul
li Puce 1
li Puce 2
<div>
<h1>Demo PUG – Jade
<p>Texte</p>
<ul>
<li>Puce 1 </li>
<li>Puce 2</li>
</ul>
</h1>
</div>
pug html exemple

HTML tags, identifiers, classes, and attributes

All HTML tags are supported (a complete list). To add an identifier (parameter id), it is enough to make follow the tag by #idelement, for example p # p1 which will give

p#p1 <p id=”p1″>Texte</p>

To add a class (for example, a CSS style that allows you to define the color and size of a text), we will use .nameoftheclass, which will give

p#p1.oneclass <p class=”oneclass” id=”p1″>Texte</p>

We can also put all that in parentheses. If the resulting HTML file does not meet your expectations, that’s what you need to do. On the other hand, we lose some of Pug’s interest.

p(id=”p1″ class=”oneclasse”)

or

p.oneclasse(id=”p1″)

or

p#p1(class=”oneclasse”)

 <p class=”oneclasse” id=”p1″>Texte</p>

In the same way, we can stack the id and several classes

p#p1.class1.class2.class3 Texte <p class=”class1 class2 class3″ id=”p1″>Texte</p>

The principle remains the same whatever the attribute one wishes to pass.

From code (script) Javascript, jquery …

Pug also handles very well the inclusion of Javascript code (or jQuery). To do this, just add the script tag (). like this

script().
// code area
$(‘#p1’).click(function(){
console.log(“click”);
});
<script>
// code area
$(‘#p1’).click(function(){
console.log(“click”);
});
</script>

But we can also write javascript directly in the HTML.

Note. It is necessary to “paste” the sign = to the tag li to recover the value of the variable i in the label.

– var x = 5;
ul
– for (var i=1; i<=x; i++) {
li= i + “. Hello”
– }
<ul>
<li>1. Hello</li>
<li>2. Hello</li>
<li>3. Hello</li>
<li>4. Hello</li>
<li>5. Hello</li>
</ul>

Similarly, you can fill a list (or a list of choices) from the contents of a variable.

– var list_gpio = [“GPIO1”, “GPIO2”, “GPIO3”];
div
h1 GPIO List
for gpio in liste_gpio
div.card
h3= gpio
<div>
<h1>GPIO List
<div class=”card”>
<h2>GPIO1</h2>
</div>
<div class=”card”>
<h2>GPIO2</h2>
</div>
<div class=”card”>
<h2>GPIO3</h2>
</div>
</h1>
</div>

Disable code

An entire block can be commented upon. Attention Pug respects the hierarchy and will comment all the code of the lower level. As you can see, the PUG code is not converted to HTML.

//ul
li Puce 1
li Puce 2
<!–ul
li Puce 1
li Puce 2
–>

HTML Conversion to PUG or PUG to HTML Online

If you have an HTML page to resume, you can use a converter. There are several on the internet. The best known is http://html2jade.org/ works fine. One can choose the type of indentation as well as the width of it.

jade pug to html converter

Same goes the other way, Beautify Converter offers an online PUG to HTML converter. You can enter code directly or load it from a URL or file. As you can see, it’s no problem to use resources from a CDN. Here I loaded the Bootstrap framework.

jade to html converter beautify

Example on a real case

To finish this article, I propose to you to see what it gives on a concrete case. In the previous tutorial we saw how to create a web interface for our ESP8266 projects, we will use this code as the basis for building an ESP8266 project from HTML, CSS and Javascript files directly embedded in the SPIFFS memory area of the ESP8266 .

As a reminder, here is what the current interface looks like. It is entirely generated from the Arduino code in the form of a string published by the web server of the ESP8266.

demo webserver esp8266 theme bootstrapCDN superhero

Here is the equivalent Pug code

html(charset='UTF-8')
  head
    meta(http-equiv='refresh', content='60', name='viewport')
    script(src='https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js')
    script(src='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js')
    link(href='https://maxcdn.bootstrapcdn.com/bootswatch/3.3.7/superhero/bootstrap.min.css', rel='stylesheet')
    title ESP8266 Demo - www.projetsdiy.fr
  body
    .container-fluid
      .row
        .col-md-12
          h1 Demo Webserver ESP8266 + Bootstrap
          h3 Mini station météo
          ul.nav.nav-pills
            li.active
              a(href='#')
                span.badge.pull-right 24.20
                |  Température
            li
              a(href='#')
                span.badge.pull-right 38.00
                |  Humidité
            li
              a(href='#')
                span.badge.pull-right 971.68
                |  Pression atmosphérique
          table.table
            thead
              tr
                th Capteur
                th Mesure
                th Valeur
                th Valeur précédente
            tbody
              tr
                td DHT22
                td Température
                td 24.20°C
                td -
              tr.active
                td DHT22
                td Humidité
                td 38.00%
                td -
              tr
                td BMP180
                td Pression atmosphérique
                td 971.68mbar
                td -
          h3 GPIO
          .row
            .col-md-4
              h4.text-left
                | D5 
                span.badge OFF
            .col-md-4
              form(action='/', method='POST')
                button.btn.btn-success.btn-lg(type='button submit', name='D5', value='1') ON
            .col-md-4
              form(action='/', method='POST')
                button.btn.btn-danger.btn-lg(type='button submit', name='D5', value='0') OFF
            .col-md-4
              h4.text-left
                | D6 
                span.badge OFF
            .col-md-4
              form(action='/', method='POST')
                button.btn.btn-success.btn-lg(type='button submit', name='D6', value='1') ON
            .col-md-4
              form(action='/', method='POST')
                button.btn.btn-danger.btn-lg(type='button submit', name='D6', value='0') OFF
            .col-md-4
              h4.text-left
                | D7 
                span.badge OFF
            .col-md-4
              form(action='/', method='POST')
                button.btn.btn-success.btn-lg(type='button submit', name='D7', value='1') ON
            .col-md-4
              form(action='/', method='POST')
                button.btn.btn-danger.btn-lg(type='button submit', name='D7', value='0') OFF
            .col-md-4
              h4.text-left
                | D8 
                span.badge OFF
            .col-md-4
              form(action='/', method='POST')
                button.btn.btn-success.btn-lg(type='button submit', name='D8', value='1') ON
            .col-md-4
              form(action='/', method='POST')
                button.btn.btn-danger.btn-lg(type='button submit', name='D8', value='0') OFF
          .row
            .col-md-4
              form#selecttheme(method='POST', name='selecttheme')
                input#choixtheme.span(name='theme', type='hidden')
                .btn-group
                  button.btn.btn-default Theme : superhero
                  button.btn.btn-default.dropdown-toggle(data-toggle='dropdown')
                    span.caret
                  ul.dropdown-menu
                    li(onclick='$("#choixtheme").val("bootstrap"); $("#selecttheme").submit()')
                      a(href='#') Boostrap
                    li(onclick='$("#choixtheme").val("cerulean"); $("#selecttheme").submit()')
                      a(href='#') Cerulean
                    li(onclick='$("#choixtheme").val("cosmo"); $("#selecttheme").submit()')
                      a(href='#') Cosmo
                    li(onclick='$("#choixtheme").val("cyborg"); $("#selecttheme").submit()')
                      a(href='#') Cyborg
                    li(onclick='$("#choixtheme").val("darkly"); $("#selecttheme").submit()')
                      a(href='#') Darkly
                    li(onclick='$("#choixtheme").val("flatly"); $("#selecttheme").submit()')
                      a(href='#') Flatly
                    li(onclick='$("#choixtheme").val("journal"); $("#selecttheme").submit()')
                      a(href='#') Journal
                    li(onclick='$("#choixtheme").val("lumen"); $("#selecttheme").submit()')
                      a(href='#') Lumen
                    li(onclick='$("#choixtheme").val("paper"); $("#selecttheme").submit()')
                      a(href='#') Paper
                    li(onclick='$("#choixtheme").val("readable"); $("#selecttheme").submit()')
                      a(href='#') Readable
                    li(onclick='$("#choixtheme").val("sandstone"); $("#selecttheme").submit()')
                      a(href='#') Sandstone
                    li(onclick='$("#choixtheme").val("simplex"); $("#selecttheme").submit()')
                      a(href='#') Simplex
                    li(onclick='$("#choixtheme").val("slate"); $("#selecttheme").submit()')
                      a(href='#') Slate
                    li(onclick='$("#choixtheme").val("spacelab"); $("#selecttheme").submit()')
                      a(href='#') Spacelab
                    li(onclick='$("#choixtheme").val("superhero"); $("#selecttheme").submit()')
                      a(href='#') Superhero
                    li(onclick='$("#choixtheme").val("united"); $("#selecttheme").submit()')
                      a(href='#') United
                    li(onclick='$("#choixtheme").val("yeti"); $("#selecttheme").submit()')
                      a(href='#') Yeti
            .col-md-8
              p
                a(href='http://www.projetsdiy.fr') Version francaise : www.projetsdiy.fr
              p
                a(href='https://www.diyprojects.io') English version : www.diyprojects.io

Paste this code into a new document on Geany and save it. Then press F8 to generate the HTML file.

pug compilation html geany

Here is the compiled HTML code. You can open it in a browser. All the resources are recovered from the Internet, you will get the same rendering as in the image above but no interaction is still possible!

<!DOCTYPE html>
<html charset="UTF-8">
  <head>
    <meta http-equiv="refresh" content="60" name="viewport">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
    <link href="https://maxcdn.bootstrapcdn.com/bootswatch/3.3.7/superhero/bootstrap.min.css" rel="stylesheet">
    <title>ESP8266 Demo - www.projetsdiy.fr</title>
  </head>
  <body>
    <div class="container-fluid">
      <div class="row">
        <div class="col-md-12">
          <h1>Demo Webserver ESP8266 + Bootstrap</h1>
          <h3>Mini station météo</h3>
          <ul class="nav nav-pills">
            <li class="active"><a href="#"><span class="badge pull-right">24.20</span> Température</a></li>
            <li><a href="#"><span class="badge pull-right">38.00</span> Humidité</a></li>
            <li><a href="#"><span class="badge pull-right">971.68</span> Pression atmosphérique</a></li>
          </ul>
          <table class="table">
            <thead>
              <tr>
                <th>Capteur</th>
                <th>Mesure</th>
                <th>Valeur</th>
                <th>Valeur précédente</th>
              </tr>
            </thead>
            <tbody>
              <tr>
                <td>DHT22</td>
                <td>Température</td>
                <td>24.20°C</td>
                <td>-</td>
              </tr>
              <tr class="active">
                <td>DHT22</td>
                <td>Humidité</td>
                <td>38.00%</td>
                <td>-</td>
              </tr>
              <tr>
                <td>BMP180</td>
                <td>Pression atmosphérique</td>
                <td>971.68mbar</td>
                <td>-</td>
              </tr>
            </tbody>
          </table>
          <h3>GPIO</h3>
          <div class="row">
            <div class="col-md-4">
              <h4 class="text-left">D5 <span class="badge">OFF</span></h4>
            </div>
            <div class="col-md-4">
              <form action="/" method="POST">
                <button class="btn btn-success btn-lg" type="button submit" name="D5" value="1">ON</button>
              </form>
            </div>
            <div class="col-md-4">
              <form action="/" method="POST">
                <button class="btn btn-danger btn-lg" type="button submit" name="D5" value="0">OFF</button>
              </form>
            </div>
            <div class="col-md-4">
              <h4 class="text-left">D6 <span class="badge">OFF</span></h4>
            </div>
            <div class="col-md-4">
              <form action="/" method="POST">
                <button class="btn btn-success btn-lg" type="button submit" name="D6" value="1">ON</button>
              </form>
            </div>
            <div class="col-md-4">
              <form action="/" method="POST">
                <button class="btn btn-danger btn-lg" type="button submit" name="D6" value="0">OFF</button>
              </form>
            </div>
            <div class="col-md-4">
              <h4 class="text-left">D7 <span class="badge">OFF</span></h4>
            </div>
            <div class="col-md-4">
              <form action="/" method="POST">
                <button class="btn btn-success btn-lg" type="button submit" name="D7" value="1">ON</button>
              </form>
            </div>
            <div class="col-md-4">
              <form action="/" method="POST">
                <button class="btn btn-danger btn-lg" type="button submit" name="D7" value="0">OFF</button>
              </form>
            </div>
            <div class="col-md-4">
              <h4 class="text-left">D8 <span class="badge">OFF</span></h4>
            </div>
            <div class="col-md-4">
              <form action="/" method="POST">
                <button class="btn btn-success btn-lg" type="button submit" name="D8" value="1">ON</button>
              </form>
            </div>
            <div class="col-md-4">
              <form action="/" method="POST">
                <button class="btn btn-danger btn-lg" type="button submit" name="D8" value="0">OFF</button>
              </form>
            </div>
          </div>
          <div class="row">
            <div class="col-md-4">
              <form id="selecttheme" method="POST" name="selecttheme">
                <input class="span" id="choixtheme" name="theme" type="hidden">
                <div class="btn-group">
                  <button class="btn btn-default">Theme : superhero</button>
                  <button class="btn btn-default dropdown-toggle" data-toggle="dropdown"><span class="caret"></span></button>
                  <ul class="dropdown-menu">
                    <li onclick="$(&quot;#choixtheme&quot;).val(&quot;bootstrap&quot;); $(&quot;#selecttheme&quot;).submit()"><a href="#">Boostrap</a></li>
                    <li onclick="$(&quot;#choixtheme&quot;).val(&quot;cerulean&quot;); $(&quot;#selecttheme&quot;).submit()"><a href="#">Cerulean</a></li>
                    <li onclick="$(&quot;#choixtheme&quot;).val(&quot;cosmo&quot;); $(&quot;#selecttheme&quot;).submit()"><a href="#">Cosmo</a></li>
                    <li onclick="$(&quot;#choixtheme&quot;).val(&quot;cyborg&quot;); $(&quot;#selecttheme&quot;).submit()"><a href="#">Cyborg</a></li>
                    <li onclick="$(&quot;#choixtheme&quot;).val(&quot;darkly&quot;); $(&quot;#selecttheme&quot;).submit()"><a href="#">Darkly</a></li>
                    <li onclick="$(&quot;#choixtheme&quot;).val(&quot;flatly&quot;); $(&quot;#selecttheme&quot;).submit()"><a href="#">Flatly</a></li>
                    <li onclick="$(&quot;#choixtheme&quot;).val(&quot;journal&quot;); $(&quot;#selecttheme&quot;).submit()"><a href="#">Journal</a></li>
                    <li onclick="$(&quot;#choixtheme&quot;).val(&quot;lumen&quot;); $(&quot;#selecttheme&quot;).submit()"><a href="#">Lumen</a></li>
                    <li onclick="$(&quot;#choixtheme&quot;).val(&quot;paper&quot;); $(&quot;#selecttheme&quot;).submit()"><a href="#">Paper</a></li>
                    <li onclick="$(&quot;#choixtheme&quot;).val(&quot;readable&quot;); $(&quot;#selecttheme&quot;).submit()"><a href="#">Readable</a></li>
                    <li onclick="$(&quot;#choixtheme&quot;).val(&quot;sandstone&quot;); $(&quot;#selecttheme&quot;).submit()"><a href="#">Sandstone</a></li>
                    <li onclick="$(&quot;#choixtheme&quot;).val(&quot;simplex&quot;); $(&quot;#selecttheme&quot;).submit()"><a href="#">Simplex</a></li>
                    <li onclick="$(&quot;#choixtheme&quot;).val(&quot;slate&quot;); $(&quot;#selecttheme&quot;).submit()"><a href="#">Slate</a></li>
                    <li onclick="$(&quot;#choixtheme&quot;).val(&quot;spacelab&quot;); $(&quot;#selecttheme&quot;).submit()"><a href="#">Spacelab</a></li>
                    <li onclick="$(&quot;#choixtheme&quot;).val(&quot;superhero&quot;); $(&quot;#selecttheme&quot;).submit()"><a href="#">Superhero</a></li>
                    <li onclick="$(&quot;#choixtheme&quot;).val(&quot;united&quot;); $(&quot;#selecttheme&quot;).submit()"><a href="#">United</a></li>
                    <li onclick="$(&quot;#choixtheme&quot;).val(&quot;yeti&quot;); $(&quot;#selecttheme&quot;).submit()"><a href="#">Yeti</a></li>
                  </ul>
                </div>
              </form>
            </div>
            <div class="col-md-8">
              <p><a href="http://www.projetsdiy.fr">Version francaise : www.projetsdiy.fr</a></p>
              <p><a href="https://www.diyprojects.io">English version : www.diyprojects.io</a></p>
            </div>
          </div>
        </div>
      </div>
    </div>
  </body>
</html>

So, what do you prefer? In the next tutorial, we’ll see how to use this code to create a Web interface and interact with Arduino code.

Subscribe to the weekly newsletter

No spam and no other use will be made of your email. You can unsubscribe anytime.

We will be happy to hear your thoughts

Leave a Reply

DIY Projects
%d bloggers like this: