By Ev Bogue - December 11th 2013
[Note: I no longer use Hakyll for this site. While Hakyll is excellent, I eventually found a Node.js static site generator that suited my needs.]
Over the past few days I’ve transitioned evbogue.com to Hakyll, a static website generator written in Haskell.
A number of people have asked questions about this. Why did I switch off Node.js? Why Hakyll? How is Hakyll?
I hope to answer these questions in this piece. I will attempt to provide installation instructions for an Arch Linux VPS.
I have to stress that switching to Hakyll is an experiment. I’ve used Hakyll for two days so far, so my findings are all preliminary. I might change my mind and switch to something else – don’t jump on the bandwagon just yet if you have any hesitation!
I was inspired to try Hakyll because of Gwern. Gwern is one of those websites on the Internet I keep going back to again and again, because every time I go there I find a new nugget of information I didn’t see before. Gwern is handling a lot of content (more content than I would ever put on a website) in a graceful way. This convinced me that Hakyll was robust. Gwern has been using Hakyll for a long time, without switching to another tool. I took this as a sign that Hakyll works for him, and that it might work for me too. Gwern explains his website choice on his about page.
Previous to Hakyll, I used a realtime website generator called Bitters that I developed with Gwen Bell as we were learning Node.js. Deploy Node explains how to create this realtime website generator from scratch.
One of the frustrations I had with Bitters, and perhaps Node.js, is I never could find a way to render a whole bunch of routes using markdown files in a folder. No matter how many ‘brilliant’ Node.js programmers I asked about how to do this, no one could answer me with a straight answer or provide a patch that would add this functionality. So adding routes to new documents in Bitters continues to be a pain.
Haskell is not without it’s own headaches. Where Node.js has callback hell, Haskell has dependency hell. While the Hakyll workflow, once it’s installed, is more than ideal, installing Haskell is less than ideal.
To get Haskell to work on your Arch Linux system, you will need to add the Arch-Haskell repository above Arch-Extra in /etc/pacman.conf. Then you will need add the pacman-key for the lead Haskell developer for Arch. Then you will need to update your keyring. If all of this is confusing to you, Deploy Arch Linux is a good place to start if you want to get more familiar with the Arch Linux ecosystem. Read the Haskell Package Guidelines for Arch Linux for more information.
I also tried installing Haskell on Debian and Fedora, and I ran into installation problems. Haskell has some strange dependency issues. Once I got familiar with them, it became easier to get Haskell to install on my systems.
Here’s how I got Haskell to install on Arch Linux, once I added the Arch-Haskell repository.
$ sudo pacman -Syu ghc cabal-install
This installs the Glorious Haskell Compiler and Cabal Install.
Once you have these two binaries, you need to use Cabal to install the rest of the packages. Do NOT install Haskell Packages from AUR. This is a terrible experience.
Cabal Install’s job is to track libraries. However, some Haskell applications depend on Haskell programs. Cabal won’t know if a Haskell program depends on another Haskell program. If you don’t know this going in, you won’t know you have to install alex and happy before you can install Hakyll. Do this now, and not after you get error messages.
$ cabal update
If cabal offers you the option of updating cabal, don’t do it. Instead proceed to the next step.
$ cabal install happy alex
This will install Happy and Alex.
Next, you’ll be free to install Hakyll.
$ cabal install Hakyll
If you’re on a desktop your install should finish and Hakyll will be installed.
If you’re on a VPS, you’ll run into your next problem.
The problem is: GHC takes up so much memory, your installation with probably get a SIGKILL if you’re using a VPS with limited RAM. A SIGKILL means you ran out of memory and the virtualization software tells the application to shut down. This will probably happen for you at the point when you’re installing pandoc, a requirement of Hakyll.
To overcome this problem, you’ll need to add a gigabyte of swap memory to your VPS. Swap memory is virtual memory on your hard disk.
Here’s how I did this on Arch Linux.
$ sudo dd if=/dev/zero of=/swapfile bs=1M count=1024 $ sudo chmod 600 /swapfile $ sudo mkswap /swapfile $ sudo swapon /swapfile
You just created a gigabyte of swap memory, which will buffer your install with extra virtual memory so your install doesn’t get a SIGKILL.
Overwhelmed yet? Well, then stick with Node.js, it’s way easier to install your dependencies. Otherwise, let’s continue.
The Hakyll workflow is pretty simple. Run
to start a new project. If hakyll-init doesn’t work, make sure ~/.cabal/bin is in your $PATH by typing
$ export PATH=$PATH:~/.cabal/bin
This will add the path where Hakyll is located to your $PATH in Linux.
Inside your new project folder, you’ll see a number of files.
Edit these files into a site you want to look at, and then you’ll want to render them using Haskell into a static website.
First, you’ll need to compile your site.hs file into a binary
$ ghc --make site.hs
Then you’ll want to build your site
$ ./site build
and then you want to preview your site
$ ./site watch
If these commmands don’t work, you’ll need to use prefix your command with LANG=en_US.UTF-8, like so
$ LANG=en_US.UTF-8 ./site build
Or set your global language setting for this change to be permanent
$ export LANG=en_US.UTF-8
If anything goes wrong, do a clean
$ ./site clean
When you do a build, it will put your static website in ‘_site’. Then you’re free to serve this static website however you want, using any webserver you want. I’m using lighttpd right now. You could choose to use a Node.js static website, or use the included preview webserver that comes with Hakyll.
What do you think about Hakyll?