May 08, 2019
by Rohov Dmytro
I need to exclude specific posts from displaying in production in my blog build with Gatsby and mark them as drafts during development. I will describe how to achieve this goal so you can do this too in less than 5 minutes.
This post is a part of «10 Better with Gatsby» series where I share my personal experience on tuning and tweaking Gatsby.
List of posts in development:
List of posts in production:
date
is after build timemd
files.I found a plugin but could not achieve everything I needed. Mine open sourced solution can be found here:
It allows you to add release functionality via config and skip part of this article. Also there are additional options you can use. Visit plugins README to learn more.
Step #1. Adding new fields to GraphQL
We will add a field called released
based on:
date
field from markdown filereleased
field from markdown fileprocess.env.NODE_ENV
timezone
Also we will add a field called releasedNotForced.
Similar to released
but
with process.env.NODE_ENV
been ignored.
This step is abstracted into gatsby-plugin-released
Step #2. Update GraphQL queries to respect the released
value
We should exclude drafts from building and displaying.
Step #3. Update components to render drafts differently.
To have a nice visual distinction and feel good about it. :)
The goal of this step is to add fields to node.frontmatter.fields
to use via
GraphQL. Gatsby offers a special API for this. What we need is to modify
gatsby-node.js
file.
We will add two fields:
released
fieldreleasedNotForced
field that act just like released
but ignores the
process.env.NODE_ENV
variable.Just in case you are wondering.
In development mode we may want to force posts to be rendered without editing
any GraphQL queries. It is done by forcing released
to be true
based on
process.env.NODE_ENV
. Thus in a development mode we loose the original value
we may want to use in a component code to have a visual distinction between
drafts and released posts.
The way to preserve this is to always set the released
field in a markdown
file. But it was so nice to have this value be calculated automatically based on
date
.
That is why I’ve added a releasedNotForced
property — to preserve that value
while forcing released
to be true.
Remember, if you don’t want to mess with your config just use this plugin.
Here is a function we use to calculate releasedNotForced
value.
// gatsby-node.js
const moment = require('moment-timezone');
const getValue = ({ node, options }) => {
const { fieldName, timezone } = options;
if (!node.frontmatter) {
return false;
}
if (node.frontmatter.hasOwnProperty(fieldName)) {
return node.frontmatter[fieldName];
}
if (!node.frontmatter.date) {
return false;
}
const dateNode = moment.tz(node.frontmatter.date, timezone);
const dateNow = moment().tz(timezone);
const value = dateNow.isSameOrAfter(dateNode);
return value;
};
Then let’s add released
and releasedNotForced
fields to
node.frontmatter.fields
. What we need is to use the onCreateNode
function.
// gatsby-node.js
const onCreateNode = ({ node, actions }) => {
const MD_TYPE = 'MarkdownRemark';
const options = {
fieldName: 'released',
fieldNameNotForced: 'releasedNotForced',
timezone: 'UTC',
force: process.env.NODE_ENV === 'development',
};
const { createNodeField } = actions;
const { fieldName, fieldNameNotForced } = options;
// Skip modifications for non-markdown files
if (node.internal.type !== MD_TYPE) {
return;
}
const value = getValue({ node, options });
createNodeField({
node,
name: fieldName,
value: options.force === true ? true : value,
});
createNodeField({
node,
name: fieldNameNotForced,
value,
});
};
released
valueWe need to exclude drafts from a build step in file gatsby-node.js
and respect
the released
value from blog pages such as index.js.
In both cases the query will look something like this. Pay attention to a filter property.
const query = graphql(
`
{
allMarkdownRemark(
sort: { fields: [frontmatter___date], order: DESC }
filter: { fields: { released: { eq: true } } }
) {
edges {
node {
id
}
}
}
}
`
);
This step is totally up to yours component tree. The key point is to request necessary fields via GraphQL query.
const query = graphql`
query {
allMarkdownRemark(
sort: { fields: [frontmatter___date], order: DESC }
filter: { fields: { released: { eq: true } } }
) {
edges {
node {
id
fields {
slug
released
releasedNotForced
}
}
}
}
}
`;
So we have a single GraphQL query for production and development, released
field is calculated automatically and draft posts can be rendered differently.
Cool!
And be warned! There are drafts in my «10x better Gatsby» series! :) So go check it out to stay tuned!