2021 update: in the time since this blog post was first published in 2017, I've rewritten my blog twice! Once in Vuex and then again in Gatsby. That said, I'm keeping this post available for historical purposes.
Recently, I’ve had a desire to start blogging again to aid with reflection as I work on projects. It’s a hobby I’ve explored since my exposure to the internet over a decade ago, and I’ve always considered myself a casual blogger. In the past, I’ve used platforms like WordPress and Blogger for blogs about my projects. This time, I’ve been compelled to start branding my own name and taking ownership of my internet presence. To this end, I wanted to build a blog for myself so I’d have full control and ownership of both the written content and the supporting code of my blog. Originally, I was looking into writing my own blogging platform in React, but I didn't want to reinvent the wheel.
If you’re not familiar with templating frameworks, they are able to generate HTML markup via various templating languages. For this theme I used EJS (Embedded JavaScript). Templating means you can write a portion of your site (like a header or a footer) only once, and reuse the same code in multiple parts of your website. This creates a static site that can be easily extended and modified without having to make duplicate changes.
At first I considered a generator like Jekyll, but I really wanted to work on a project in JavaScript. There was a JS port named Heckle, but it wasn’t complete and I didn’t want to pick up an incomplete framework for my new blog. Ultimately, I picked Hexo as the platform on which to build my new blog. There were a few major points that made it an easy choice for me:
Pros
- Markdown support for easy and consistent post styles
- Generates files very quickly
- Very extensible via plugins
- Highly customizable via themes
- Customizable URLs for SEO optimization
- Built in JavaScript, my language of choice
Hexo isn’t perfect, however. There are some things about it which weren’t apparent at first, but surfaced later as annoyances:
Cons
- Spotty documentation that’s missing important instructions
- No built-in HTML beautification means EJS templates structured for JS readability create ugly HTML markup
- Small developer community
Starting out
I wanted to build a theme in Bootstrap 4 that was mobile responsive, SEO-friendly, and full of delicious meta and schema data for search engines. My inspiration was the official Bootstrap 4 blog example template and my goal was to include all of the same functionality in my new custom theme. I didn’t want to copy the theme or have a default Bootstrap look, however, so the final result would be styled for my personal blog.
Unfortunately, the documentation for Hexo is spotty at best and is misleading at worst. In the beginning, there was one step back for every two forward. After some research, I learned how to correctly build a “skeleton” on which the rest of the layout can depend. The result was the layout.ejs file which contains the main site layout used on every page. Site-wide markup like head content and footer scripts are pulled from partials to construct the frame of the site here. If I needed to update scripts or styles, I could make a single change in one place and see it reflected everywhere.
Hexo supports different post types, but almost everything can be boiled down to either an archive or an article. The tag.ejs and category.ejs layouts are essentially archived lists of specific tags and categories, so they use the same _partial/archive.ejs partial as archive.ejs to display their contents. _partial/archive.ejs itself is able to index content sorted by categories, tags, and dates so it can serve up any archive-like list needed for the blog. In my personal implementation, these archive lists are included in the sitemap for better indexing. 2021 update: upon further reflection, I basically implemented components in Hexo, hehe!
Schema, OG, and metadata
Once archiving and listing content was handled, I was able to focus on building the actual structure of the blog posts. I had full control over the HTML structure that would house each of my blog posts. This allowed me to be incredibly lean for a fast load time while also packing in schema data from Schema.org. Each post generates the correct schema tags to pass all of the tests on the Schema Markup Validator. This results in better indexing and understanding of the website by web crawlers.
Every blogger wants their posts to be shared, so my next focus was adding the Open Graph (OG) Protocol to each page. If you’re not familiar with OG, it’s an assortment of meta tags that pass information to social media networks like Facebook and LinkedIn so they know how to display the article’s image, title, and description when shared on the social network. Hexo comes with an OG helper, but it left much to be desired. To that end, I wrote a new Meta Maker helper for this theme that pulls metadata from the page and the site’s _config.yml files to generate proper tags for each page. It also handles the other important SEO tags like rel=canonical and generates the sharing meta tags for Twitter (which doesn’t use OG).
This one script was immediately very useful to me and I’ve since used it on other Hexo projects. In the future, I’m considering expanding its functionality and creating a plugin with additional features, like something akin to Yoast SEO but for Hexo.
Finishing the design
As mentioned on the list of cons above, an issue I immediately encountered was producing human-friendly HTML markup. This didn't cause any performance issues, but due to how the site was maintained in separate files it was very difficult to discern bugs. Because I was designing this theme as a web design and SEO project, it was important to me that the finished result looked beautiful to both the machine and the human. I also wanted to feel encouraged extending any partial if needed, and human-readable markup would assist in troubleshooting new features. If I structured my EJS templates to look good in EJS, they produced poorly formatted HTML. When I purposefully structured the EJS for beautiful HTML, I still sometimes encountered issues with paragraph tabbing and extra line breaks. This has been discussed before in the context of EJS, so at least I’m not alone with this issue. In the future, I’d probably use a tool like htmltidy to clean up the files after rendering. If I did so, the EJS files could be properly structured for JavaScript readability while still producing human-readable HTML markup.
Once again, this is a non-issue if you don’t care about the readability of your files, but a goal in this project was producing an incredibly easy-to-use and accessible theme. It was tedious to structure the EJS for ideal HTML in this way, but I learned a lot about EJS in the process.
I wanted the actual design to use similar colors as the rest of my website, which is violet and pink. My site was designed before Pantone’s 2018 Color of the Year was picked, and seeing Ultra Violet get featured made it an easy decision to keep using the color and those that complement it (like charcoal gray). 2021 update: while I stand by my original color choices, I've since changed the website to use shades of blue.
Final thoughts
Ultimately, creating the Space Cadet theme taught me a lot about blog design and using a templating framework like Hexo. Prior to this project, I was leaning more heavily toward server-based solutions for blogging and was even considering building my own platform with React. However, Hexo has shown me the power of static site generators. I’ve since ported the rest of my personal website to Hexo as well. Because everything on this domain is hosted on Google Firebase, using a static solution is very easy! 2021 update: my website doesn't use Hexo anymore and now runs on Netlify! I would encourage others looking for simple templating tools to try out Hexo. With libraries of plugins and themes available, it’s easy to get started with little technical knowledge.
Check out the link below to download the Space Cadet theme for your own Hexo blog and use it under the MIT license: