Using Hashnode as a Source for Gatsby

Alex Hyett - Nov 6 '21 - - Dev Community

I have done quite a few website migrations over the years. My blog like many first started out on WordPress. After several attempts at optimisation, I ended up generating a static version of my WordPress website.

On my static site generation journey, I discovered Gatsby.js and completely redesigned my website around it. However, writing posts locally in markdown has its own downsides and lacks the discoverability you get from blogging on Hashnode.

So I decided to move my blog posts over to Hashnode but I still wanted my posts to appear on my main blog.

Migrating the Blog Posts

The first step was to import all my blog posts to Hashnode. There are a few methods you can use to import your blog posts.

Hashnode import methods

I decided to use the Dev.to importer as I repost all my posts on dev.to anyway. Unfortunately, the bulk import didn’t work for me so I had to import my posts one at a time.

This was handy though as you need to set the following for each post manually:

  • Post slug
  • Tags
  • Canonical URL

Once all my posts were imported it was time to edit my Gatsby website to start pulling down the posts.

Gatsby plugins

If you do a search for gatsby-source-hashnode you will find a couple of plugins on the Gatsby website.

I decided to go with the first one (gatsby-source-hashnode) as it has a lot more downloads and still appears to be maintained.

However, I quickly noticed when testing out the plugin that it was only pulling down the first 6 posts from my Hashnode blog. This might be a recent change to the API which hasn’t yet been picked up by the plugins.

Luckily, the plugin is open source so I raised a PR for the plugin owner to review.

In the meantime, I copied my modified code to a folder in my gatsby repository called plugins/gatsby-source-hashnode. I then used the plugin as described in the documentation.

GraphQL queries

I am using GraphQL queries in a few places to pull down posts:

  • Blog Feed
  • Blog Post
  • Latest Posts
  • RSS Feed

For reference, this is what a couple of my queries look like for pulling from Hashnode.

Blog Feed

query pageQuery($skip: Int!, $limit: Int!) {
    site {
      siteMetadata {
        title
        description
      }
    }
    allHashNodePost(
      sort: { fields: [dateAdded], order: DESC }
      limit: $limit
      skip: $skip
    ) {
      edges {
        node {
          brief
          slug
          title
          coverImage {
            childImageSharp {
              gatsbyImageData(
                width: 920
                height: 483
                layout: CONSTRAINED
                transformOptions: {cropFocus: CENTER}
              )
            }
          }
        }
      }
    }
  }
Enter fullscreen mode Exit fullscreen mode

Blog Post

query BlogPostBySlug($slug: String!) {
    site {
      siteMetadata {
        title
        author
        siteUrl
      }
    }
    hashNodePost(slug: { eq: $slug }) {
      _id
      brief
      childMarkdownRemark {
        htmlAst
      }
      slug
      title
      dateAdded
      coverImage {
        publicURL
        childImageSharp {
          gatsbyImageData(
            width: 920
            height: 483
            layout: CONSTRAINED
            transformOptions: {cropFocus: CENTER}
          )
        }
      }
    }
  }
Enter fullscreen mode Exit fullscreen mode

I am not yet pulling down tags or reading time from the API. That is something I will try out later.

Automation with GitHub actions

I already have GitHub actions set up for my website so that any new commits to the main branch trigger a website build and push to S3. I wrote a post about it if you want to find out how.

However, now that I am not committing articles to that repo I needed a way to automatically trigger builds when I publish a new post on Hashnode.

Luckily, Hashnode has an option to backup your blog posts to GitHub which we can use as the trigger point.

Step 1: Add workflow_dispatch to your GitHub action

To be able to remotely trigger a build on GitHub you need to add workflow_dispatch to the on: section of your workflow file.

This is what the top of mine looks like:

name: Deploy Blog

on:
  workflow_dispatch:
  push:
    branches:
      - main
Enter fullscreen mode Exit fullscreen mode

Step 2: Create a personal access token

Next, we need to create a personal access token that we will use as the API Key for triggering the remote build.

You can do this in GitHub under Settings > Developer Settings > Personal Access Tokens

I set my access token with the following permissions.

GitHub Access

You will need to set an expiry date as well and set yourself a reminder to generate a new token before it expires.

Make sure you copy the access key as you won’t get a chance again!

Step 3: Add the key as a secret to your backup repository

To be able to use this access key we need to add it as a secret to the repository where Hashnode is backing up your posts.

On the backup repository go to Settings > Secrets and add a new repository secret called ACCESS_TOKEN and put in the key from the previous step.

Step 4: Add a workflow file

Next, we need to add a workflow that gets triggered every time a commit is added to this repository. In our case, this will be whenever we publish a post on Hashnode (Note: Drafts aren’t saved in GitHub).

Add the following file to your backup repository .github/workflows/workflow.yml

---
name: Trigger Deploy

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - run: |
          curl -X POST \
          -H "Authorization: Bearer ${{secrets.ACCESS_TOKEN}}" \
          -H "Accept: application/vnd.github.v3+json" \
          https://api.github.com/repos/GITHUB_USERNAME/WEBSITE_REPO/actions/workflows/workflow.yml/dispatches \
          -d '{"ref": "main"}'
Enter fullscreen mode Exit fullscreen mode

Make sure you change GITHUB_USERNAME to match your GitHub username, WEBSITE_REPO to the repository with your Gatsby.js website and workflow.yml to match the name of your deploy workflow file.

To test, try updating one of your posts in Hashnode and you see this workflow get triggered then followed by your website workflow.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .