# Personal Website Redesign

by Created: 15 Apr 2014 Updated: 20 May 2014

After 8 years of neglect, I recently recreated my personal website. This note describes the new site build, deployment, and design.

## Build

I wanted statically-generated site content using a mix of Markdown and HTML.

After surveying the available template languages, I actually set out to create my own. I may eventually release that software, once it’s mature enough to support this site. However, that project was taking longer than I was willing to spend on it; I wanted results faster.

So, after taking another look at available technologies, I settled on Jekyll, which uses Liquid for templates. Jekyll offered most of the features I needed, including LaTeX (using MathJax) and code syntax highlighting (using Pygments) out of the box.

### Jekyll Setup

Ruby is a bit of a pain to install on Dreamhost. I followed these instructions but ran into compiler errors, apparently because GCC was running out of memory. What worked for me was to then cd into the build tree (see the log for its location) and manually make and make install.

I also needed to install some dependencies, for Jekyll and the plugins and config options I use:

Jekyll itself was pretty straightforward to setup and use, except that I have multiple collections. Support for multiple collections is under development in Jekyll but not yet released. I tried using the proto version of it, and found it didn’t do half the things I needed, so I used the jekyll-page-collections plugin to handle the ‘Projects’ and ‘Notes’ parts of this site.

### Jekyll Plugins

I ended up needing quite a few plugins. I’ve written 11 so far and counting. It’s great that Jekyll is flexible enough to enable this, but I have run up against some limitations.

I didn’t see a plugin for generating Amazon affiliate links, but it’s trivial to do this in Jekyll; here it is in its entirety:

Save that as amazon.rb in your _plugins folder and use it in templates as {{ ASIN | amazon }}. For example, {{ '0321165810' | amazon }}.

I also wanted to change the highlighter markup so that it includes the language canonical name nicely formatted. My solution to that was to override an internal method of the builtin HighlightBlock, which is fragile but works for now. While I was at it, I also tracked whether a page uses any syntax highlighting, so that I could conditionally include the syntax.css file only on those pages that need it, for performance.

Normally, Jekyll can include files only from the _includes directory. To show source code here from the _plugins directory (or any other source code of the site), I wrote a plugin to include files from arbitrary locations. For example, {% includeraw _plugins/includeraw.rb %} displays this plugin itself:

I also wrote a plugin to generate a sitemap that handles all page-collections and static files, another plugin to generate TOC (there are several out there, but they all had problems with my site design), and others. Eventually, I’ll put these up on GitHub.

## Deploy

There are many ways to deploy Jekyll-generated content. I’ve used git for deployments on many projects now, and it works well for my purposes.

When using git on DreamHost, it’s necessary to configure headless git to play nicely in their environment by creating a ~/.gitconfig file. I use these settings:

I also use rbenv there (installed into ~/local/, and added to ~/.bash_profile and ~/.bashrc).

There are many ways to use Git for deployment, but they’re all similar in spirit to this. You set up a bare repo to use as the remote for local deployment and a separate repo to use for the deployment source tree, and then finally configure a post-receive (or post-update) hook in the bare repo that causes the other repo to pull.

Those instructions build locally and push the build products to the remote server. I like to also build remotely, which involves adding jekyll build to the hook, with either the _config.yml file set to build to the right place, or else passing --destination to the jekyll build command.

Note that, whether you build locally or remotely, this deployment method is non-atomic. I recommend deploying atomically, by combining this with Capistrano or an equivalent method. Otherwise, you risk an outage if any errors occur.

## Development

I use Pow and jekyll build --watch (instead of jekyll serve --watch). Pow makes vhost setup painless, and also enables testing on other devices on your LAN, which is very useful for testing mobile and other browsers.