Discussion:
[hakyll] Related Posts
Wayne Chang
2017-03-19 16:46:43 UTC
Permalink
Hi,



I'm trying to add a Related Posts section to my blog...I'm running into
circular dependency errors from the item compiler as I try to link two
posts to each other.
---
title: My Post Title
teaser: Something eye-catching that will make the user click
bannerImageUrl: /images/my-post.png
- "2017-01-02-my-second-post.md"
- "2017-01-07-my-third-post.md"
---
match "posts/*" $ do
route $ cleanRoute
compile $ do
id' <- getUnderlying
metadata <- getMetadata id'
let relatedPostsNames = fromMaybe [] $ lookupStringList
"relatedPosts" metadata
let relatedPostsPaths = map (fromFilePath . ("posts/"++))
relatedPostsNames
posts <- loadAll $ fromList relatedPostsPaths
let mHasRelatedPosts = (if null posts then mempty else
constField "hasRelatedPosts" "True")
let taggedPostCtx =
mHasRelatedPosts
`mappend`
listField "posts" postCtx (return posts)
`mappend`
constField "postListingTitle" "Related Posts"
`mappend`
postCtxWithTags tags
pandocCompiler
= loadAndApplyTemplate "templates/post.html"
= taggedPostCtx
= loadAndApplyTemplate "templates/default.html"
= taggedPostCtx
= relativizeUrls
It works except for the problem above. We can first have Post 1 can
refer to Post 2, but at this point, Post 2 can no longer refer to Post 1
without creating a circular dependency.


I'm considering:

- Loading Post metadata in a way that sneaks past the compiler's
dependency graph
- Creating a post/meta folder containing only files with copied metadata
per post, allowing for a DAG


Neither of these feel ideal. Any thoughts?



Thanks in advance for any responses! I can do a short write-up on this
after to help those with this problem in the future.


Best,

- Wayne
--
You received this message because you are subscribed to the Google Groups "hakyll" group.
To unsubscribe from this group and stop receiving emails from it, send an email to hakyll+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Wayne Chang
2017-03-19 18:56:03 UTC
Permalink
Update on this. I'm just trying to just get this to work today, so I
Post by Wayne Chang
Creating a post/meta folder containing only files with copied metadata
per post, allowing for a DAG
This is my solution:



First, we add a prepare step to our Makefile. This step will extract the
Post by Wayne Chang
@(cd posts/ && \
mkdir -p meta; \
for f in *.md; do \
csplit "$$f" "%---%" > /dev/null; \
mv xx00 "meta/$$f"; \
echo "Generated posts/meta/$$f"; \
done);
match "posts/meta/*" $ do
route idRoute
compile pandocCompiler
Point of confusion here...the documentation suggests[1] that load will
load files as-needed if they're not in the compiler depgraph already,
but I found the above line necessary for loadAll to find my metadata
files at all. Also, when I experimented by feeding a file Identifier
called "DEFINITELY-NOT-FOUND" to loadAll, it silently failed and
returned an empty list. Does loadAll not follow that rule? Or maybe the
documentation meant that the asset will be loaded so long as they're
specified as a match? In any case, the silent failing is pretty non-
ideal for me.
Post by Wayne Chang
let relatedPostsPaths = map (fromFilePath . ("posts/meta/"++))
relatedPostsNames
Voila! Graph cycle broken.



Of course, if you think of something nicer, I'd love to hear about it.
I'll be trying to do that myself.


Best,

- Wayne
Post by Wayne Chang
Hi,
I'm trying to add a Related Posts section to my blog...I'm running
into circular dependency errors from the item compiler as I try to
link two posts to each other.
---
title: My Post Title
teaser: Something eye-catching that will make the user click
bannerImageUrl: /images/my-post.png
- "2017-01-02-my-second-post.md"
- "2017-01-07-my-third-post.md"
---
match "posts/*" $ do
route $ cleanRoute
compile $ do
id' <- getUnderlying
metadata <- getMetadata id'
let relatedPostsNames = fromMaybe [] $ lookupStringList
"relatedPosts" metadata
let relatedPostsPaths = map (fromFilePath . ("posts/"++))
relatedPostsNames
posts <- loadAll $ fromList relatedPostsPaths
let mHasRelatedPosts = (if null posts then mempty else
constField "hasRelatedPosts" "True")
let taggedPostCtx =
mHasRelatedPosts
`mappend`
listField "posts" postCtx (return posts)
`mappend`
constField "postListingTitle" "Related Posts"
`mappend`
postCtxWithTags tags
pandocCompiler
= loadAndApplyTemplate "templates/post.html"
= taggedPostCtx
= loadAndApplyTemplate "templates/default.html"
= taggedPostCtx
= relativizeUrls
It works except for the problem above. We can first have Post 1 can
refer to Post 2, but at this point, Post 2 can no longer refer to Post
1 without creating a circular dependency.
- Loading Post metadata in a way that sneaks past the compiler's
dependency graph
- Creating a post/meta folder containing only files with copied
metadata per post, allowing for a DAG
Neither of these feel ideal. Any thoughts?
Thanks in advance for any responses! I can do a short write-up on this
after to help those with this problem in the future.
Best,
- Wayne
Links:

1. https://hackage.haskell.org/package/hakyll-4.9.5.1/docs/Hakyll-Core-Compiler.html#v:load
--
You received this message because you are subscribed to the Google Groups "hakyll" group.
To unsubscribe from this group and stop receiving emails from it, send an email to hakyll+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Jasper Van der Jeugt
2017-03-19 19:08:09 UTC
Permalink
Hey Wayne,

I'm on mobile right now so I can't be too elaborate but generally a good
approach to this is using version support:

https://jaspervdj.be/hakyll/tutorials/06-versions.html

You can generate two "versions" for every post: one version of the post can
be used just to get the metadata, and other version can be used for the
actual pages.

Hope this helps
Jasper

On Mar 19, 2017 7:58 PM, "Wayne Chang" <***@wycd.net> wrote:

Update on this. I'm just trying to just get this to work today, so I went
with hacky solution #2:

Creating a post/meta folder containing only files with copied metadata per
post, allowing for a DAG


This is my solution:

First, we add a prepare step to our Makefile. This step will extract the
metadata header per post in posts/ and stick them in posts/meta:

prepare:
@(cd posts/ && \
mkdir -p meta; \
for f in *.md; do \
csplit "$$f" "%---%" > /dev/null; \
mv xx00 "meta/$$f"; \
echo "Generated posts/meta/$$f"; \
done);


Load the files into the compiler:

match "posts/meta/*" $ do
route idRoute
compile pandocCompiler

Point of confusion here...the documentation suggests
<https://hackage.haskell.org/package/hakyll-4.9.5.1/docs/Hakyll-Core-Compiler.html#v:load>
that load will load files as-needed if they're not in the compiler depgraph
already, but I found the above line necessary for loadAll to find my
metadata files at all. Also, when I experimented by feeding a file
Identifier called "DEFINITELY-NOT-FOUND" to loadAll, it silently failed and
returned an empty list. Does loadAll not follow that rule? Or maybe the
documentation meant that the asset will be loaded so long as they're
specified as a match? In any case, the silent failing is pretty non-ideal
for me.

Modify relatedPostsPaths use the metadata subdirectory:

let relatedPostsPaths = map (fromFilePath . ("posts/meta/"++))
relatedPostsNames


Voila! Graph cycle broken.

Of course, if you think of something nicer, I'd love to hear about it. I'll
be trying to do that myself.

Best,
- Wayne

On Sun, Mar 19, 2017, at 12:46 PM, Wayne Chang wrote:

Hi,

I'm trying to add a Related Posts section to my blog...I'm running into
circular dependency errors from the item compiler as I try to link two
posts to each other.

This is my attempt:

In posts/2017-01-01-post-title.md:

---
title: My Post Title
teaser: Something eye-catching that will make the user click
bannerImageUrl: /images/my-post.png
relatedPosts:
- "2017-01-02-my-second-post.md"
- "2017-01-07-my-third-post.md"
---


In src/Main.hs:

match "posts/*" $ do
route $ cleanRoute
compile $ do
id' <- getUnderlying
metadata <- getMetadata id'
let relatedPostsNames = fromMaybe [] $ lookupStringList
"relatedPosts" metadata
let relatedPostsPaths = map (fromFilePath . ("posts/"++))
relatedPostsNames
posts <- loadAll $ fromList relatedPostsPaths
let mHasRelatedPosts = (if null posts then mempty else
constField "hasRelatedPosts" "True")
let taggedPostCtx =
mHasRelatedPosts
`mappend`
listField "posts" postCtx (return posts)
`mappend`
constField "postListingTitle" "Related Posts"
`mappend`
postCtxWithTags tags

pandocCompiler
= loadAndApplyTemplate "templates/post.html"
taggedPostCtx
= loadAndApplyTemplate "templates/default.html"
taggedPostCtx
= relativizeUrls
It works except for the problem above. We can first have Post 1 can refer
to Post 2, but at this point, Post 2 can no longer refer to Post 1 without
creating a circular dependency.

I'm considering:
- Loading Post metadata in a way that sneaks past the compiler's dependency
graph
- Creating a post/meta folder containing only files with copied metadata
per post, allowing for a DAG

Neither of these feel ideal. Any thoughts?

Thanks in advance for any responses! I can do a short write-up on this
after to help those with this problem in the future.

Best,
- Wayne
--
You received this message because you are subscribed to the Google Groups
"hakyll" group.
To unsubscribe from this group and stop receiving emails from it, send an
email to hakyll+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups "hakyll" group.
To unsubscribe from this group and stop receiving emails from it, send an email to hakyll+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Loading...