Starting over with Nikola

Posted:   |  More posts about nikola python

This site was down for quite some time. I did not want to deploy the old PHP-based site again and therefore looked for alternatives. I never used a static site generator before, but as this site has only a single author (me), I decided to go for it. Python is my favorite programming language, so the site generation tool should also be Python based. I started to look at the Python Wiki blog software list and quickly narrowed my choice down to Nikola:

  • Nikola looks more lightweight than Django based Hyde
  • Nikola supports Jinja2 templates which I'm happily using in various projects.
  • Nikola has its own site with documentation --- it's not perfect, but somebody cared enough to write it :-)

I'm using Nikola's developer version directly from github:

git clone git://
cd nikola
sudo ./ install
sudo apt-get install python-dev python-pip python-lxml python-imaging
sudo pip install -r requirements-full.txt

Starting a new Nikola site is fairly easy:

nikola init myblog
cd myblog
nikola new_post # create a new post (will ask for title)
nikola auto     # build and start internal webserver

Now I just needed to start my own theme:

nikola install_theme base-jinja
mkdir themes/mytheme
echo 'base-jinja' > themes/mytheme/parent

I added a small custom filter in to "compress" whitespace in generated HTML:

from nikola import filters
from functools import partial
import re

WHITESPACE_PATTERN = re.compile('\s+')
PRE_BLOCKS = re.compile(r'<pre.*?pre>', re.DOTALL)

def repl(m, captures):
    name = '$$CAPTURE-{}$$'.format(len(captures))
    captures[name] =
    return name

def compress_whitespace(raw):
    >>> compress_whitespace('a  b')
    'a b'
    >>> compress_whitespace('a <pre> \\n </pre> b')
    'a <pre> \\n </pre> b'
    text = raw.decode('utf8')
    captures = {}
    text = PRE_BLOCKS.sub(partial(repl, captures=captures), text)
    text = WHITESPACE_PATTERN.sub(' ', text)
    for key, val in captures.items():
        text = text.replace(key, val)
    return text.encode('utf8')

    ".css": [filters.yui_compressor],
    ".js": [filters.yui_compressor],
    ".jpg": [filters.jpegoptim],
    ".png": [filters.optipng],
    ".html": [filters.apply_to_file(compress_whitespace)]