From Jekyll to Gatsby: 7 Simple Steps
2020-09-16Six years ago, during my final year in college, I was enrolled in a course on Open Source technology. To pass the course was to do two things: contribute to an open source project, and blog about it. Laughably, the only thing that propelled me to start writing publicly was the fear of failing the class.
I passed the course and managed to get some semblance of a blog together. However, I didn't put too much effort into building the site itself since much of my effort was expended in writing the content and trying to creep my way into open source. At the time, Jekyll was all the rage and I went with a themed Jekyll starter called Lanyon.
It served me well over the years, but my unfamiliarity with how it worked kept me from making any substantial changes to the structure of the site. I've finally taken the stand to move to a stack I'm more comfortable with.
Why Gatsby?
I considered refurbishing my blog with Gatsby and Next. I decided to go with Gatsby since it is a little more specialized towards static site generation.
Let's Get Migrating
Scaffolding
Getting a Gatsby project up and running is well-documented on the Gatsby site. Enhancing the project to generate a page from a markdown file is also clearly explained. These are the steps I followed to get the initial project set up for the blog:
- Used the
gatsby-source-filesystem
plugin to read markdown files into Gatsby. I added an entry to theplugins
key ingatsby.config.js
.
plugins: [{
resolve: `gatsby-source-filesystem`,
options: {
name: `markdown-pages`,
path: `${__dirname}/src/markdown-pages`
}
}]
- Parsed markdown files using the
gatsby-transformer-remark
plugin which extracted the frontmatter as data and the content as HTML.
plugins: [
{
resolve: `gatsby-source-filesystem`,
options: {
name: `markdown-pages`,
path: `${__dirname}/src/markdown-pages`
},
},
`gatsby-transformer-remark`
]
- Created a template for blog posts using React to render a blog post's data as a React component.
- Generated pages for all markdown files using the
createPage
Gatsby API. - Created an index page for all blog articles that displayed a list of links.
Migrating Content
I copied all the markdown files from my old website to the folder indicated in the gatsby-source-filesystem
config entry: markdown-pages
. I was now able to see all my old blogs being listed on the index page, but most of the posts themselves looked terribly broken.
Fixing All the Things
Links
To avoid breaking links, I used the same slug format that my old Jekyll site used: YYYY/MM/DD/Title
. In my case, the slug was derived from the filename instead of the frontmatter, which required a little special handling.
- To access the filename, I used createFilePath.
- I extracted the slug and the date from the filename and passed them along as node fields, available to subsequent page queries.
const result = extractMetadataFromFilename(filePath);
date = result.date;
slug = result.slug;
createNodeField({ node, name: `date`, value: date });
Highlighting
In my old Jekyll site, I was using pygments
for syntax highlighting of code snippets, which used syntax like this to create a highlight:
{% highlight C++ %}
{% raw %}
void f(int x, int n)
{
Gadget * g = new Gadget{n}; // Look ! I’m a Java Programmer :)
if(x < 100) throw std::runtime_error{"weird"}; //leak
if(x < 200) return; //leak
delete p;
}
{% endraw %}
{% endhighlight %}
Since this no longer worked in Gatsby, I changed all highlights to be enclosed in three back-quotes which translates to a <pre>
tag enclosing a <code>
blog.
I would like to eventually embed gists directly into my posts, but that's an improvement for a later blog post.
Images
First, I copied over the images from my old site to src/images
. To make Gatsby aware of where my images were located, I added another plugin entry for the gatsby-source-filesystem
plugin.
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/src/images`,
},
}
I then modified the plugin entry for gatsby-trasformer-remark
to add the gatsby-remark-images
plugin to it.
{
resolve: `gatsby-transformer-remark`,
options: {
plugins: [
{
resolve: `gatsby-remark-images`,
options: {
maxWidth: 800,
},
},
],
},
}
With this configuration, I was able to embed images inline using the familiar markdown format:
![Architecture](../images/NN.jpg)
It's important to use a relative path to the images
folder.
- src
- markdown-pages
- images
For the directory structure above, ../images/image.png
would be the path to an image referenced in a markdown file.
Gifs
gatsby-remark-images
cannot handle gifs. I added the gatsby-remark-copy-linked-files
plugin to properly handle any gifs that gatsby encountered.
{
resolve: `gatsby-transformer-remark`,
options: {
plugins: [
{
resolve: `gatsby-remark-images`,
options: {
maxWidth: 800,
},
},
`gatsby-remark-copy-linked-files`
],
},
}
Favicon
Again, I invoked the mighty plugin system of Gatsby and added another plugin entry in gatsby-config.js
.
{
resolve: `gatsby-plugin-favicon`,
options: {
logo: `./src/favicon.ico`
}
}
Styling
I lazily copied over the poole/lanyon theme to avoid me having to write any CSS. Let's not kid ourselves, I don't really know how to design a site.
Since these are global CSS styles, I needed to import them into the gatsby-browser.config.js
file to make them apply to the generated HTML files.
import './src/styles/poole.css';
import './src/styles/lanyon.css';
import './src/styles/Calendas_Plus.otf';
Deploying
To test the site out and compare it with my old site, I deployed the site to Netlify. It was about as simple as going to the Netlify site, authorizing access to my GitHub repo, and providing a build command.
Testing that No Links are Broken
With my site deployed to Netlify, I tested that no links would be broken by ensuring that each link on the old site also existed on the new site:
links.forEach(link => {
link = link.replace('deborah-digges.github.io', 'epic-mirzakhani-8e39a6.netlify.app');
request(link, (err, res, body) => {
if (err) { console.log('Page fetch failed', err); }
console.log(link, res.statusCode);
});
});
I ran the following script on each of the two pages of my old blog to extract all the links:
let links = document.querySelectorAll('a');
let siteLinks = []
for (let i=0; i < links.length; i++) {
let linkText = links[i].textContent;
linkText = linkText.replace(/\s+/g, ' ').trim();
const link = links[i].href;
siteLinks.push([linkText, link]);
}
for(let i=0; i < siteLinks.length; i++) {
console.log(siteLinks[i][1]);
}
Admittedly, it's a little rudimentary, but hey! it did the job.
Switching over
Once I was ready to bid adieu to the shackles of my Jekyll site, I overwrote my Github User Pages repository with the shiny new Gatsby site. I will be going over the details of deploying a Gatsby site to GitHub Pages in a subsequent blog post!
Next Up
Now that I'm using a system I understand a little better, I want to soon:
- Implement pagination
- Create categories for pages and allow browsing the blog by category
- Create a navigation element called
Content
in the header which expands toBlogs
,Drawings
,Book Reviews
- Create a
Reading List
navigation element - Lean enough about CSS and design to create a better landing page (Maybe hire a designer?)
If you'd like to check it out in more detail, you can find the source code here.
Tune in again for more exciting updates to my Gatsby blog!