Production Drafts for Hakyll Posts
Last week I was asked to review a draft of a blog post:
@RiccardoOdone I just found your blog and am really digging your Haskell content. I'm working on a blog explaining property based testing options, could I ask you to take a look at it? I'd love your feedback / opinion :)— Maxfield Chen (@_nihliphobe) May 13, 2020
That made me realize I don’t have a way to do a similar trick. However, last week I worked on “Adding
published to Hakyll Posts”. Thus, I already did the hard work on understanding the internals, so I could just sit back and code it.
Up until now the blog worked as follows:
- Published posts were compiled by Hakyll to
- Drafts were not compiled except when
HAKYLL_ENVwas set to
With the new changes:
- All posts are compiled by Hakyll.
- Published posts are compiled to
posts/*and appear in the archive.
- Drafts are compiled to
drafts/posts/*but do not appear in the archive.
In particular, only published posts are compiled to
- matchMetadata "posts/*" (isDevelopmentOrPublished env) $ do + matchMetadata "posts/*" isPublished $ do route $ setExtension "html"
Drafts are compiled to
drafts/posts/*. Also, when compiling the URL to the draft is printed:
"posts/*" (not . isPublished) $ do matchMetadata let draftPath = ("drafts/" <>) . (`replaceExtension` "html") . toFilePath . customRoute $ draftPath route let putDraftUrl path = traverse_. putStrLn) (unsafeCompiler "----DRAFT----", [ <>) . draftPath . itemIdentifier $ path, (previewUrl "-------------" ]$ compile pandocCompiler>>= loadAndApplyTemplate "templates/post.html" postCtx >>= loadAndApplyTemplate "templates/default.html" postCtx >>= relativizeUrls >>= (\x -> putDraftUrl x >> pure x)
In the archive only published posts are included except when in development:
create ["archive.html"] $ do route idRoute compile $ do- posts <- recentFirst =<< loadAll "posts/*" + posts <- recentFirst =<< loadAllPublished env "posts/*"
loadAllPublished :: (Binary a, Typeable a) => [(String, String)] -> Pattern -> Compiler [Item a] = if isDevelopmentEnv env then all else published loadAllPublished env pattern_ where all = loadAll pattern_ = publishedIds pattern_ >>= traverse load published = lookup "HAKYLL_ENV" env == Just "development" isDevelopmentEnv env
A similar change appears in the Atom feed code:
- =<< loadAllSnapshots "posts/*" "content" + =<< loadAllSnapshotsPublished "posts/*" "content"
loadAllSnapshotsPublished :: (Binary a, Typeable a) => Pattern -> Snapshot -> Compiler [Item a] = publishedIds pattern_ >>= traverse (`loadSnapshot` snapshot) loadAllSnapshotsPublished pattern_ snapshot publishedIds :: MonadMetadata m => Pattern -> m [Identifier] = fmap (fmap fst . filter (isPublished . snd)) . getAllMetadatapublishedIds
As always, feel free to go ahead and grab the code.
The draft I ended up reviewing was “Functional Fika — Nix and Haskell”. Thanks Maxfield for the inspiration and for teaching me what fika is! ☕️
Support my work by tweeting this article! 🙏