Unleash Your Dev Blog: Write More with GitHub Issues as Your CMS
Tags: webdev, nextjs, github, blog
Published: 2024-04-02 16:23:44

In this article, I'm going to show you how to leverage Github Issues as a CMS, and integrate it into your Next.js blog 🚀

![GIF](https://github.com/abdulrcs/abdulrahman.id/assets/54136956/dfc35d49-f7c8-4280-8f8c-06fd4502696d)

I recently migrated my [open-source portfolio website](https://github.com/abdulrcs/abdulrahman.id) from using Contentful API as a CMS (Content Management System) to GitHub Issues instead.

> Here's the detailed PR I made in my portfolio repo to migrate Contentful API to use GitHub Issues if you're interested:  [abdulrcs/abdulrahman.id#17](https://github.com/abdulrcs/abdulrahman.id/pull/17)

## Why?

I'm inspired by the blog from swyx.io that uses GitHub issues and comments, as mentioned [here](https://www.swyx.io/github-cms).

The friction of writing a GitHub issue is less daunting than using a fully-fledged CMS like Contentful because you have to log in to their page, navigate to the content section, host the images yourself, etc.

This will (hopefully) lead to more writings in the future 🤞

## How to use the GitHub API
We can use a GitHub API wrapper using [renatorib/github-blog](https://github.com/renatorib/github-blog) to fetch our GitHub Issues.

> Note: GitHub API is limited to 5000 requests/hour, so we need to *statically render the blogs* using `getStaticProps` and `getStaticPaths` to make it scalable, more on that later.

First, [generate the GitHub token here](https://github.com/settings/tokens).

After that, create new labels in your issue named `type:post`, `state:published`, and `state:draft`. 

![image](https://github.com/abdulrcs/abdulrahman.id/assets/54136956/d8dd692b-a244-4549-bd4a-f11a613b306b)

Then, we can create a GitHub issue for our blog post!
Don't forget to add a _front matter_ in the issue to create a _slug_ for our post URL like this:

```md
---
slug: your-slug-title
---
```

![image](https://github.com/abdulrcs/abdulrahman.id/assets/54136956/7eafdac3-deb8-48cf-89fb-d6add3eab169)

## Integrating github-blog to Next.js
### Installing the Library

Install `@rena.to/github-blog` in your Next.js project.

```bash
yarn add @rena.to/github-blog
```
### Fetching Lists of Posts
Here's an example of how to fetch a list of posts statically using `getStaticProps`:
```js
export async function getStaticProps() {
  const blog = new GithubBlog({
    repo: 'your-github-username/your-repo',
    token: process.env.GITHUB_TOKEN,
  })
  const posts = await blog.getPosts({
    query: {
      author: 'your-github-username',
      type: 'post',
      state: 'published',
    },
    pager: { limit: 10, offset: 0 },
  })

  return {
    props: {
      posts: posts.edges,
    },
  }
}
```

### Fetching a Post using Slug
In the `/blog/[slug]` page, you can query the exact post by using the slug:
```js
export async function getStaticProps({ params }) {
  const blog = new GithubBlog({
    repo: 'your-github-username/your-repo',
    token: process.env.GITHUB_TOKEN,
  })
  const data = await blog.getPost({
    query: {
      author: 'your-github-username',
      search: params.slug,
    },
  })
  const metadata = data.post
  const source = metadata.body

  return {
    props: {
      metadata,
      source,
    },
    revalidate: 30,
  }
}
```

### Generating Static Paths for our posts

We need to statically generate our post URL links by fetching all the posts, and mapping each unique slug inside `getStaticPaths`:

```js
export async function getStaticPaths() {
  const blog = new GithubBlog({
    repo: 'your-github-username/your-repo',
    token: process.env.GITHUB_TOKEN,
  })

  const data = await blog.getPosts({
    query: {
      author: 'your-github-username',
      type: 'post',
      state: 'published',
    },
    pager: { limit: 10, offset: 0 },
  })

  return {
    paths: data.edges.map(({ post }) => ({
      params: { slug: post.frontmatter.slug },
    })),
    fallback: false,
  }
}
```

##  Adding Comments Feature

We can use [utteranc.es](https://utteranc.es/), a lightweight comment widget built on GitHub Issues to integrate _authed comments_ in our blog.

![image](https://github.com/abdulrcs/abdulrahman.id/assets/54136956/bd1aebfd-4590-4a65-844f-1fe7c91d29e9)

This is brilliant because in a _Developer Blog_ of course there's a big chance that our audience has a GitHub profile 😆

Since we already integrated the GitHub Issues as our blog, we can add comments to our blog by adding this script to our page:

```html
<script src="https://utteranc.es/client.js"
        repo="[ENTER REPO HERE]"
        issue-term="title"
        theme="github-dark"
        crossorigin="anonymous"
        async>
</script>
```

## That's it!
![MioJimCarreyGIF](https://github.com/abdulrcs/abdulrahman.id/assets/54136956/7b7eb261-d5eb-473b-9fd9-ab27061f6121)

I hope that integrating GitHub issues as the source of your posts will empower you to write more consistently and publish faster 🥳