Blog: Goodbye Jekyll, Hello Gatsby

As of last week, I rewrote this website from Jekyll to Gatsby.

Why?

Previously, my website was built using Jekyll, a static site generator written in Ruby. Since Github Pages can host Jekyll projects automatically without having to build beforehand, this made it very trivial to get this website up and running. Even though I've moved away from it, I would still recommend Jekyll to those who are looking to setup their own static site.

Then why did I switch?

Jekyll is built with Ruby, which isn't the most cooperative of tools to use on Windows. I've switched computers several times in the last two years, and for each of them, I've had to install Ruby and Jekyll for the sole purpose of updating my website. I don't work on any Ruby-related projects either, making it even more cumbersome to have.

On the other hand, Gatsby, along with nearly all of my projects, are written in Node, so all it takes to get started with Gatsby is one npm install.

A small bonus to switching is that I would be working with React again

How it works

Gatsby is a static site generater run with Node. It uses React and GraphQL to handle components and data querying within the website.

Layouts

Jeykll uses frontmatter to specify information about pages, such as their layout, title, date, etc. Each page can have a layout, but layouts can also have layouts as well, resulting in nested layouts that are easy to use.

Gatsby's layout system is different. It has a special layout file that can be placed in /layouts/index.js, which contains a top level (React) component and acts as a default wrapper for all pages. However, compared to Jekyll's system, there are a few drawbacks:

  • Only one layout file can be created. The suggested workaround for multiple layouts is to return a different React component depending on the URL of the page that is being loaded.
  • Instead of React's children object prop, the layout takes in a children function prop which returns the contents of the layout. This means layout components can't be directly used as regular React components without some changes.

Gatsby v2, which is currently in beta, actually fixes this by removing the special layout component. The new suggested workflow is to use regular React components as "layouts." This is a lot more natural to use and is what I've adopted for my website.

This resulted in a layout system that is very similar to what I had with Jekyll. Layouts could be nested and easily pass data between them.

Markdown Pages

My blog posts and project pages are written in Markdown and need to be compiled into HTML. Jekyll handles this automatically, but Gatsby required a few extra steps.

There's a basic tutorial on Gatsby's website that explains how to add markdown pages, but the basic idea is to detect all markdown files in the source folder, and generate each page using a special page template.

These templates are functional React components that accept data passed by Gatsby during the build process. This data can be results from a GraphQL query, or a custom JS object called "context."

However, I also have pages that use the same layouts as those templates. Normally, this would require having the same layout component code in a template file (for Markdown) and in a layout file (for JSX). To avoid code duplication, I moved those templates into layout components so that any page could easily use the layout.

The Lightchain

If you've visited my website before, the lightchain at the top-left of the page shouldn't be a surprise. In the Jekyll website, this was achieved by adding a JS file to all pages that contained jQuery code which dynamically changed some CSS on click. While a similar method could be done by changing the build process to add a custom JS file, I wanted something less janky (also without jQuery).

The main issue was that a click registered in the Lightchain component would need to be propagated into all components that changed if the chain was pulled. This would result in some nasty prop dependencies where the lightchain callback would be passed through basically every component in the website.

My solution was to use Redux. Now, a lightchain click would create an action and pass it the reducer. The store currently consists of just one variable to hold the lightchain state, but this could be extended to add more functionality in the future. Any component that had interactive parts based on the lightchain, such as the home page description, would simply connect to the store and listen to changes.

Page Transitions?

One feature that I didn't get to port over was the page transition animation.

Previously, this was done using a long jQuery script that dynamically replaced the contents of the old page with the contents of the new one while fading in between. It also added the previous page to the browser history, and also transitioned going backwards and forwards. While changing the content, the content box resized its height to fit the incoming content. To get the accurate height, it waited for all images in the new content to load before getting the new height. Otherwise, the height wouldn't take into account for any non-cached images and would end up a bit short.

I'm not entirely sure how to mimic this effect in Gatsby, so this will be left out for now.