Switching from Handlebars to Pug

David Dikman
Nerd For Tech
Published in
4 min readAug 14, 2022

When creating japapps.com, I wanted a minimal and easy way to generate HTML from a database of articles. I chose to start with HandlebarsJS.

This worked well until recently. I wanted to define OpenGraph data for each page to get nicer unfurls when sharing on social and to improve the page SEO.

HandlebarsJS works great for rendering a single HTML but when you want to use layouts I found the experience difficult. It is very limited and that is why I chose to switch to PugJS instead.

HandlebarsJS pages only pass content to the layout

As I added pages to the site, I also added the OpenGraph meta tags for a featured image and a title. Just good SEO housekeeping really.

But with HandlebarsJS, I had to pass this as variables to the layout to get them added to the header. To add further header content, say a script tag or a meta data for the image size, I was forced to extend the parent template further affecting all other pages or pass pure HTML from the Javascript code.

Previews from opengraph.xyz before and after editing the opengraph metadata

Most of the content on this site is rendered from data in a database. For these pages passing the data as variables works well as they already are variables.

Passing data from the page to the template to render

For any static pages I written though, having to add a controller method in javascript to serve the page only to pass an object with title and feature image to the template, is a code smell. It means splitting the content into two places and making maintenance hard.

It isn’t a big problem but it grows with every file I need to add.

All page content in one single filewith PugJS

In PugJS you can override blocks of the layout instead of passing data which makes this both optional and allows you to pass content from the child page to template, instead of having to rely on a controller method.

Even the layout can be selected inside the pug file, something I had to do in javascript for HandlebarsJS.

extends layouts/main.pug

The block override looks like below, a mention of the block in the parent template and then the same block can define content in the child file.

//- template.pug
html
head
block meta

//- page.pug
block meta
title Japapps - JWords Beta
meta(name='description' content='Sign up for the beta of our new Japanese learning app JWords. A spin off of a popular word puzzle.')
...

The PugJS blocks replace the parent layout contents by default so, in my parent layout, I can define default meta tags and only the pages that need to replace these can do so.

Comparing how to pass data to templates in HandlebarsJS versus PugJS

I am really happy with the new architecture. As a plus, after switching to PugJS and I could replace each controller for files that do not need any dynamic data with a single handler method. It simply confirms if there is a pug template existing and serves that.

It was easy to rewrite in PugJS

As HandlebarsJS is HTML with extensions it was easy to convert to PugJS using the html-to-pug.

After converting the HTML I rewrote all the references to conditionals, variable interpolation and iterators.

HandlebarsJS variable interpolation:
<p>published {{ publishedAt }} by {{ author }}</p>
PugJS variable interpolation:
p published #{publishedAt} by #{author}

HandlebarsJS vs PugJS popularity

I cannot remember the exact reason why I chose HandlebarsJS to start with but I believe it might have been because it was the most starred library I found for ExpressJS.

Data from https://stackshare.io/stackups/handlebars-vs-pug

PugJS was previously the well known library Jade, but, it got renamed due to trademark issues. I am guessing they lost some awareness points due to this.

As for when to use either framework, I think PugJS makes a perfect compliment to ExpressJS. It’s even mentioned top of the list. They also provide a guide on how to install PugJS to ExpressJS.

List of template engines supported by ExpressJS

HandlebarsJS on the other hand even states in their own documentation that it is well suited for rendering pure contents server side or in CLIs.

Interestingly, I’ve found varied support for either templating engine on other services. Codepen supports PugJS whilst carbon.now.sh only has syntax highlighting for HandlebarsJS.

PugJS worked very well for me

PugJS allowed me to use single files for rendering pages where needed or pass data when needed. The file size shrunk a lot, making it more readable without any added complexity.

As the name betrays, PugJS is for Javascript. However, there is a Jade library for Python and Haml for Ruby.

I hope this helps you deciding what is best for your project and thank you for reading!

As a final treat, here’s a cyberpunk Pug generated using Midjourney

--

--

David Dikman
Nerd For Tech

Full-stack developer and founder. Writing here and at https://greycastle.se. Currently open for contract work.