From Ghost to Hexo

I’ve moved this blog from Ghost to Hexo.

Why? I liked Ghost’s interface and it’s very straightforward compared with WordPress, but it has too many moving parts. I like editing posts with a real editor, or directly on GitHub for speed. Being able to hook everything up to a CI service and use pull requests makes life easier. So it’s static site generators all the way for me.

Jekyll is easily the most popular SSG (powering GitHub pages will do that) and it’s a fine tool, but managing Ruby is a pain. The same goes for Middleman: too Ruby. Hugo looks like it could be fun, but I’m not quite ready to leap into Go.

So, Hexo. It’s built with JavaScript and uses EJS and Swig for templating, so I can keep using the tooling I’ve been working on over the past couple of years. Getting started was fairly straightforward.

  • I installed Hexo locally. It was as straightforward as installing any other npm package.

  • My Ghost install was at 0.4.x, so I exported my posts using the not-so-secret ugly debug tools. It looks like this menu has been renamed “Labs” in more recent versions of Ghost.

  • I attempted to import my Ghost posts into Hexo with hexo-migrator-ghost. This failed with:

    $ hexo migrate ghost GhostData.json
          throw (e);
    TypeError: Cannot read property '0' of undefined
        at /Users/paul/Projects/anglepoised-notes/node_modules/hexo-migrator-ghost/index.js:27:21
        at fs.js:334:14
        at /Users/paul/Projects/anglepoised-notes/node_modules/hexo/node_modules/nunjucks/node_modules/chokidar/node_modules/readdirp/node_modules/graceful-fs/graceful-fs.js:104:5
        at /Users/paul/Projects/anglepoised-notes/node_modules/hexo/node_modules/hexo-fs/node_modules/chokidar/node_modules/readdirp/node_modules/graceful-fs/graceful-fs.js:104:5
        at /usr/local/lib/node_modules/hexo/node_modules/hexo-fs/node_modules/chokidar/node_modules/readdirp/node_modules/graceful-fs/graceful-fs.js:104:5
        at FSReqWrap.oncomplete (fs.js:95:15)

    Sigh. I couldn’t be bothered to debug this, so tried sucking the posts out of the existing Ghost feed with hexo-migrator-rss. This worked. Hurrah!

  • Mostly, anyway. I started the Hexo server with hexo server and noticed a few formatting issues. I have so few posts that repairing each by hand was the most straightforward way to fix this.

  • Hacking the URL from /year/month/post/ to /year/month/ didn’t work - no date-based archive pages. I should probably fix this at some point. Maybe hexo-generator-archive will do it.

  • Tags weren’t appearing on posts. I manually added them to the Front Matter in each post, and added tags: {% raw %}{{ tags }}{% endraw %} to scaffolds/

  • The share tool at the bottom of each post pointed to This prompted me to sort out the config. This was trivial. It’s just YAML.

  • The default Hexo theme is a bit meh. I tried a couple from the theme directory, but they didn’t work for me. There are many more themes in this old list, but it’s not clear whether they’d work properly with the latest version or not. So, another thing to fix later.

  • I like favicons. It took me a while to work out that the favicon filename is set in the theme’s _config.yml and the file itself should be dropped into the /source directory.

  • The feed wasn’t being generated. I had to install hexo-generator-feed and update _config.yml to get this working.

      type: atom
      path: atom.xml
      limit: 20
  • I like using npm as a build tool so I made npm start run hexo server. Small beginnings.

I still have plenty of things I’d like to do (CI! Linting Markdown! Using PostCSS!) but I’m please that getting from zero to minimum viable blog was this straightforward.