← Blog

GitHub as a minimal CMS for my blog

#GitHub #trick

I just moved all my blog source materials, i.e. markdown files and images, to a separate GitHub repository. Now, instead of the blog markdown files stored in /src/blog/1 of the website source repository, they need to be fetched via GitHub’s API when building the site.

Why do this

First, less distraction.

I noticed that whenever I opened my blog project in VS Code, I got easily distracted by other parts of the site source code and ended up spending more time on tweaking the site rather than working on a new blog post. The original goal for building my personal site and blog was indeed to get my hands dirty with React,2 so anything that gave me an opportunity to work with a React codebase was a positive.

Now that I get paid to write React code, this is no longer the case. And that’s fine. Time has changed, so I adapt. Now I just want to type out some words whenever I have something to write. Without distraction. To that end, using a separate git repository seems like an option worth exploring. This also has benefit of isolating the history of my writing from that of the rest of the source code.

Second, ease of migration.

This might be somewhat contradictory to the point I just laid out (i.e. “I want to focus on writing”) because this time I’m saying I want to make it easier to try alternative approaches to building my website and blog. Well, what can I say? I’m only a human and my human mind is fully capable of holding contradictory beliefs.

Again, the original motivation for this website and blog was to practice React while building something useful for myself. While I now get a plenty of practice in writing React code at work, I also acknowledge that the frontend web development landscape has evolved ever since. And, as I discussed in a past post, I expect metaframeworks to lead this evolution for the foreseeable future.3 I want to explore this space more by using this website and blog as a simple use case.

Third, just for fun.

Getting into web development certainly turned me into a tinkerer of sorts. And playing with a small, existing project is a good fun. Sure, it doesn’t always help me to grow in skills and knowledge, but at the moment I don’t feel prepared to start something completely different and/or complex for its own sake, or even learning. Maybe one day, maybe.

How this works

The first step is, of course, creating a new GitHub repository with all the blog source materials.

Once that’s done, I have a few options. On one end of the spectrum, I can go full SPA with a dynamic route generated on runtime for each blog post, all handled by the client. On the other end, I can fetch and write the source materials so that the files are ready to be consumed by the static site generating process. And there are some other options in the middle, including Incremental Static Regeneration by Next.js.

I am starting with the path of least resistance, i.e. simply writing the fetched files to the paths that they used to be. This way, I don’t need to modify any existing code for my Gatsby site. I just need to write some new code to implement this new setup. This new code includes some helper functions to fetch and write blog source files from GitHub, which I then call using Gatsby’s onPreBootstrap lifecycle API to make these files available to Gatsby before it starts generating pages for blog contents.

Then there is a build hook for the Netlify site that is triggered whenever I push to the main branch of the blog source materials repository. This triggering is handled by a simple GitHub Actions job. Of course, I want to keep the build hook URL to myself, so I store it as a repository secret, which is conveniently accessible to the GitHub Actions job.

This way, I can make sure that my Gatsby site deployed on Netlify stays up to date when I make changes to the blog source materials.

What’s missing

One of the most notable regressions with the current setup is that I cannot see the rendered output in real time, which leads to a very poor workflow. One way to address this is to use Netlify’s “branch deploy” feature with a draft branch. However, this is still suboptimal as I cannot see the rendered output in real time as I’m writing that draft. Alternatively, I can have the Gatsby site dev server running locally and copy over the draft to it to see how the rendered output looks like. This has the advantage of keeping the whole drafting process local, but still involves juggling two projects at the same time.

Another downside of this setup is that the deployed site has to rebuild every time. This is not really a regression since the previous, unbundled setup had this issue as well. I recently started using Gatsby’s “conditional page builds” to reduce the wasted build time.4 This helps, but there are still many opportunities for further optimization.

What’s next

As I mentioned earlier, I intend to use this decoupling of website/blog app and the blog source materials as an opportunity to explore different frameworks and metaframeworks. Right now, the first on my list is Next.js, which recently made some splash with its v10 release. Plus, Netlify has been embracing Next.js with great enthusiasm, as evidenced by many recent posts on its official blog about Next.js. When SveltKit gets released, I might want to try that as well.

And, of course, (hopefully) now with less distraction, I really should write more frequently for this blog. 🤞

Footnotes

  1. Images were living under /static folder, whose contents would be simply copied over to the generated /public folder and thus could be easily hyperlinked from the blog post.

  2. I could have done this with some to-do apps, but building something that actually serves my needs felt much more interesting. What’s the point of technology if not that, anyways?

  3. Also, the space for build tools is getting heated up: from the recent release of snowpack v3 (RC), to WMR from the Preact team, to Vite by Even You of Vue.js. Definitely something to pay attention to!

  4. On Netlify, this requires a plugin to keep the Gatsby’s cache between builds.