What is a static site generator?

Way back when I started this blog I was using Wordpress. Wordpress is cool, but too cool for me. It’s morphing into a fully blown content management system - which I don’t need for my simple blog. I like writing my blog posts in Markdown, and even though Wordpress has a plugin, it screws with the formatting, and besides - I prefer to write things in Emacs.

And poor Wordpress. None of my content is dynamic. Even the Twitter stream, which reads my latest status updates is a bit futile if I only update my Twitter status every 3 months. I was using all that processing power to generate something which was basically just HTML.

Why write my own?

It didn’t seem like a difficult thing to do, a couple of scripts to convert some Markdown into HTML, and then something to place the generated Markdown into a HAML template. It was very simple, but then I started adding things.. My quick and simple static site generator started to suffer from feature creep and whoneedswp was born.

I started adding support for Disqus, Google Analytics and syndication of Twitter feeds. Soon I’d open sourced the code so the world could see the delights of my hastily put together Ruby scripts.

However, instead of persevering with my own static site generator I’ve decided to look at some others. Mine certinally isn’t perfect, and I don’t have the time to maintain it anymore. I needed to find an alternative.

Along comes Nanoc3

After reading thechangelog I stumbled upon nanoc3 . Nanoc appears to be quite an old project, but it has all the working parts required to convert my website from using whoneedswp.

An understanding of Rules and how to break them

Nanoc3 is more advanced than whoneedswp. There is a lot more flexibility in how the site is generated. whoneedswp required content to be placed in the correct folder structure. Nanoc3 allows you to specify your own. You can even create new data sources of content. All of this is specified within a special config.yaml.

The other configuration file is Rules. This specifies what type of content these is; Nanoc3 supports more than just Markdown; what templates are used and how it is converted into HTML.

Migration of content, adding YAML headers to files

One of the features of whoneedswp was that it would scan the content of pages and look for metadata. These were lines which started with “Summary” or “Tags”. Anything following the colon on this content was used removed from the content, and was available for use by the page templates. This allowed me to display the summary of the page in an alternative location, and more interestingly allowed me to generate tag clouds for my content.

nanoc3 also allows you to embedd metadata within the content of the pages; but instead of scanning the content of the document it reads a section of YAML from the top of the document. YAML is a “straight-forward machine parsable data serialisation format”, so allows you to easily describe metadata associated with the page in a format which which is easily converted into code. Marvellous.

Tag clouds and automatically generated pages

Although there are a couple of helpers for tagging content in nanoc these only extend to listing tags associated with a specified item or returning items associated with a specified tag.

There are two main components related to tags in my site; the tag cloud and the tag page. The tag cloud lists all the tags in the site and emphasises the more popular ones. Each tag page lists all the items which are associated with the specified tag.

The Helper interface allows you to specify functions which can be used within any item template. Unfortunately, because I wanted to place the tag cloud on every page, I would have to generate the tag cloud before any of the page content was created. Fortunately within the Rules file there is provision for pre-processing.

preprocess do
  @site.collect_all_tags
end

The above block of code invokes the collect_all_tags function within Nanoc3::Site. I added this function by adding some custom code to the lib/ folder within my site.

collect_all_tags not only counts the number of tags and assigns each tag a weighting, but it also creates a new Nanoc3::Item for every tag. These items have no content, but have a name and title set. The items are also given the virtual path of /tags/ which by adding a simple compile directive to the Rules file allows them to use a custom template.

compile '/tags/[^\/]+/*' do
  filter :kramdown
  layout 'kind_tag'
end

The kind_tag template dynamically builds the content for the item based on the name tag assigned to it and the pages assigned to that tag:

.content
  %ul
    - items_with_tag(item[:name]).each do |i|
      %li
        = link_to(i[:title], i, { :class => "title" })
        %p= i[:summary]