Writing Drafts In Gatsby
2/9/2019
There are a few solutions out there for keeping drafts in GatsbyJS, but none achieved what I wanted.
The ones I've found required graphql
to do the heavy lifting to filter out drafts which meant a lot of filtering out anything where drafts was false. If you don't care about the justification, you can skip to the code for how I write drafts in GatsbyJS.
Justification
These were the specifications that led me to the solution I use:
- Easy to infer which articles are in draft state.
- Single author not using Netlify CMS (works for multiple authors as well, but not required for me).
- The production build/runtime of my site should be totally unaware of drafts.
Finding Drafts is Clear
I'm a huge advocate for reducing the friction of finding content that has a state of "Work in Progress". Having a separate directory explicitly for drafts helps me do that.
One of the downsides of using drafts
in frontmatter is that you usually have to search through the frontmatter with a tool that can tell if a file is a draft (grep, ripgrep, etc) or keep the state in your brain (which is a bad use of a brain).
Single Author Hosting Content on Dropbox
I'm the only author on my Gatsby sites and use Dropbox to host my content. I think this solution could easily work for multiple authors using git as the "backend" (the way you might use Netlify CMS), but I haven't tried that with this solution so mileage may vary.
I also use Dropbox to host my content and builds are done as a result of changes to files. Having a separate drafts folder allows me to write content without triggering unnecessary Dropbox/Netlify hooks.
Production Safety
I don't want to have a bunch of drafts filters in my GraphQL. I can't think of a compelling reason for GraphQL to filter drafts when I know that I don't want drafts in production). Having a separate drafts folder reduces a lot of the complexity (and potential bugs) that would come with using GraphQL to do the same filtering.
How I Write Drafts in Gatsby
Now to the fun part: configuring Gatsby!
I have two content folders in my src directory:
content
- the content ready for productiondrafts
- the content that I'm still working on
There are 3 "stages" of the content lifecycle:
Stage | content present | drafts present |
---|---|---|
Local Development | ✅ (symlink) | ✅ (symlink) |
Non-Production Netlify | ✅ (pulled at build) | ✅ (pulled at build) |
Production Netlify | ✅ (pulled at build) | ❌ |
The goal is to have a gatsby-source-filesystem
for drafts
in any non-production stage and to not even worry about it in production.
Setup for Gatsby Config
In my gatsby-config.js
I have a Gatsby config object (rather than setting the object directly on module.exports
):
const cfg = {
/* ...my default configuration */
};
module.exports = cfg;
Then do a conditional check for the environment where Gatsby is building the site (based on Netlify's deploy contexts):
if (process.env.CONTEXT !== "production") {
const draftsCfg = {
resolve: `gatsby-source-filesystem`,
options: {
name: `drafts`,
path: `${__dirname}/src/drafts`
}
};
cfg.plugins.push(draftsCfg);
}
If process.env.CONTEXT
isn't production
, provide drafts
as a filesystem source.
draftsCfg
is agatsby-source-filesystem
plugin configuration object, where thesourceInstanceName
of the content isdrafts
and the path to the content is thesrc/drafts
directory inside of the project root.
Next we push the draftsCfg
into the plugins
object that Gatsby will use when it builds the site.
Now whenever Gatsby is run locally or in a non-production branch (because Netlify's preview branches are AWESOME!) and the build in the production environment is totally unaware of the fact that we have a drafts
folder.
Caveat
A lot of this looks like it's dependent on using Netlify, but every hosting provider worth its salt provides a way to set environment variables. Netlify does it out of the box, so it was super convenient to hook into that, but it's not a show stopper if you're using another hosting provider.
Big ❤️ to GatsbyJS and Netlify for making this process super easy!