Website rebuild with Eleventy (11ty), Tailwind CSS, and GitHub Issues as CMS
• • #jamstack
I rebuilt my website, so it's time for yet another "How I built my blog" post.
TLDR: The site is built with Eleventy and Tailwind CSS, and GitHub Issues are used to store the blog posts.
This is what I used to build the current version of the website:
- 11ty as static site generator
- Tailwind CSS for styling
- Nunjucks as the template language
- Markdown to write the blog posts
- GitHub for hosting the code
- GitHub Issues as CMS
- GitHub Actions to trigger build hooks
- Netlify for deployment
- Plausible for privacy-friendly analytics
- And also, lots of coffee ☕
Perfomance
#Not for all blog posts, but in general, the Lighthouse score is pretty good😊.
Why Eleventy?
#Eleventy calls itself "a simpler static site generator" on its website. And it is indeed simple and straightforward. One thing I really like about it is that I could easily understand what's going on under the hood and how I can achieve certain steps. This made development a breeze, especially combined with Tailwind CSS for styling.
GitHub Issues CMS
#All posts are stored as GitHub Issues (in Markdown format), then the GitHub API is used to fetch all issues, and then Eleventy builds the site with all posts.
Thank you to Swyx for this idea.
What's cool about using GitHub Issues as CMS:
- It's free
- Easy and fast to update
- Easily store images - You can attach files by dragging & dropping, selecting, or even pasting from the clipboard.
- Editable from mobile
- Publishing/Unpublishing articles is simply done by adding a label called "published"
- Not implemented here but Issue comments & reactions (👍🎉🚀) can be used as a commenting system
With this short snippet, we can then fetch all issues with the label "published" from GitHub:
const { Octokit } = require("@octokit/rest");
const octokit = new Octokit({
auth: process.env.GITHUB_TOKEN,
});
async function getIssues() {
const { data } = await octokit.issues.listForRepo({
owner: GITHUB_REPOSITORY_OWNER,
repo: GITHUB_REPOSITORY_NAME,
labels: "published",
per_page: 100,
state: "all"
});
// TODO: add pagination for > 100 posts
return data;
}
GitHub Actions to trigger build hook
#Netlify creates a new build whenever the main branch is updated. But we can also create a new build whenever we edit an Issue by using a GitHub Action. Since I'm using Netlify for deployment, all I have to do is send a post request to the Netlify build hook.
(If you don't have the option with a build hook, you could also use an Action to create a new empty commit to trigger a new build.)
What's really cool is that GitHub Actions can be used to run whenever issues are opened, edited, deleted, labeled, or unlabeled. So every time I make an edit, the new site is live just a few seconds later.
This is what my .github/workflows/ci.yml
file looks like. Notice the if-statement to skip this Action when I edit an unpublished post:
# Trigger Netlify build hook when GitHub issues change
name: Issue Trigger
on:
issues:
types: [opened, edited, deleted, labeled, unlabeled]
jobs:
trigger-netlify-build:
# Run if type is either deleted/labeled/unlabeled, or if opened/edited and it is published (we have 1 label)
# No need to run if edited/opened and not yet published
if: (github.event.action != 'edited' && github.event.action != 'opened') || github.event.issue.labels[0] != null
runs-on: ubuntu-latest
steps:
- name: REST API with curl
env:
NETLIFY_BUILD_HOOK: ${{ secrets.NETLIFY_BUILD_HOOK }}
run: |
curl -X POST -d '{}' "$NETLIFY_BUILD_HOOK"
Resources and Credits
#- Bryan Robinson - Mix markdown and data into one collection with 11ty: Extremely helpful article about combining API data with data from markdown files.
- Swyx - Moving to a GitHub CMS: This is where I got the idea of using GitHub Issues as CMS.
- Jason Etcovitch - Personal blog with 11ty: I took design inspiration and parts of the code from this site.
Starter Repos with a GitHub CMS
#Currently, my site is not Open Source, since Swyx mentioned there can be SEO problems because the content will be duplicated across the GitHub issue and the blog. But maybe I'll release a separate starter template in the future.
Other Starter Repos you can use:
- sw-yx/swyxkit: SvelteKit + Tailwind + GitHub Issues
- djyde/sairin: Next.JS + GitHub Issues
- NickColley/website-from-github-issues: Eleventy + GitHub Issues
- renatorib/github-blog: Optional helper package to work with the GitHub API as CMS
Hope you enjoyed the read!
▶ Follow me on
Twitter
&
LinkedIn
▶ Tutorials on
YouTube
▶ Dev Advocate at
AssemblyAI
▶ Founder of
python-engineer.com