How I build my Astro blog using GitHub Discussions
Join me in my experiment to build an Astro blog where we host blog content on GitHub, but without using Git to push and commit Markdown as regular files, but instead we'll be using GitHub Discussions as CMS for our Markdown content and then eventually using GitHub API to retrieve the content.
On May 6, 2023 — 8 min read
AstroMarkdownGitHubVercel
Intro
So I’ve been trying to finish my blog for some time now, finally was able to. I wanted it to be up and running in a quick time and also, to be easily maintainable.
I chose Astro as it’s the best fit for the job, with its great Markdown support, but one thing I didn’t like was having both content and codebase on the same repository..
I come across some articles talking about making GitHub as CMS, saw some boilerplates around this idea and I wanted to have a go, but it wasn’t easy..
How to manage content
One great feature I liked about astro is their ContentCollection, where you create and manage your own types of collection, collection here means a folder with some Markdown files, more on that here.
But the problem with Astro now, is that it does not support fetching remote Markdown files and at the same time, benefit from ContentCollection, we need to have the Markdown files locally in order to be considered a ContentCollection..
So the TLDR of this article, is to fetch Markdown from a remote place, which in our case from GitHub (perfect way to host your Markdown content, more on that later on) and then save the fetched Markdown content as files locally, all of this needs to happen on build time..
GitHub Discussion
Currently I found two ways to build CMS on GitHub, either using issues or discussions, what I was familiar with was using issues, I saw it being used on a lot for blogs, but I also found GitHub discussions to be a better choice, first we’ll talk about the setup and then the fetch script using GitHub API.
Setup
So here are the things I did to setup the blog in GitHub discussion:
Enabled discussion feature in my repository.
Deleted all default labels.
Deleted all default categories and sections.
Created new section named “Articles”.
Created two new categories with type “Announcement”, named “Released” and “Drafts” respective to release and draft posts. in this case “Announcement” type categories prevents non maintainers from posting new discussions under this category.
Now we need to know the format of the Markdown files we want to save locally, so we create a new ContentCollection:
Now we need to understand how to map discussion settings to the Markdown format above, so we have the following field and their mapping in GitHub Discussions:
title: the title of the discussion, easy!
subtitle (this will only be used in the post OG image): a frontmatter field.
lede: a frontmatter field.
tags: assigned GitHub labels of the discussion.
created_at: date of creation of the discussion.
updated_at: date of the update of the discussion.
draft: whether or not such discussion is in the “Drafts” category.
picked: whether or not such discussion is pinned in the GitHub discussions page.
featured: here I created a special tag, named “@featured”
A few points worth mentioning here:
only one post can be featured at a time.
only maximum of 3 picked posts at a time.
as for the “frontmatter” fields, here’s an example:
Fetch script
Now for the fetching part, I had to add and extra build step for Astro, and here’s how it goes:
For the script, I created a new file under /scripts/fetch-discussions.mjs:
Now to elaborate further on the fetchDiscussions() function:
Now the final part:
Now, when we run the command below, our discussions will turn into a blog posts, they will be saved under /src/content/blog/*
Hosting (Vercel)
Finally, we need to change the build command for our hosting provider, in our case, nothing comes close to “Vercel”, we head down to the settings page of our project, then to the “Build & Development Settings”, and we override the default build command:
Continuous deployment
Now the cherry on top, is to have our posts automatically built & deployment, so I used GitHub Actions to trigger Vercel deployment manually on each discussion change event, so I created two workflow files, one for preview & production deployment on vercel, this is an example of the preview.yml:
Caveats & Problems
New, we’ll talk about some problems we have with this approach,
Slug problem
As we see in the fetch code above, we’re creating slug from the title of the discussion, but the problem is that, the title is changeable, so does the slug, which is very bad for SEO, we want the post to always have the same slug and the same URL.
Publish date
Problem here is that the publish date of the post, is not changeable, it’s always tied to the created_at date of the discussion, but it’s not huge problem, I can live with that.
GitHub Action trigger
With GitHub Actions, I was not able to limit discussions event triggers to a certain discussions categories (Drafts & Release, in my case), meaning for every discussion’s change, it will will trigger a new run, but because the runs does not exceedingly take a lot of time (12s tops), it’s alright.
Future improvements
Here are some things that I’m planning to work on next:
Fix issue with posts’ slug and urls after changing the title, probably use some kind of a KV store, to save the first generated post slug?
Incremental Static Regeneration (ISR) with Astro, to only build newer / changed posts?
If you made it this far, thank you for reading, I hope you find it useful,