Come with me now on a journey through code and data...

Building This Blog

Why build my own static site generator?

This blog has been an exercise in learning JavaScript. Previously I was building static pages using Hexo with the Next theme (the look of this blog has many elements of the Next theme copied).

Hexo has so many features and special effects which is cool, but also confusing. I wasn't able to easily customise it - like for the main pages which aren't part of my blog, or for displaying Jupyter Notebooks which I use a lot for making notes when learning new things.

As Hexo is just a static page site generator, I decided to build my own very simplified version of it. This way I would know how every part of it worked and have complete control to make it look how I wanted. I've lost a couple of features that I can one day add back in, such as comments from Disqus, and Google Analytics tags applied to each page, also I lost all the animations. But now I can post any custom type of page I like and have made code to convert Jupyter Notebook's and display them nicely.

The Structure

The main components of the site are split into templates and use a library called Mustache to piece them together to create my static site.

I have a bunch of partials that sit in their own folder - like the header and nav bar that appear on every page, and the navigation footer that is at the end of every post.

I have three main templates at the moment which are the main types of page I might display, these are my main pages - simple pages that only contain the header and nav bar, my archive page that lists all blog posts, and my blog-post pages which includes the nav footer.

As I create new posts and pages I add them to a source directory and reference them in a config file which is basically just a big JSON object. The config contains the page title, type, post-date, and path to source file.

Finally there is the script! The script reads loads all templates in the partials and templates directories, then loops through the config generating a new page for each entry, placing them in a public folder.

There are also additional files to be copied to the public folder like css,images,pdfs,js etc

In [ ]:
blogPosts.js // Config file of blog posts to be generated
siteGenerator.js // Script to be run in Node to convert all content into HTML

/ partials
      header.mustache
      footer.mutache
/ templates
      mainPage.mustache
      archive.mustache
      blogPost.mustache
/ source
    / images
    / pdfs
    / blogPosts
        myNotebook.html
/ public
  ...

Mustache

There's not much to building Mustache templates, they're just HTML with a few additional tags for places to insert partials or variables. Here's a few examples of the different things you can insert:

Strings

Double-curlies

In [ ]:
var titleVarName = "Home Page"

example.mustache:

In [ ]:
<html>
    <head>
        <title>{{titleVarName}}</title>
    </head>
    <body>
    ...

HTML

Triple-curlies

In [ ]:
var mainContentHTML = "<p>Welcome to my website<br/>Take a look around</p>"

example.mustache:

In [ ]:
...
    <body>
      {{{mainContentHTML}}}
    </body>
</html>

Partials

Partials can be templates so need to be handled differently to HTML in order for variables to be passed into them.

In [ ]:
var headerPartial = "<div>Welcome {{name}}. This is the header partial!</div>"

example.mustache:

In [ ]:
<body>
  {{> headerPartial}}
  ...
</body>

To avoid url escaping make sure to include ampersand:

example.mustache:

In [ ]:
...
<link>
  {{& linkPath}} 
</link>
...

Mustache Rendering

In [ ]:
const template = fs.readFileSync(templatePath).toString()
const contentVars = {'title': 'Archives', 'homePageLink': '/', 'contentHTML': contentFromFile}
const partials = {'header': headerFromFile, 'footer': footerFromFile}
In [ ]:
const renderedHTML = Mustache.render(template, contentVars, partials)