3Hakyll is a simple static site generator library in Haskell. It is mostly
4inspired by [Jekyll](http://github.com/mojombo/jekyll), but I like to believe
5it is simpler. An example site where it is used is
6[my personal homepage](http://jaspervdj.be) of which
7[the source code](http://jaspervdj.be/snapshot.tar.gz) is available as a
16Inspired by [xmonad](http://xmonad.org), a small Haskell program is used as
17configuration file. In this file, you give instructions on how the site should
18be generated. In the rest of this document, we will examine a small example.
20This is our directory layout:
34Static files can be rendered using the `static` command. This command ensures
35the files will copied when you compile the site.
37For convenience reasons, there is also a `staticDirectory` command, which works
42 staticDirectory "images"
47Pages can be written in html, markdown, LaTeX, and basically anything
48pandoc supports. They can also contain metadata, which are always key-value
52 author: Jasper Van der Jeugt
53 title: A sample markdown post
55 # A sample markdown post
57 This is a sample markdown post. It supports pandoc extensions
58 like code highlighting. For example:
61 main = putStrLn "Hello World!"
64Metadata is always placed in the beginning of a file, and is delimited by a
65`---` string. The metadata can only contain simple key-value pairs. We can
66now read in this page using the `Text.Hakyll.Page.readPage` function. This
67will return a `Page`, which is actually just a `Map String ByteString`. In
68this example, the map would consist of the following key-value pairs:
70- `author`: `Jasper Van der Jeugt`
71- `title`: `A sample markdown post`
72- `body`: The rest of the file (rendered to html).
73- `url`: `text.html` (the original filename was `text.markdown`, the extension
78In hakyll, there is a strict separation between pages and templates. Templates,
79for example, cannot contain metadata.
82 by <strong> $author </title>
86Templates are rendered using the Haskell `Text.Template` library. This means
87that in your template, you can use `$identifier`, and it will be replaced by
88the value of `identifier`.
90With this template we could, for example, render the file we saw in the previous
91section. It would go like this:
93 page <- readPage "text.markdown"
94 render <- renderPage "templates/sample.html" page
96Now, `render` will be a `Page` containing all metadata from `page`, but the
97`body` key would be replaced by the substitution. This means we can combine
98rendering actions. Given another template `templates/default.html`:
102 <title> $title </title>
109We can now combine the rendering actions:
111 page <- readPage "text.markdown"
112 render <- (renderPage "templates/sample.html" page >>=
113 renderPage "templates/default.html")
115Of course, you can't really do anything with the render if you don't write it
116to a file somewhere. That's why the function `renderAndWrite` exists:
118 readPage "text.markdown" >>=
119 renderPage "templates/sample.html" page >>=
120 renderAndWrite "templates/default.html"
122Now, where will this file be written? In `_site/text.html`, of course! That's
123because the page still contains a key called `url`, which the renderAndWrite
124function uses to determine the file destination.
126## More advanced things
128Sometimes, you want to create a `Page` from scratch, without reading from a
129file. There are functions to do that for you, and I suggest you read the
130documentation of `Text.Hakyll.Page`. As a more advanced example, I will
131explain the RSS system I wrote for my website.
135 | `-- 2009-12-02-a-first-post.markdown
140Our post contains some metadata:
144 date: December 2, 2009
149 A first post describing the technical setup of this blog, for that is
151The `templates/rssitem.xml` file is a template for rendering one post to an
155 <title>$title</title>
156 <link>http://jaspervdj.be/$url</link>
157 <description>New blogpost: $title</description>
160Now a template for rendering the whole rss feed, `templates/rss.xml`:
162 <?xml version="1.0" ?>
165 <title>jaspervdj - a personal blog</title>
166 <link>http://jaspervdj.be/</link>
167 <description>Personal blog of jaspervdj</description>
172Alright, let's get coding.
174 -- Find all posts paths.
175 postPaths <- liftM (L.reverse . L.sort) $ getRecursiveContents "posts"
176 -- Read and render all posts with the rssitem.xml template
177 -- Also, only render 5 posts.
178 pages <- mapM readPage (take 5 postPaths)
179 items <- mapM (renderPage "templates/rssitem.xml") pages
181 renderAndWrite "templates/rss.xml" $ pageFromList [ ("items", concatPages items),
184That's that. Now we have a nice rss feed.
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list