By default, Hakyll does not come with a system for writing drafts: posts whose contents you would like to preview, but not deploy to the live site.
When I first wanted to add drafts to my own website, I did some internet research and found this post by Jorge Israel Peña, which does a great job of explaining what to do. Unfortunately, I assume he was using an older version of Hakyll because I still needed to do some tweaks to make everything work. Here’s how my drafts system works with Hakyll 4.5.1.0:
Put all published posts into the posts
directory, and put draft posts into the drafts
directory.
To build a draft version of the website, run ./site build draft
. To build the deployable version of the website, just run ./site build
as normal. Any action can be targeted for the draft version simply by adding draft
as the second command line argument. For example, run ./site watch draft
to host the draft version of the website on your local machine.
To publish a draft, simply move it from the drafts
directory to the posts
directory.
Here’s the game plan. In the main
function, we first parse the command line arguments before the call to the hakyll
function. If we detect the draft
parameter, then we’ll modify the Hakyll configuration to use a separate set of cache and destination directories used exclusively for draft builds. We’ll also create a new Pattern
called postsPattern
that we use anywhere we used to have a pattern for the posts
directory: (e.g., match "posts/*"
becomes match postsPattern
). Here’s the relevant code:
main = do
args <- getArgs
let draftMode = length args == 2 && args !! 1 == "draft"
hakyllConf = if draftMode
then defaultConfiguration {
destinationDirectory = "_draft",
storeDirectory = "_draftcache",
tmpDirectory = "_draftcache/tmp"
}
else defaultConfiguration
postsPattern = if draftMode
then "posts/*.markdown" .||. "drafts/*.markdown"
else "posts/*.markdown"
args' = take 1 args
when draftMode $ putStrLn "Running in draft mode"
withArgs args' $ hakyllWith hakyllConf $ do
-- Your Hakyll rules go here
-- ...
Notice that we use withArgs
to hide the draft
command line argument from the call to hakyllWith
because it is not a recognized argument and would cause a command line parsing error.
Finally, as already mentioned, anywhere you attempt to match against a pattern like "posts/*"
, replace the pattern with postsPattern
. Consider defining a utility function
matchPosts = match postsPattern
and using matchPosts
throughout your code.