10 Oct
2015

The Quest for the One True Static Site Generator

Category:UncategorizedTag: , :

When I started blogging back in 2005 I created my personal blog on Blogger. I’ve been using this excellent blogging service over the years, enjoying the luxuries of not having to deal with the intricacies and complexities of hosting providers and blogging engines. Somewhere last year I started to get interested by the rise of static site generators. These days every self-respecting programming language has one or more associated static site generator tools.

What particularly piques my interest in static site generators is their promise of simplicity. Just spitting out some static HTML, CSS and JavaScript files. Fast to serve by any web server. Back to basics.

So at some point I started my quest to move away from Blogger. The tool I used for the job was Octopress, built on top of the ever popular Jekyll. This meant that I could host my personal blog on GitHub. What’s not to like?

Everything migrated smoothly and I got things set up in no time. But somehow I lost my excitement when everything went online. During the migration I constantly had to Google questions and answers, never having the feeling that I knew what I was doing. As soon as I started working on a new blog post, I got frustrated by the impediments it posed on my writing flow. Having a backlog of 10 years of blog posts ultimately seemed to have a negative impact on the performance of the output generation process. Who knew?

So after almost a year of not blogging, I decided to migrate again to another static site generator. This time I went for raw performance by adopting DocPad. At least, that’s what I thought at the time.

I spent a lot of time in order to get things working. I chose Jade as my templating engine, but got really frustrated by the terseness of its syntax, constantly struggling with the significant whitespace issues. I’ve used Jade in a couple of other projects in the past but I did not remember that it caused me so much pain.

Furthermore, some DocPad plugins were generating errors and/or warnings because they were out-of-date or using some part of the internal DocPad API that had been rendered obsolete in a more recent version, etc. … I constantly had to make compromises regarding the blog features that I wanted to implement because I didn’t get things to work just the way I wanted. After a frustrating couple of weeks I got something going. I pushed it to a brand new server at DigitalOcean and lost interest again.

When I decided to write another blog post, I noticed how very slow the generation process went. Again the impediments and negative impact on my writing flow. Not cool.

A couple of months ago I ran into yet another static site generator named Nanoc via One Thing Well. This one has been around for several years now. I started reading the documentation and instantly got a prototype working. Before migrating my personal blog again, I decided to use it for another static website that I created for my son’s soccer team in order to discover its features and applicability.

I totally loved how simple and easy it was to get things set up. For this website I had a couple of specific issues that I wanted to solve, like quickly adding photo albums and news items. I was able to implement a new version of the website in no time, growing ever more enthusiastic about Nanoc. After this successful venture, I decided to migrate my blog yet again, this time to Nanoc.

Having created two static websites with Nanoc, I couldn’t be happier about how everything turned out. One of the things I like the most is that I can just use plain old HTML interspersed with some erb. Layouts, partials and captures are all at your disposal.

Compilation and routing rules contained by the rules file are pretty amazing and easy to set up. Suppose I want to set up custom routing for all articles on my blog, using the year, month an the slug. Here’s the code to accomplish this:

route '/articles/*' do
      year, month, day, slug = /([0-9]+)\-([0-9]+)\-([0-9]+)\-([^\/.]+)/
          .match(item.identifier).captures
      "/#{year}/#{month}/#{slug}/index.html"
end

Processing markdown files and/or HTML files is as easy as adding the following compilation rule:

compile '/articles/*.{html,md}' do
    filter :erb
    filter :kramdown, :enable_coderay => false, :input => 'GFM', :hard_wrap => false
    layout '/article.*'
end

Here we first process the erb code, then process the markdown syntax using the GitHub dialect and render the output using the article layout. This is all I had to do in order to correctly process all legacy blog posts (HTML) as well as the newer ones (markdown).

Oh, and rendering the entire blog including 10 years of blog posts takes about 30 to 40 seconds on my machine, which is pretty awesome compared to Jekyll and especially Docpad.

Generating output pages from virtual items added from code is a pretty advanced scenario, but almost as easy to set up as the basic stuff. An example of this is generating a page for every unique tag used by a blog article.

def create_tag_pages
    get_list_of_tags.each do |tag|
        sanitizedTagName = sanitize_tag_name(tag)

        @items.create(
            "= render('_tag_page', :tag => '#{tag}')",               
              { :title => "#{tag}", :tag => "#{tag}", :is_hidden => true }, 
              "/tags/#{sanitizedTagName}/",
              :binary => false
        )
      end
end

If you’re in need for a decent static site generator, then look no further. Using Nanoc is an easy and above all, a very fun way to generate static HTML content.

Until next time.