Tutorial: Rules, routes and compilers
Basic rules
While changing the content is nice, you’ll have time for that once your site is
configured. Configuration is done using the site.hs
file: let’s take a look at
it!
main :: IO ()
= hakyll $ do
main ...
Hakyll configurations are in the Rules
monad. In order to run them, the
hakyll
function is used, so your main function usually starts this way.
hakyllWith
is also available, this function allows you specify a custom
Configuration.
Some actual rules look like this:
"images/*" $ do
match
route idRoute
compile copyFileCompiler
"css/*" $ do
match
route idRoute compile compressCssCompiler
This is a declarative DSL: the order in which you write the rules makes little difference, Hakyll will use dependency tracking to determine the correct order.
We group the different rules using match
. The first argument for match
is a
Pattern. The OverloadedStrings
extension allows us to just write String
s
here, which are interpreted as globs — all files in the images/
directory,
and all files in the css/
directory.
However, we can see that one item makes no use of match
, but uses create
instead.
"archive.html"] $ do
create [
route idRoute$ do
compile ...
Don’t pay attention to the somewhat complicated-looking stuff in compile
–
this will become clear soon. The real question here is why we use create
instead of match
.
The answer is simple: there is no archive.html
file in our project directory!
So if we were to use match
, no file would be matched, and hence, nothing
would appear in the output directory. create
, however, ensures the items
listed are always produced.
Basic routes
The route
function is used for determining the output file. For example, you
probably want to write the processed contents of contact.markdown
to
_site/contact.html
and not _site/contact.markdown
.
idRoute
is a commonly used route and just keeps the filename. We use this for
e.g. the images and CSS files.
setExtension
is another common route which takes a single argument: the
desired extension of the resulting file. In order to route contact.markdown
to
_site/contact.html
, use:
$ setExtension "html" route
customRoute
is a more advanced higher-order function which allows for even
more customization. You want to route contact.markdown
to
_site/nwodkram.tcatnoc
? No problem, just use:
$ customRoute $ reverse . toFilePath route
More information can be found in the Routes module.
Basic compilers
The compile
function determines how the content is produced for a certain
item. compile
takes a value of the type Compiler (Item a)
. Let’s look at
some common examples:
copyFileCompiler
is self-explanatory, the output is exactly the same as the input;compressCssCompiler
performs some simple build-in compression transformations for CSS;pandocCompiler
reads markdown, reStructuredText, or another input format and renders it as HTML (if you want to pass specific options to pandoc, usepandocCompilerWith
).
Compilers are very flexible: Compiler
is a Monad and Item
is a Functor.
A good example to illustrate the Monad
instance for Compiler
is
relativizeUrls :: Item String -> Compiler (Item String)
This compiler traverses your HTML and changes absolute URLs (e.g.
/posts/foo.markdown
into relative ones: ../posts/foo.markdown
). This is
extremely useful if you want to deploy your site in a subdirectory (e.g.
jaspervdj.be/hakyll
instead of jaspervdj.be
). Combining this with the
pandocCompiler
gives us:
>>= relativizeUrls :: Compiler (Item String) pandocCompiler
For a real website, you probably also want to use templates in order to give your pages produced by pandoc a nice layout. We tackle this in the next tutorial.
Other tutorials
Find links to other tutorials.Documentation inaccurate or out-of-date? Found a typo?
Hakyll is an open source project, and one of the hardest parts is writing correct, up-to-date, and understandable documentation. Therefore, the authors would really appreciate it if you would give feedback about the tutorials, and especially report errors or difficulties you encountered. If you have a github account, you can use the issue system. Thanks! If you run into any problems, all questions are welcome in the above google group, or you could try the IRC channel,#hakyll
on
irc.libera.chat (we do not have
a channel on Freenode anymore).