This blog is written using gatsbyjs, a powerful static site generator.
I have a pile of articles that aren’t ready for publishing, and I thought of how can I hide them on prod, while making visible on local. And by “making visible” I mean it should be apparent that a post is in a non-published state so that I have a visual cue.
I thought I can perhaps use a different git branch, i.e. git checkout -b drafts
and store drafts there and then cherry-pick posts that are ready to be published into main
. But then it’s hard to see which articles aren’t ready yet as there won’t be any distinguisher on the front-end side. I.e. if I checkout drafts
branch, all the posts will be blended together. That’d be a no-effort solution, but as it had this drawback that I could see would be annoying I decided to actually code it up.
Criteria (DOD)
For those who didn’t know, DOD stands for Definition Of Done
- Being able to marks posts as draft
- Draft posts must be visible on dev
- On dev there must be a visual cue that the post is a draft
- Draft posts must be hidden on prod
Let’s get into this!
draft
field on frontmatter
Frontmatter is extra metadata in YAML defined for the markdown file and it’s separated from the main content of the markdown with triple dashes:
---title: Draft posts in GatsbyJsdescription: Make posts you are working on visible in local env and hidden on proddate: 2022-10-11tags: - gatsby---
This blog is written using [gatsbyjs](https://gatsbyjs.com/), a powerful static site generator....
So the frontmatter for the above markdown can be described as the following JSON:
{ "title": "Draft posts in GatsbyJs", "description": "Make posts you are working on visible in local env and hidden on prod", "date": "2022-10-11", "tags": ["gatsby"]}
Let’s define the draft
field on the frontmatter:
---title: Draft posts in GatsbyJsdescription: Make posts you are working on visible in local env and hidden on proddate: 2022-10-11tags: - gatsbydraft: true---
This blog is written using [gatsbyjs](https://gatsbyjs.com/), a powerful static site generator....
Describe the type to be boolean in the gatsby-node.js
using createSchemaCustomization:
exports.createSchemaCustomization = ({ actions }) => { const { createTypes } = actions ... createTypes(` ... type Frontmatter { title: String description: String date: Date @dateformat ... draft: Boolean } ... `)}
Now, you can already use it as it is, but draft !== published
because whether the article is published depends on environment. Drafts ARE published on local, but ARE NOT published on prod.
We can do just that hooking into graphql node creation using the onCreateNode API.
Adding published
field on GraphQL node creation
As we just established, a post should be published if draft !== true
OR environment is not prod
.
As such, published
field depends on the context.
published = true
for all the posts (even those that are drafts) in non-prod context (or env)published = false
whenever a post is a draft in production context
exports.onCreateNode = ({ node, actions, getNode }) => { const { createNodeField } = actions
if (node.internal.type === `Mdx`) { ... createNodeField({ name: `published`, node, value: node.frontmatter.draft !== true || !isProd, }) ... }}
Determining whether the current env is prod or not can be done using process.env.NODE_ENV
:
const process = require(`process`)const isProd = process.env.NODE_ENV === 'production'
Using both post.frontmatter.draft
and post.fields.published
All the content now can be filtered using a GraphQL filter
filter: {fields: {published: {eq: true}}}
which should be incorporated in all the queries where applicable. This is the pageQuery
of this blog distilled only to the relative parts:
export const pageQuery = graphql` query { allMdx( sort: { fields: [frontmatter___date], order: DESC }, filter: {fields: {published: {eq: true}}} ) { fields { slug published } nodes { frontmatter { title description draft } } } }`
And there you have it! But one little touch… As you remember I wanted visual cues for when a post is in a draft state.
Visual cues for drafts
I simply render a little “editing” sign next to any post title that is in draft state:
const isDraft = post.frontmatter.draft === true
... JSX:
<span itemProp="headline"> {isDraft && <DraftSign />} {title}</span>