Matt Sweetman

New website built with Haggerston

Haggerston overground logo

The latest version of this site was built using Haggerston, a static site generator developed by myself and Kelvin Luck. It was named after the place it was built in.

For the past few years this site has been powered by Wordpress, but after several hacking attempts and an endless battle with spam I decided it was time to change. The new site is served as flat HTML files, generated locally using Haggerston and then uploaded to the remote server. No PHP or databases are involved, helping keep maintence and security issues to a minimum.

Leveraging the power of Grunt

Haggerston is built as a Grunt task. The reason we chose Grunt is because it can already do a lot of what is needed to generate a static site. It can copy files and folders, compile CSS, rsync to remote hosts, start local servers, and watch for file changes. The only task that's missing is one to generate HTML pages. This is where Haggerston comes in.

Haggerston is a relatively simple task, it's job is to turn a folder of .json files into .html files. Each json file specifies a template to use when rendering the html. If you've used javascript templating libraries before then the process should be familiar to you. All Haggerston is doing is turning templates into html files, and using the json files as data for the templates. Haggerston uses Swig as its templating language.

A basic example

Using Haggerston is as simple as dropping in an empty task into your Grunfile.js:

module.exports = function(grunt) {
  grunt.initConfig({
    haggerston: {}
  });

  grunt.loadNpmTasks('grunt-haggerston');
};

This makes the following assumptions: source files exist in a subfolder called src/content, templates exist in src/templates, and the generated site will be created in a subfolder called out. Each of these properties can be overridden in the config if necessary.

Let's take the url for this article as an example. The page exists at /articles/new-website-built-with-haggerston/, which started life in a source folder on my local machine like so:

src
└─┬ content/
  ├─┬ articles/
  │ └─┬ new-website-built-with-haggerston/
  │   └── index.json
  └─┬ templates/
    └── article.html

Running grunt haggerston from the command line will take each .json file from the content folder, render it against a chosen Swig template from the templates folder and export the .html into a corresponding structure in the output folder:

out
└─┬ articles/
  └─┬ new-website-built-with-haggerston/
    └── index.html

You choose which template to render the data against by specifying it in each json file. Let's take a look at the index.json file of this page as an example:

{
  "template": "article.swig",
  "templateData": {
    "title": "New website built with Haggerston",
    "date": "2013-04-27",
    "blurb": "How I built my new website with Haggerston and Grunt",
    "content": "index.md"
  }
}
  • "template" specifies which Swig template will be used to render the .html file. This is the only mandatory property of a Haggerston .json file.
  • "templateData" is the data that will be sent to the Swig template when it's rendered. You can put anything you like inside it, or omit it entirely.

This process is extremely simple, but the key to making a good static site is knowing how to use templates. Swig supports something called template inheritance, and it allows templates to inherit and override blocks of markup from their parent. Check out the Swig documentation for an example of how to use it.

Using the concept of middleware

Each step in the Haggerston process is designed as middleware, an idea borrowed from connect that allows developers to intercept the flow of a process and manipulate the data being worked upon.

You may have noticed a property in the index.json example above:

"content": "index.md"

Haggerston is designed to find properties with values that end in '.md'. It then tries to locate the referenced markdown file, parse it into html, and replace the original property with the result. This means that when you use {{content}} in your template you're actually getting the html generated from the index.md file, not the string 'index.md'.

The part of Haggerston that does this is called the Markdown middleware. It's simply a function that gets called during the overall Haggerston Grunt task. Each middleware acts the same, and the function is given access to all the json data and rendered templates, meaning it can manipulate the pages in whatever way it likes before they're written to disk.

The basis for a piece of middleware looks like this:

module.exports = function() {
  return function (pages, next, options) {
    // Here you can manipulate the pages array in whatever way you want.
    // Afterwards just call next(pages) to continue with the Haggerston process.
    next(pages);
  };
};

Haggerston comes with a default set of middleware modules that performs common tasks. Each middleware is executed sequentially, and is top-and-tailed with core tasks that cannot be moved. Here's an example of how the overall process works:

  1. Core process: Read .json files into javascript objects
  2. Middleware: Read markdown files and parse them into html markup
  3. Middleware: Render the template into html markup
  4. Middleware: Highlight any code blocks found in the rendered markup
  5. Core process: Write the rendered markup to .html files.

You can write your own middleware and insert it at any point between the opening and closing core processes.

Limitations

Static sites will never be as powerful as dynamically generated sites, but they can make a good approximation. With some clever middleware and templating you can create common blog-like features such as categories, tags and pagination. Perhaps the most difficult thing to implement is a commenting system. The most popular solution is a third party service such as Disqus, which helps delegate the responsibility of maintenance and security issues to a third party.

Overall the decision to choose a static site over a dynamic one is down to how complex you think the site will be. For an infrequently updated blog run by a single user it's a good choice, and I'd recommend investigating the possibilities.


Flashkana for iPhone

Flashkana screenshot

Flashkana is now available on the App Store for iPhone. This is the iOS version of my original Android app.

After finishing the Android version I spent some time trying to figure out the best way of porting the app to iOS. Eventually I decidied to write it from scratch using the native toolset, it seemed the only approach that would produce the best performance and most consistent behaviour.

Arriving late to iPhone development has given the iOS framework plently of time to mature. Building the app was effortless, the XCode toolset is rich and powerful, documentation is detailed, and community support is plentiful. It took a fraction of the time to develop of Android. It was obvious that the Android framework was still finding it's feet when I first started with it. I'd had to write a custom view-swiping mechanism. UIScrollView is a built-in component in iOS and provides the exact mechanism Flashkana requires. This instantly solved a large chunk of the build. (It's worth noting the same type of component is now available in Android.)

The app is free, so head over to the App Store to check it out.


What's That Tag?

What's That Tag? screenshot

What's That Tag? is a small game I've been working on recently. The aim is to guess what word has been used to tag a collection of images. The images have been tagged by users on Instagram and the game uses it's API to search and retrieve relevant photos. For each round it takes six images and shows them to you one-by-one till you correctly guess the tag that was used to conduct the original search. Bonus points are awarded for each un-shown image.

The game was built using Backbone, Underscore and jQuery. It uses CSS 3D transitions for the image flipping animation, so you'll need a modern browser in order to play it. It also works on iPad, although because the keyboard needs to be visible it's best played in portrait orientation.

After testing it for a few days I've found the quality of tagging on Instagram pretty dubious, which can make the game quite difficult. I've adjusted the search terms to try and return more obvious images but it can still be tricky. Perhaps another API like Flickr might be better.


Base class for Backbone

The core Backbone objects (Model, View, Collection and Router) have a convention for construction and initialization that make them feel more like traditional classes. This convention provides a degree of consistency across the Backbone framework. In a large project you might find yourself wanting to use it for all objects, not just Backbone ones, so the following class might help you out.

BaseClass ensures it follows several rules laid out in the other Backbone classes:

  • Call initialize upon instantiation, passing any arguments that were sent in the constructor
  • Extend prototype with Backbone Events functionality
  • Give each instantiated object a unique id

This is the minimum existing Backbone classes provide, so it's perfect as a basis for our class.

// Create a new object constructor and call initialize on instantiation
// This follows the convention laid out by other Backbone classes
Backbone.Class = function(options) {
  this.cid = _.uniqueId('class');
  this.initialize.apply(this, arguments);
};

// Extend the prototype with Events and a default initialize function
_.extend(Backbone.Class.prototype, Backbone.Events, {
  initialize: function(){}
});

// Add the extend method to allow us to create subclasses of the object
// Steal the reference from Model as it's innaccessible outside Backbone
Backbone.Class.extend = Backbone.Model.extend;

You can also find this available as a Gist: https://gist.github.com/2843476

The only slight oddity is how we must borrow extend from one of other Backbone classes. In this case we've chosen Backbone.Model, but View, Router and Collection are equally valid. Unfortunately Backbone doesn't make the extend method available publicly so this is the only solution.

The base class can then be used in a similar way to other Backbone classes:

var LoaderUtility = Backbone.Class.extend({
  initialize: function(options) {
    this.timeout = options.timeout;
  }
});

var loaderUtility = new LoaderUtility({timeout: 5000});

You might find this adds a bit of consistency to your code base. If this approach is too reliant on inheritance then you can always try adapting the example to create a mixin.


Javascript 1K demo

Lattice of Love screenshot

Lattice of Love is my submission for this year's JS1K competition. The theme is 'love' so a heart seemed quite appropriate.

The lattice pattern is based on a hypotrochoid, better known to many kids as a Spirograph. Instead of rolling the cog around a circle I've rolled it around a heart shape, which is be described using the heart curve equation. I've used a couple of Canvas bitmap operations to provide a slight blur and after-image, which help smooth out the visual appearance.

The code was optimized and compressed using Google's Closure Compiler, which got it down to 813 bytes - nicely under the 1K limit.

You can check out the source code here: https://github.com/webroo/lattice-of-love