Migrating from Jekyll to Hexo

status
published
dsq_thread_id
TL;DR: I migrated my blog from Jekyll to Hexo. This is everything you need to know to do the same.

Initializing Hexo in your existing Jekyll project

Here's what I did:
Back up your existing Jekyll blog to a subdirectory so you can wildly make changes with impunity:
mkdir jekyll.bak
Now move all the non-git files in the directory into jekyll.bak. Initially I just did it in finder, but then I got curious about how to do it in bash. So if you want to just run a nifty command here you go:
find . -maxdepth 1 -mindepth 1 ! -name '.git' ! -name 'jekyll.bak' -exec mv '{}' ./jekyll.bak/ ;
We keep the .git/ dir around so that we can cleanly iterate towards a Hexo blog from our Jekyll blog while maintaining all previous version control history. However, the hexo init command actually removed .git/ on my system so we need to move it too, but only temporarily:
mv .git .git.bak
Now initialize Hexo in your project directory:
hexo init .
This should have left jekyll.bak and .git.bak intact while adding a bunch of new files. Now it's safe to bring back your Git history and add a commit:
mv .git.bak .git
git add .
git commit -m 'Add Hexo boilerplate'
Now we've succesffully initialize Hexo. From here on out everything we do will to customize Hexo to suit our needs.
To make sure everything is running properly run the dev server:
hexo server

Migrating Content

Now let's get all your blog posts migrated over to the new system. When running the server you should see the Hello World post as your first post on the homepage. You will also see the default Hexo theme. Here's what that looks like:
Default hexo blog
Default hexo blog
That "Hello World" post is the only post in your blog. Hexo keeps all your posts at source/_posts. Let's remove the default post.
rm source/_posts/hello-world.md
Now, since Hexo and Jekyll are very similar in how they store your posts it's very straightforward to migrate all your content. First, copy it all over. If you also used jekyll.bak to backup your original blog then you can do this:
mv jekyll.bak/_posts/* source/_posts/
Second, update your Hexo settings to recognize Jekyll-style post filenames. In _config.yml edit the line for new_post_name:
new_post_name: :year-:month-:day-:title.md # File name used to identify posts
Now restart the Hexo server and you should see all your content 😎

Gripes

Hexo is not without its shortcomings. I'll outline those here, but take this with a grain of salt because I just started using Hexo yesterday so it may be that my gripes are due to lack of understanding rather than actual problems with the framework.

Not simple to create standalone pages

Hexo is highly content focused, meaning when you create a new "page" you are actually just creating a new Markdown file with some content. In my experience the "content first" approach is perfectly suited to blog posts, but not necessarily to pages which are often unique in layout.
For example, I wanted to create a /tags page. This is simple enough using the Hexo API in a layout file:
<% site.tags.each((tag) => { %>
	<a class='tag' href='<%= url_for(tag.path) %>'>
		<%= tag.name %>
	</a>
<% }) %>
But I wanted to be able to do this on one single page. I.e. instead of writing markdown I wanted to write the above code and output all my tags. This didn't work, so I ended up creating a workaround where my tags.md file does nothing more than specify the layout I want to render.
---
title: Tags
layout: tags
---
This may seem minor, but I would have liked to be able to simply put the above EJS code into my "page" file and had it render.

Not simple to create helper functions

More than once I found myself wanting to refactor some view logic out of the EJS templates and into an external helper function. As of now it's still unclear to me how to do this. I ended up writing all my code inline in the EJS files but this is not pretty.

Documentation

This is a tough one since Hexo actually has quite a bit of documentation online. However, I found it didn't readily cover the things I really cared about. Namely, in-depth guides to creating themes.
For example, things like:
  • How to loop through various content types (posts, tags, categories, etc)
  • How to sort, filter, etc, those content types
  • What methods and properties are available on all the Hexo objects
I ended up discovering these things through trial and error or viewing other peoples themes. This is fine, but it seems that it could be greatly improved to limit the time it takes someone new to the framework to get comfortable with it.

Development Takeaways

Regarding layouts and templating: If you want to create custom pages then create a new layout file with the desired name (say about.ejs) and then specify that layout file in the post/page markdown file:
---
layout: about
---
Regarding helper functions: I didn't find a good way to add helpers yet but I haven't yet read through all the docs. Who knows, maybe there is an elegant solution.

Why

I've been meaning to redo my blog for a while. Jekyll does it's job quite well, but I never liked liquid templates and my existing blog has needed some work for quote some time. For example, code snippets when rendered in post excerpts sometimes caused unclosed <pre> tags, which would really mess up rendering for the whole index page.
Also, JavaScript. I write it all the time so it makes sense to use it for my blog. I also like the emphasis out of the box on Stylus as opposed to Sass or Less.
Lastly, a good friend of mine recently told me he uses Hexo for his blog. Personal recommendations go a long way.

Outcome

So far I've been quite happy. Things I like:
  • Drafts
  • CLI for creating content
  • Simple, multi-language support
  • Powered by JavaScript