Writing Perch Templates in Pug

I was using a HTML preprocessor on a non-Perch project and I started wondering whether using one to write Perch templates would be a worthy addition to my Perch workflow. So I decided to try using Pug (previously known as Jade), because why not?!

Here’s how you’d write a simple perch:content tag with Pug:

perch:content(id="title" type="text" label="Title")/

This compiles to:

<perch:content id="title" type="text" label="Title" />

Notes:

1- Manually outputting opening and closing tags:

perch:before
    ul

Compiles to:

<perch:before><ul></ul></perch:before>

Which is not what we usually want. It’s common to have an opening tag inside <perch:before> and the closing tag inside <perch:after>. In this case, we have to manually write the opening and closing tags. In Pug you can output plain text (including raw HTML) like so:

perch:before
    | <ul>

perch:after
    | </ul>

or:

perch:before
    != "<ul>"

perch:after
    != "</ul>"

Both compiles to:

<perch:before><ul></perch:before>
<perch:after></ul></perch:after>

2- Self-closing tags:

While Pug automatically self-close HTML tags such as img and meta, you need to explicitly self-close your Perch tags when needed:

// not self-closing
perch:content(id="title" type="text" label="Title")

// self-closing
perch:content(id="title" type="text" label="Title")/

Compiles to:

<!-- not self-closing -->
<perch:content id="title" type="text" label="Title"></perch:content>

<!-- self-closing -->
<perch:content id="title" type="text" label="Title"/>

3- Tags inside another tag’s attributes:

In Perch templates we often have Perch tags inside HTML tags. For example:

<a href='<perch:content id="url" type="text"/>'>Link</a>

You cannot do the following as Pug won’t compile the perch:content here:

// doesn't work
a(href='perch:content(id="url" type="text")/') Link

What you can do instead is writing the tag yourself:

a(href!='<perch:content id="url" type="text"/>') Link

Note that Pug by default escapes special characters in attributes. Since we need the special characters we need to use != instead of =.

Alternatively, you can use variables for this:

- var url = '<perch:content id="url" type="text"/>'

a(href!=url) Link

// this also work:
a(href!='/' + url) Link

4- Comments:

In Perch templates:

<!-- This comment gets output to the browser -->

<!--* This comment gets stripped from the template before being output to the browser *-->

The above works fine in Pug, but perhaps you want to keep comments in your .pug files and not have them in your perch_template.html at all:

<!-- This comment will be in your perch_template.html and get output to the browser -->
// This comment will also be in your perch_template.html and get output to the browser

<!--* This comment will be in your perch_template.html, but won't get output to the browser *-->

//- This comment won't be in your perch_template.html so won't get output to the browser

It’s up to you where to keep your comments. For example, if your development team mainly look at your .pug files, you might want to use //- when adding development notes that don’t need to be output to the browser.

Putting it to the test:

So let’s re-write a few Perch templates.

Example #1

This is perch/templates/categories/category.html:

<perch:before><ul></perch:before>
<li style="margin-left: <perch:category id="catDepth" type="hidden" />0px;">
    <h4><perch:category id="catTitle" type="smarttext" label="Title" required="true" /></h4>
    <perch:category id="catSlug" type="slug" for="catTitle" suppress="true" />
    <perch:category id="desc" type="textarea" label="Description" editor="markitup" markdown="true" size="s" />
</li>
<perch:after></ul></perch:after>

This can be written like this in Pug:

perch:before
    | <ul>

li(style!='margin-left: <perch:category id="catDepth" type="hidden"/>0px;')
    h4
        perch:category(id="catTitle" type="smarttext" label="Title" required="true")/
    perch:category(id="catSlug" type="slug" for="catTitle" suppress="true")/
    perch:category(id="desc" type="textarea" label="Description" editor="markitup" markdown="true" size="s")/

perch:after
    | </ul>

Or if you prefer variables:

- var catDepth = '<perch:category id="catDepth" type="hidden"/>'

perch:before
    | <ul>

li(style!='margin-left:'+catDepth+'0px;')
    h4
        perch:category(id="catTitle" type="smarttext" label="Title" required="true")/
    perch:category(id="catSlug" type="slug" for="catTitle" suppress="true")/
    perch:category(id="desc" type="textarea" label="Description" editor="markitup" markdown="true" size="s")/

perch:after
    | </ul>

Example #2

Using perch:if and perch:else tags. This example is from the documentation:

<perch:if exists="name">
     <h2><perch:content id="name" type="text" label="Name" /></h2>
 <perch:else />
     Author unknown
</perch:if>
perch:if(exists="name")
    h2
        perch:content(id="name" type="text" label="Name")/
    perch:else/
    | Author unkown

Example #3

Let’s re-write another example from the documentation:

<perch:after>
  <perch:if exists="paging">
    <div class="paging">
      Page <perch:content id="current_page" type="hidden" /> 
        of <perch:content id="number_of_pages" type="hidden" />
      <perch:if exists="not_first_page">
        <a href="<perch:content id="prev_url" type="hidden" encode="false" />">Previous</a>
      </perch:if>
      <perch:content id="page_links" encode="false" />
      <perch:if exists="not_last_page">
        <a href="<perch:content id="next_url" type="hidden" encode="false" />">Next</a>
      </perch:if>
    </div>
  </perch:if>
</perch:after>
perch:after
    perch:if(exists="paging")
        .paging
            | Page
            perch:content(id="current_page" type="hidden")/
            |  of
            perch:content(id="number_of_pages" type="hidden" )/

            perch:if(exists="not_first_page")
                a(href!=prevURL) Previous

            perch:content(id="page_links" encode="false")/

            perch:if(exists="not_last_page")
                a(href!=nextURL) Next

Should you use Pug in your Perch workflow?

It’s up to you to evaluate whether it’s going to benefit you. Pug files need to be compiled so your adding an extra step here, but you may find Pug files faster to write and/or easier to read.

To get you started, you can find some of Perch default templates written in Pug on GitHub.

If you’re following Gulp workflow for Perch and considering to introduce Pug to your workflow, you can use the following and edit your gulpfile.js to include it. Required installs:

module.exports = function (gulp, plugins, config) {
    return function () {
        var destination = 'perch/templates';

        var stream = gulp.src('src/templates/**/*.pug')
            .pipe(plugins.pug())
            .pipe(plugins.htmlBeautify({indentSize: 2}))
            .pipe(gulp.dest(destination));

        return stream;
    };
};
link

Related articles