stephen fulljames

Minimum Viable Portfolio

All articles

Converting to Docpad

10 Jun 2013

As part of the day job last week I spent some time evaluating Docpad as a potential tool for upcoming changes to our website. I guess its best described as semi-static site generator, in that it renders templated pages to a static output directory as HTML but also runs as a Node.js process so some dynamism is available if you want it. Anyway, as we currently have a hybrid of Wordpress content management with a Node front end, the latter using Wordpress as an API, it sounded like an interesting way to bring our less frequently updated content out of Wordpress and leave that simply for blogging.

To get a feel for what Docpad could do I thought a good way to try it would be to rebuild my personal website, which is where you are now. The previous version was a slightly weird hand-cranked flat file mishmash, with JSON objects defining article lists and the articles themselves being Markdown wrapped in a Jade template. Ugly and illogical but it worked, or at least gave the appearance of working. When I put it together in 2012 I had thought of using a static site generator such as Jekyll, but I also wanted to use it as a learning experience for Node so this is the way it was. Trying out Docpad seemed like a way to make all these parts fit together properly.

This isn't going to be a comprehensive guide on how to get up and running with Docpad - their own tutorial is very good and got me to the point where I was confident to build my own thing. Its also not going to cover skeletons, the pre-configured sample sites offered as a base to work from, as I already had a site with styling that I wanted to convert. But they do look interesting as a template for the kind of rapid-start projects we often engage in and I'll revisit them another time.

Although, before we start - make sure your NPM version is at least 1.2 or Docpad won't install correctly.


Use of plugins is essential to add functionality to the core of Docpad. Mostly I've been working with rendering add-ons so far, and this site makes use of the Jade, Markdown and LESS renderers to compile my templates. Jade is used for the layouts, and the articles themselves are now written in pure Markdown - the first, and most significant, improvement from the old site.

I've also added the cleanurls plugin, as the default behaviour is to build navigation lists with .html file extensions - not a massive problem in itself but I wanted to preserve the existing url structure. This worked without a hitch.

Working with other data

One of the foibles of the old site is that all the article and project listings you see on the homepage were generated from JSON objects of metadata and required careful setting of URLs in that data to make everything connect together. One of the key parts of Docpad's design is that each document contains metadata at the top which takes that problem away - each article is now self-contained and Docpad's ability to generate collections of documents based on their metadata is used to build the articles, projects and tools listings.

However there were still some links - the social media contacts and external blog posts - which didn't really belong to documents so they're still defined by lumps of JSON.

To achieve this, the data files are required into the main config file and then template helper functions expose them to the site. For example:

contacts = require('./data/contacts')

# Define the DocPad Configuration
docpadConfig = {
    getContacts: -> contacts

This makes a method called getContacts available to any template, which then returns the JSON object to be looped through. In the default Jade layout we then have:

  - each link in getContacts()
    li: a.me_ext(href=link.href,rel="external")= link.label

Template inheritance

As conversion progressed (pleasingly quickly) I found I needed a sub-template for articles which would add the 'back to index', headline, etc. I didn't want to replicate the entire main layout file, but documentation on how to inherit from it and add the extra bits wasn't too apparent.

So I guessed, and added a 'layout' declaration to the metadata of the sub-template to bring in the main template as a wrapper. That it worked first time like this is a testament to either my intuition or the logical design of Docpad (I'm guessing the latter).

Excluding files from output

All was going well, and now I was up to the point where I was reconstructing the projects and tools lists on the homepage. These have quite a lot of metadata to them, and I wanted to try and avoid the cludgy JSON object approach. It would also be good to have the option to expand these listings into more detailed articles at some point in the future - especially as a couple of the project links now appear to be offline so I need to describe them here instead.

Making them collections of Docpad documents therefore made sense, but having content-less HTML files cluttering up the output didn't sound like a good idea.

Fortunately a quick dig through the metadata config options revealed the 'write' attribute, which when set to false will still render the document but won't send the result to the output directory. I did notice, however, that the first pass render of each new file would add it to output until the metadata was set, so had to run 'docpad clean' to get rid of them again afterwards. However subsequent generations and deployments were fine.


One of the sections of the site has a common block of text explaining what it is, but this appears across two templates. Rather than replicate this I tried to use Docpad's include method. This seemed to be unreliable with Jade rendering, so I added the partials plugin and set it up that way.

The Docpad tutorials mostly use the eco renderer, so it took a little fiddling around to remember the partial syntax for Jade, eventually using:

!= partial('fiction-about')


Finally I needed to put the new site somewhere. My current Node sites are manually managed on Webfaction hosting, but for convenience I decided to run the new site on Heroku. Docpad has instructions for deploying here, and they worked perfectly. All I need to do now is update the domain.

What an anti-climax, huh? "Web development worked perfectly". There's a first time for everything, I guess.

This post was written with Help Me Write, with a group of people aiming to write a post a week on Sundays and share it on Sunday evening or Monday morning. If you blog you might like to join in.

This version of the Minimum Viable Portfolio runs on Docpad.