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:
gulp-pug
- compiles Pug files to HTMLgulp-html-beautify
- to format the generated HTML files
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;
};
};