Search code examples
haskellhakyll

Why am I unable to define an arbitrary field in Hakyll?


When trying to define a "links" field on my index page, I'm met with an error that says: [ERROR] Missing field $links$ in context for item index.html, even though I have created a links field. (At least I'm pretty sure I have ...)

-- site.hs
main = hakyll $ do

    match "index.html" $ do
        route idRoute
        compile $ do
            links <- loadAll "links/*"
            let indexCtx =
                    listField "links" linkCtx (return links) `mappend`
                    constField "title" "Home"                `mappend`
                    defaultContext

            getResourceBody
                >>= applyAsTemplate indexCtx
                >>= loadAndApplyTemplate "templates/default.html" indexCtx
                >>= relativizeUrls

    match "templates/*" $ compile templateBodyCompiler


linkCtx :: Context String
linkCtx =
    field "link" $ \item -> return (itemBody item)
    defaultContext

-- index.html
<h2>Links</h2>
$partial("templates/link-list.html")$

-- templates/link-list.html
<ul>
    $for(links)$
        $link$
    $endfor$
</ul>

-- links/behance.markdown
---
title: Behance
---

[Behance](https://www.behance.net/laylow)

Solution

  • When trying your code, I get no such error. Instead I get a type error from linkCtx. It can be corrected like this:

    linkCtx =
        field "link" (\item -> return (itemBody item)) `mappend`
        defaultContext
    

    Or more idiomatically, replacing the lambda with point-free form.

    linkCtx =
        field "link" (return . itemBody) `mappend`
        defaultContext
    

    Also if you want to load some items, you should match them first so hakyll knows about their existence.

        match "links/*" $ compile pandocCompiler
    

    After making the changes listed above, rebuild site.hs using: stack build and the list of links will be rendered in index.html