Migration From WordPress to Hexo Site Generator

A “static site generator” is an application, in most cases exposing a CLI (command line interface) to build a set of HTML, CSS and JavaScript from your website project and you serve those files as your entire site without the need for a database. No Database means no query optimizations or memcaching. An SSG generates your entire site as nothing more than a collection of front-end resources, and that equates to speed. To the users, these pages act no different than a regular blog, the posts are just “hard-coded”. If you’ve ever used server side caching on your WP site then the concept should be a bit familiar. One method of server caching does attempt to build static content over generating each piece of each page on each page load.

Hexo is a SSG (static site generator) built with Nodejs. Hexo isn’t the top dog on the SSG market, there are some wider used options like Jekyll and Octopress, both are very stable Ruby SSG’s. I chose Hexo because it seems to be building a lot of popularity and I wanted an SSG built on Node. Since the finished site is nothing but HTML, CSS and JavaScript our projects can be setup to use almost any language that compiles/transpiles into browser friendly resources. This means all the code we write will be tied to web development moreso than the language underlying the SSG. There are helper methods specific for Hexo, but in general, all SSG’s I’ve looked into use the same tech so we could easily migrate from a Nodejs SSG to a Ruby, Python or even a Go SSG…

I have a great deal of respect for WordPress being that much of the work I’ve done has been WordPress related. I’m not leaving WordPress as a developer but rather I’m leaving as an author who writes about development and wants a performance site at little to no cost. I’ve been thinking about this move for awhile now. Speed is a huge factor in modern development, (RAIL wink* wink*), I don’t require many of the features that WordPress provides, so I don’t feel it’s the best fit for OneThingSimple anymore.


An Explanation Before the Hexo Migration

WordPress is extensible, the customization possibilities are amazing. We can all agree that the WordPress dashboard offers a robust UX and puts hundreds of thousands of tools at the finger tips of site admins, but the dashboard can be slow moving (especially when hosting within a budget). It’s not that WordPress itself can’t be fast, I’ve optimized WP/WC sites into “PageSpeed” scores over 90 while still running sliders, carousels, accordion tabs and custom JavaScript. See this recent article with blazing fast WP templates, those speeds come only from hard-work and planning. There are many detailed articles on fine tuning WP sites which speaks to the fact that it’s not a “1-2-3 and done!“ easy thing to do. Most performance gains don’t effect the admin dashboard either and that’s where a site author and admin spends most of their time. If you’ve ever spent a day tuning settings in a large WP plugin such as “W3 Total Cache” then you know how much development time is prolonged by the seconds accumulated over many page loads changing settings and testing results.

My final point is the disconnect between “PageSpeed” score and actual page speed. A “PageSpeed” score is what your managers and marketing team pushes for because it affirms a websites usability and adherance to best practices through the eyes of a web crawler. “PageSpeed” is supposed to help site SEO and is a valued site metric (no argument there). Actual page speed though, and perceived page speed are what your visitors experience while interacting with your site, it’s a huge factor in how the user ultimately thinks of your site and if they come back. Is it nice? fast? does it feel good to use? If so then the user feels good too. But if the site is slow, janky and unresponsive then the user is frustrated and most likely doesn’t want to come back. WordPress sites can have great performance and beauty, but the dashboard, the database, the plugins all come with a price. For a standard blog with pictures and articles, that price can be quickly negated using a “static site generator”.


An expensive coat might be nice to have, and it can be a lifesaver too,
but if your living in the desert then you probably don’t need it
.

WordPress is the coat in that example and this blog is the desert.. In more ways than one.


Hexo who? What is a static site generator and what is it good for?

A “static site generator” is an application, in most cases exposing a CLI (command line interface) to build a set of HTML, CSS and JavaScript from your website project and you serve those files as your entire site without the need for a database. No Database means no query optimizations or memcaching. An SSG generates your entire site as nothing more than a collection of front-end resources, and that equates to speed. To the users, these pages act no different than a regular blog, the posts are just “hard-coded”. If you’ve ever used server side caching on your WP site then the concept should be a bit familiar. One method of server caching does attempt to build static content over generating each piece of each page on each page load.

Hexo is a SSG (static site generator) built with Nodejs. Hexo isn’t the top dog on the SSG market, there are some wider used options like Jekyll and Octopress, both are very stable Ruby SSG’s. I chose Hexo because it seems to be building a lot of popularity and I wanted an SSG built on Node. Since the finished site is nothing but HTML, CSS and JavaScript our projects can be setup to use almost any language that compiles/transpiles into browser friendly resources. This means all the code we write will be tied to web development moreso than the language underlying the SSG. There are helper methods specific for Hexo, but in general, all SSG’s I’ve looked into use the same tech so we could easily migrate from a Nodejs SSG to a Ruby, Python or even a Go SSG.

Hexo has a plugins just like a regular blogging platform, some of them are geared towards augmenting your posts and others towards augmenting the site or the SSG in itself. There are Hexo plugins for easy deployment, ftp syncing, minification and even an admin UI. We can write our own Hexo plugins if we truly wished, which is the foreseable benefit to choosing an SSG built on a language which you already know. When we switch to an SSG like Hexo our writing will be primarily done using markdown files to author posts, and using EJS to build layouts, YAML for configurations and Stylus as a CSS preprocessor. As I wrote above, these options are not limited, we could customize Hexo to use JSON instead of YAML, Jade instead of EJS and SASS instead of Stylus simply by installing more plugins or tweaking a few settings. Plugins install like any other npm module scoped to a project: npm install hexo-<plugin-name> --save-dev. See Hexo plugins.


The Install, Migration and Theme Setup

To use Hexo you’ll need Nodejs and Git installed. Hexo runs as a CLI (command line interface) so it has to be installed globally to ensure that it’s accessible through your systems PATH variable.

1
$ npm install hexo-cli -g

Creating a new Hexo project is quick and easy using the command hexo init <blog>, where “<blog>“ is the name of the project folder. I’m going to make my project directory ~/projects/onethingsimple so I’ll run the following lines in my shell:

1
2
3
$ cd ~/projects
$ hexo init onethingsimple && cd onethingsimple
$ npm install

Now that the basic project is created, running the command hexo server from the project root will listen by default on http://localhost:4000 and generate the site so far for any incomming requests. There is a single blog post with some links to useful information up on the site. I’m not going to dive into detail about stuff that is already written perfectly fine in those Hexo docs already but I’ll suggest that after your up and writing that you check out the config file documentation to learn about how to work with your Hexo _config.yml file.

We’re able to have a _config.yml file in our root folder which stores setting variables regarding the project as a whole and we can also put another _config.yml inside theme folders which can house variables useful within the context of that themes files. Also, at the top of our posts we can store variables specific to that specific post.

At this point we’re ready to start authoring, if you want to have an admin panel for writing you can run npm install --save hexo-admin which installs a plugin with a post management and writing page. When you launch a server using hexo server -d you’ll not only see your page at http://localhost:4000 but also a place to write and organize your content at http://localhost:4000/admin. Pretty cool right?

The “Hexo Admin” plugin is managed by Jared Forsyth and is one of the best solution imo for writing posts using markdown. One downside to the “Hexo Admin” setup is that it doesn’t render preview text as well as applications built for more general writing such as the website/app Stackedit.io. Other solutions include Poe Markdown Editor, Minimalist Markdown Editor, or you can edit files directly from your favorite text editor in which case I’d recommend looking into a plugin or package such as MarkdownEditing. There are also apps like “MarkdownX” for Android which works very well.

Import Wordpress Posts to Hexo

So this is the important stuff here right? Regardless if you write 6 posts a month like some bloggers or 6 posts a year like me (I’ve gotten a little better lately), no one wants to lose years of their writing. Also, we don’t want to break external links that could be pointing to posts on our site. With WordPress we most likely used permalinks to create neat, organized urls because they are readable and SEO friendly. There is an option for permalinks in Hexo which will determine the folder structure created when we generate our static files. We can use redirect rules on our server to fix any pages which don’t fit the folder structure we designate.

Go into your WordPress dashboard, navigate into the “Tools” menu, click “Export” and then download your content as an XML file. Now install the Hexo WordPress migration tool using this command where <source> is the location of the downloaded XML export:

1
2
$ npm install hexo-migrator-wordpress --save
$ hexo migrate wordpress <source>

At this point, you may be all set or you may get an error. I got a parsing error. That’s fine, it looks as if all my posts were brought into the Hexo source/_posts folder along with new folders for each of the different pages which were on my WordPress blog. To keep the same page structure I’ve modified _config.yml to contain a few of the following important key values:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Site
title: OneThingSimple
subtitle: web, dev, point of view
description:
author: Michael Rosata
language: en
timezone: America/New_York
# URL
## If your site is put in a subdirectory, set url as 'http://yoursite.com/child' and root as '/child/'
url: http://onethingsimple.com
root: /
permalink: :year/:month/:title/
permalink_defaults:
# Directory
source_dir: source
public_dir: dist
tag_dir: tag
archive_dir: archives
category_dir: category
filename_case: 1

The most important values above are the permalink because it will keep the same path structure as the WP site had. The key filename_case will prevent tag and category page links from using “display name” casing in their URLs (so a URL to category “Some-Thing” can read /category/some-thing rather than use capital letters). Then archive_dir and category_dir should be set to the same values that were used in your WordPress installs permalink menu page. Now from here all your pages should load using the same path structure. I recommend using your WP sites sitemap.xml file to check.


Local Development, Get the Site Working Well

At this point we’ll want to run the server again from the root directory using the shell hexo server. Here I checked out the site and things looked good, some posts didn’t parse 100% perfect. Very minor details, when I found a broken post I just went into the /source/_posts/<broken-post-name>.md file and fixed the markup/markdown. All the links transferred fine but the post images are just urls back to my WordPress install. I found a Hexo plugin which runs through all my posts and pages, finds images with external links and downloads those images to the Hexo project and then changes each images src attribute to reference the local copy.

There was a problem with my WordPress plugin “Crayon” which I used to post code on my blog with syntax highlighting. Crayon displayed inline lines with <code> and multi-line blocks with <pre>. Those didn’t convert in the parse into Hexo. I wanted to replace the Crayon style markup, which looks like <pre class="lang:javascript>...</pre> from the migrated WP posts into markdown which looks like ```javascript <newline>....<newline>``` . To do this I used a regular expression with Sublime Text 3. Pressing CTL+H in Sublime or CTL+R in most other editors should bring up a “Search and Replace” menu. ST3 RegExp engine is greedy by default (on my machine at least) so I was careful to explicitly tell the regexp not match more text than required. The inline code is easy because we no longer need to reference a specific programming language. It’s just search: <span.*?>(.+?)</span> and replace: `$1` .

To replace Crayon blocks of code that use <pre> like <pre class="height-set:true lang:js decode:true">...</pre> I had to use a slightly longer expression in order to include the name of the programming language, as well as include any line breaks. I used search: <pre(?:.*?|lang\:(\w+))?>((.|\n)*?)</pre> and replace: \n```$1\n$2```\n which would wrap the <pre> elements inner content with a newline followed by triple ticks and the programming language name. If you ever get stuck working out a regexp I suggest running tests at Regexr.com.

Setup Disqus and Addthis

The last thing before uploading the new site is to add comments. Since we don’t have a database anymore we need to rely on third party comment systems. This is actually a preferable way to manage comments. If the theme you use doesn’t have comments set up or social sharing then I suggest you setup a Disqus account for comments. Using Disqus keeps your sites comments agnostic of any CMS, meaning that your comments are never tied to WordPress or any other platform but rather just to the ID given to the post. I used Disqus on WP too and I’m sure you can find other options if you want.

Social icons you can have your pick as well, I went with AddThis for 2 reasons. The first is because the theme I started tooling around with already used it and the second reason is that anyone can easily set up social sharing and add it to their site with a single <script> tag. I won’t even go into details on Disqus or AddThis because if you have made it this far then your probably golden pony boy.

After a thorough check that everything works fine, upload your site either in place of your WordPress install, next to it, or on another server and then point your DNS over when your ready to rock! I am serving this site from AWS S3 Buckets and using AWS Route 53 as my DNS now as well. The transfer from 1&1 took about 90 minutes. If you have any questions don’t hesitate to get in touch or leave a comment below.