Switching to GatsbyJS

Switching to GatsbyJS

Why?

So recently I decided that it could be therapeutic to get into blogging again. However I was not happy with my custom made “blogging” platform. It was ASP.NET core based using Markdown files for the blog posts. The design was yieks too.
That’s why I went to Theme Forest and came across StoryHub - React/Gatsby based template.

Even though my main forte is not the modern JavaScript, I decided to give it a try. Also the theme looks excatly like what I want for a personal website.

RTFM

My first mistake was not reading the Gatsby docs and jumping straight to the modifying the code.
While the theme was pretty nicely coded I one requirement - having different collections of post. What I needed was a way to separate my blog posts from my Monster Hunter transmogs.

React, GraphQL, Nodes and stuff

To this day I still could not get into the JSX syntax. It looks kinda dirty to mix JavaScript and html. I think that Vue.js templating better through their template syntax.

But… I like how the theme authors had used Emotion which will make customization of the theme prety neat. Also the composition of the compontents is bearable. As an example my collections list page looks like this:

const BlogList = (props: any) => {
  const { data } = props
  const collection = props.pageContext.collection
  const Posts = data.allMarkdownRemark.edges.filter(
    entry => entry.node.fields.collection == collection.name
  )
  const { currentPage, numPages } = props.pageContext
  const isFirst = currentPage === 1
  const isLast = currentPage === numPages
  const prevPage =
    currentPage - 1 === 1
      ? `/${collection.name}`
      : `/page/${(currentPage - 1).toString()}`
  const nextPage = `/${collection.name}/page/${(currentPage + 1).toString()}`
  const PrevLink = !isFirst && prevPage
  const NextLink = !isLast && nextPage
  return (
    <Layout>
      <SEO title={`${capitalize(collection.name)} - Page ${currentPage}`} />

      <BlogPostsWrapper>
        {Posts.map(({ node }: any) => {
          const slug =
            collection != null
              ? `/${collection.name}${node.fields.slug}`
              : node.fields.slug
          return (
            <PostCardMinimal
              key={node.fields.slug}
              title={node.frontmatter.title || node.fields.slug}
              image={
                node.frontmatter.cover == null
                  ? null
                  : node.frontmatter.cover.childImageSharp.fluid
              }
              url={slug}
              description={node.frontmatter.description || node.excerpt}
              date={node.frontmatter.date}
              tags={node.frontmatter.tags}
              collection={collection.name}
            />
          )
        })}

        <Pagination
          prevLink={PrevLink}
          nextLink={NextLink}
          currentPage={`${currentPage}`}
          totalPage={`${numPages}`}
        />
      </BlogPostsWrapper>
    </Layout>
  )
}
export const BlogPostsWrapper = styled.div`
  margin: 0 auto;
  padding-top: 120px;
  position: relative;

  @media (min-width: 990px) {
    width: 900px;
  }
  @media (min-width: 1200px) {
    width: 1050px;
  }
  @media (min-width: 1400px) {
    width: 1170px;
  }
  @media (max-width: 990px) {
    padding: 80px 45px 0 45px;
  }
  @media (max-width: 575px) {
    padding: 60px 25px 0 25px;
  }

  .post_card {
    margin-bottom: 120px;
    @media (max-width: 990px) {
      margin-bottom: 90px;
    }
    @media (max-width: 575px) {
      margin-bottom: 60px;
    }
  }
`

This is something that I am fine with (kinda).

Using GraphQL was also a bit of a challenge.

For the different collections I made two folders in the content folder containing my posts in Markdown Format:

  • blog
  • transmogs

Adding them to Gatsby was as easy as

// gatsby-config.js
{
    resolve: `gatsby-source-filesystem`,
    options: {
    path: `${__dirname}/content/blog`,
    name: `blog`,
    },
},
{
    resolve: `gatsby-source-filesystem`,
    options: {
    path: `${__dirname}/content/transmogs`,
    name: `transmogs`,
    },
},

I fiqured out that if I add the following code (or simply put Google helped) would add collection to the node graph for markdown posts in GraphQL.

// gatsby-node.js
exports.onCreateNode = ({ node, actions, getNode }) => {
  const { createNodeField } = actions

  /** ... **/

  if (node.internal.type === `MarkdownRemark`) {
    const value = createFilePath({ node, getNode })

    const parent = getNode(_.get(node, 'parent'))

    createNodeField({
      node,
      name: 'collection',
      value: _.get(parent, 'sourceInstanceName'),
    })
  }

  /** ... **/
}

I also have an array with collections which I loop through and set the collection in the context of the generate page so it can be used by the components and GraphQL queries down the line.

// gatsby-node.js
const siteCollections = [
  {
    name: 'blog',
  },
  {
    name: 'transmogs',
  },
]

/* ... */

// Create blog post list pages
const postsPerPage = 4
const numPages = Math.ceil(entries.length / postsPerPage)

Array.from({ length: numPages }).forEach((_, i) => {
  createPage({
    path: `/${collection.name}` + (i === 0 ? `/` : `/page/${i + 1}`),
    component: blogList,
    context: {
      limit: postsPerPage,
      skip: i * postsPerPage,
      numPages,
      currentPage: i + 1,
      collection: collection,
      collectionName: collection.name,
    },
  })
})

/* ... */

So now my “blog-list” query looks like this:

export const pageQuery = graphql`
  query($skip: Int!, $limit: Int!, $collectionName: String!) {
    site {
      siteMetadata {
        title
      }
    }
    sitePage {
      path
    }
    allMarkdownRemark(
      sort: { fields: [frontmatter___date], order: DESC }
      limit: $limit
      skip: $skip
      filter: { fields: { collection: { eq: $collectionName } } }
    ) {
      edges {
        node {
          excerpt(pruneLength: 300)
          fields {
            slug
            collection
          }
          frontmatter {
            date(formatString: "DD [<span>] MMMM [</span>]")
            title
            description
            tags
            cover {
              childImageSharp {
                fluid(maxWidth: 170, maxHeight: 170, quality: 90) {
                  ...GatsbyImageSharpFluid_withWebp_tracedSVG
                }
              }
            }
          }
        }
      }
    }
  }
`

Then my posts query is the blog list is as simple as

const Posts = data.allMarkdownRemark.edges

Then some fixing of links trought the theme and adding collection name as prefix to page slugs and voala.

Note: I tried some collections plugins but they did’t work or I was missing something. For know I will go with my hacked solution.

Conclusion

To be honest after a week of playing with this stack I got into it. Before I’ve used Jekyll, Middleman and other static site generators.

But GatsbyJS is something different. The plugin ecosystem looks promising. It’s easy to customize it after the initial shock… Also React is not that bad in hindsight. There is posibility to data from other sources like Wordpress and so on.

I do not know if I’ll stick with it but definetly the experience is changing my mind about the JavaScript ecosystem.

Also I can easily embed Youtube videos. :>

Me On Instagram