@@ -40,8 +40,9 @@ Let's get started!
41We're going to discuss a small brochure site to start with. You can find all
41We're going to discuss a small brochure site to start with. You can find all
42code and files necessary to build this site [right here](/examples/brochure.zip)
42code and files necessary to build this site [right here](/examples/brochure.zip)
43−-- feel free to look to them as we go trough the tutorial. There's a number of
43+-- feel free to look at them as we go trough the tutorial, in fact, it might be
44+very learnful to have a closer look at the files as we discuss them. There's a
44−files we will use:
45+number of files we will use:
46 about.rst A simple page written in RST format
47 about.rst A simple page written in RST format
47 code.lhs Another page with some code (which can be highlighted)
48 code.lhs Another page with some code (which can be highlighted)
@@ -90,20 +91,27 @@ in the `images/` folder: hakyll uses globs for this [^pattern].
90[^pattern]: A little caveat is that these globs are not `String`s but
91[^pattern]: A little caveat is that these globs are not `String`s but
91 `Pattern`s, so you need the `OverloadedStrings` extension.
92 `Pattern`s, so you need the `OverloadedStrings` extension.
93−We can see two simple rules next: `route` and `compile`.
94+We can see two simple rules next: [route] and [compile].
95−- `route` determines how the input file(s) get mapped to the output files.
96+- [route] determines how the input file(s) get mapped to the output files.
96− `route` only deals with file names -- not with the actual content!
97+ [route] only deals with file names -- not with the actual content!
97−- `compile`, on the other hand, determines how the file content is processed.
98+- [compile], on the other hand, determines how the file content is processed.
100+[route]: /reference/Hakyll-Core-Rules.html#v:route
101+[compile]: /reference/Hakyll-Core-Rules.html#v:compile
99−In this case, we select the `idRoute`: which means the file name will be kept
103+In this case, we select the [idRoute]: which means the file name will be kept
100the same (`_site` will always be prepended automatically). This explains the
104the same (`_site` will always be prepended automatically). This explains the
101−name of `idRoute`: much like the `id` function in Haskell, it also maps values
105+name of [idRoute]: much like the `id` function in Haskell, it also maps values
102to themselves.
106to themselves.
108+[idRoute]: /reference/Hakyll-Core-Routes.html#v:idRoute
104−For our compiler, we use `copyFileCompiler`, meaning that we don't process the
110+For our compiler, we use [copyFileCompiler], meaning that we don't process the
105content at all, we just copy the file.
111content at all, we just copy the file.
113+[copyFileCompiler]: /reference/Hakyll-Core-Writable-CopyFile.html#v:copyFileCompiler
109If we look at how the two CSS files are processed, we see something which looks
117If we look at how the two CSS files are processed, we see something which looks
@@ -116,8 +124,10 @@ match "css/*" $ do
118Indeed, the only difference with the images is that have now chosen for
126Indeed, the only difference with the images is that have now chosen for
119−`compressCssCompiler` -- a compiler which *does* process the content. Let's have
127+[compressCssCompiler] -- a compiler which *does* process the content. Let's have
120−a quick look at the type of `compressCssCompiler`:
128+a quick look at the type of [compressCssCompiler]:
130+[compressCssCompiler]: /reference/Hakyll-Web-CompressCss.html#v:compressCssCompiler
122~~~~~{.haskell}
132~~~~~{.haskell}
123compressCssCompiler :: Compiler Resource String
133compressCssCompiler :: Compiler Resource String
@@ -134,209 +144,145 @@ We can wonder what Hakyll does with the resulting `String`. Well, it simply
134writes this to the file specified in the `route`! As you can see, routes and
144writes this to the file specified in the `route`! As you can see, routes and
135compilers work together to produce your site.
145compilers work together to produce your site.
137−### Pages
147+### Templates
144−Hakyll consists of two important layers:
149+Next, we can see that the templates are compiled:
146−- A top-level declarative eDSL, used to describe the relations between the
148−- A lower-level filter-like eDSL built on Arrows.
150−Both layer are used in the configuration file of your website. This
151−configuration file is conventionally called `hakyll.hs` and placed at the root
152−of your website directory.
156−The Rules DSL is probably the simpler one. Let's look at a very simple example
157−of a `hakyll.hs`. This piece of code might look a little confusing, but don't
158−worry, we'll walk through it in detail.
160~~~~~{.haskell}
151~~~~~{.haskell}
161−{-# LANGUAGE OverloadedStrings #-}
162−import Control.Arrow ((>>>))
163−import Control.Monad (forM_)
171− compile compressCssCompiler
173− match "images/*" $ do
175− compile copyFileCompiler
177− match "templates/*" $ compile templateCompiler
152+match "templates/*" $ compile templateCompiler
179− forM_ ["about.rst", "index.markdown", "code.lhs"] $ \page ->
181− route $ setExtension "html"
182− compile $ pageCompiler
183− >>> applyTemplateCompiler "templates/default.html"
184− >>> relativizeUrlsCompiler
187−This is enough code to create a small brochure site! You can find all code
155+Let's start with the basics: what is a template? An example template gives us a
188−and files necessary to build this site [right here](/examples/brochure.zip)
156+good impression:
189−-- feel free to play around with it!
191−To create your site, compile and run your `hakyll.hs`:
193− [jasper@phoenix] ghc --make hakyll.hs
194− [jasper@phoenix] ./hakyll preview
198− [jasper@phoenix] runghc hakyll.hs preview
200−Our code begins with a number of imports. Nothing out of the ordinary here, but
201−do note that we use the `OverloadedStrings` extension for conciseness.
203−~~~~~{.haskell}
158+~~~~~
204−{-# LANGUAGE OverloadedStrings #-}
159+<html>
205−import Control.Arrow ((>>>))
160+ <head>
206−import Control.Monad (forM_)
161+ <title>Hakyll Example - $title$</title>
208−import Hakyll
163+ <body>
211−Our entry point is simply a `main` function with the type `IO ()` -- as in every
171+A template is a text file to lay our some content. The content it lays out is
212−other Haskell application. However, we directly wrap it in a `hakyll` function,
172+called a page -- we'll see that in the next section. The syntax for templates is
213−which marks our declarative eDSL. Inside this function, we no longer operate in
173+intentionally very simplistic. You can bind some content by referencing the name
214−the `IO` monad, we operate in the pure `RulesM` monad.
174+of the content *field* by using `$field$`, and that's it.
216−~~~~~{.haskell}
176+You might have noticed how we specify a compiler (`compile`), but we don't set
217−main :: IO ()
177+any `route`. Why is this?
221−The `RulesM` monad is composed of a few functions. Seldomly, you want to apply a
179+Precisely because we don't want to our template to end up anywhere in our site
222−compiler to *all* resources. You want to apply a compiler to certain files
180+directory! We want to use it to lay out other items -- so we need to load
223−instead. That's why the `match` function exists. First, let's handle the CSS of
181+(compile) it, but we don't want to give it a real destination.
224−our file. We use a `"css/*"` [Pattern] to match all files in the `css/`
227−Note that a [Pattern] matches an [Identifier], it doesn't match filenames.
183+By using the `templates/*` pattern, we compile all templates in one go.
229−[Pattern]: /reference/Hakyll-Core-Identifier-Pattern.html
185+### Pages
230−[Identifier]: /reference/Hakyll-Core-Identifier.html
232−~~~~~{.haskell}
187+The code for pages looks suspiciously more complicated:
236−`route` creates a new rule for routing items. This rule is applied to all items
189+~~~~~~{.haskell}
237−that are currently matched -- in this case, `"css/*"`. `idRoute` simply means
190+match (list ["about.rst", "index.markdown", "code.lhs"]) $ do
238−that an item will be routed to it's own filename. For example, `css/screen.css`
191+ route $ setExtension "html"
239−will be routed to `css/screen.css` -- not very exciting.
192+ compile $ pageCompiler
193+ >>> applyTemplateCompiler "templates/default.html"
194+ >>> relativizeUrlsCompiler
241−~~~~~{.haskell}
197+But we'll see shortly that this actually fairly straightforward. Let's begin by
242−route idRoute
198+exploring what a *page* is.
245−Apart from specifying where the items should go (using `route`), we also have to
200+~~~~~~
246−specify *how* they need to be compiled. This is done using the `compile`
201+---
247−function. It takes a `Compiler` as its second argument. These compilers can
202+title: Home
248−consist of very complicated constructions, but Hakyll also provides a number of
203+author: Jasper
249−good default compilers. The `compressCssCompiler` compiler will simply compress
204+---
250−the CSS found in the files.
252−~~~~~{.haskell}
206+So, I decided to create a site using Hakyll and...
253−compile compressCssCompiler
207+~~~~~~
256−We can compile our images in a similar way. We use `idRoute` again, but we don't
209+A page consists of two parts: a body, and metadata. As you can see above, the
257−want to change anything -- so we use `copyFileCompiler`. The difference between
210+syntax is not hard. The metadata part is completely optional, this is the same
258−most other compilers and `copyFileCompiler` is that the lattern will *not*
211+page without metadata:
259−attempt to read the file: it will copy the file directly, so it supports large
260−binary files as well.
262−~~~~~{.haskell}
213+~~~~~~
263−match "images/*" $ do
214+So, I decided to create a site using Hakyll and...
264− route idRoute
215+~~~~~~
265− compile copyFileCompiler
268−Next, we're going to render some pages. We're going to style the results a
217+Hakyll supports a number of formats for the page body. Markdown, HTML and RST
269−little, so we're going to need a [Template]. We simply compile a template using
218+are probably the most common. Hakyll will automatically guess the right format
270−the `templateCompiler` compiler, it's good enough in most cases.
219+if you use the right extension for your page.
272−[Template]: /reference/Hakyll-Web-Template.html
221+~~~~~~{.haskell}
222+match (list ["about.rst", "index.markdown", "code.lhs"]) $ do
274−We don't use a route for these templates, after all, we don't want to route them
225+We see a more complicated pattern here. Some sets of files cannot be described
275−anywhere, we just want to use them to style our pages a little.
226+easily by just one pattern, and here the [list] function can help us out. In
227+this case, we have three specific pages we want to compile.
277−~~~~~{.haskell}
229+[list]: /reference/Hakyll-Core-Identifier-Pattern.html#v:list
278−match "templates/*" $ compile templateCompiler
281−We can conclude that some rules do not *directly* add an output page on our
231+~~~~~~{.haskell}
282−site. In this case, we compile the template so it is available to the compiler
232+route $ setExtension "html"
285−[^1]: Actually, since the rules DSL is declarative, we could also add the
235+For our pages, we do not want to use `idRoute` -- after all, we want to generate
286− template compile rule at the bottom -- this would make no difference.
236+`.html` files, not `.markdown` files or something similar! The [setExtension]
237+route allows you to simply replace the extension of an item, which is what we
288−Now, it's time to actually render our pages. We use the `forM_` monad combinator
240+[setExtension]: /reference/Hakyll-Core-Routes.html#v:setExtension
289−so we can describe all files at once (instead of compiling all three files
292−~~~~~{.haskell}
242+~~~~~~{.haskell}
293−forM_ ["about.rst", "index.markdown", "code.lhs"] $ \page -> do
243+compile $ pageCompiler
294− match page $ do
244+ >>> applyTemplateCompiler "templates/default.html"
295−~~~~~
245+ >>> relativizeUrlsCompiler
297−The pages all have different extensions. In our website, we only want to see
248+How should we process these pages? A simple compiler such as [pageCompiler],
298−`.html` files. Hakyll provides a route to do just that:
249+which renders the page, is not enough, we also want to apply our template.
300−~~~~~{.haskell}
251+[pageCompiler]: /reference/Hakyll-Web-Page.html#v:pageCompiler
301−route setExtension "html"
252+
302−~~~~~
253+Different compilers can be chained in a pipeline-like way using Arrows. Arrows
254+form a complicated subject, but fortunately, most Hakyll users need not be
255+concerned with the details. If you are interested, you can find some information
256+on the [Understanding arrows] page -- but the only thing you really *need* to
257+know is that you can chain compilers using the `>>>` operator.
304−The [Rules] reference page has a complete listing of the API used.
259+[Understanding arrows]: http://en.wikibooks.org/wiki/Haskell/Understanding_arrows
306−[Rules]: /reference/Hakyll-Core-Rules.html
261+The `>>>` operator is a lot like a flipped function composition (`flip (.)`) in
262+Haskell, with the important difference that `>>>` is more general and works on
263+all Arrows -- including Hakyll compilers.
308−The compilation of our pages is slightly more complicated: we're using another
265+Here, we apply three compilers sequentially:
311−### The Compiler DSL
267+1. We load and render the page using `pageCompiler`
268+2. We apply the template we previously loaded using [applyTemplateCompiler]
269+3. We relativize the URL's on the page using [relativizeUrlsCompiler]
313−The gist of it is that the `Compiler a b` type has two parameters -- it is an
271+[applyTemplateCompiler]: /reference/Hakyll-Web-Template.html#v:applyTemplateCompiler
314−Arrow, and we can chain compilers using the `>>>` operator. The [Compiler]
272+[relativizeUrlsCompiler]: /reference/Hakyll-Web-RelativizeUrls.html#v:relativizeUrlsCompiler
315−reference page has some more readable information on this subject.
317−[Compiler]: /reference/Hakyll-Core-Compiler.html
274+Relativizing URL's is a very handy feature. It means that we can just use
275+absolute URL's everywhere in our templates and code, e.g.:
319~~~~~{.haskell}
277~~~~~{.haskell}
320−compile pageCompiler
278+<link rel="stylesheet" type="text/css" href="/css/default.css" />
321− >>> applyTemplateCompiler "templates/default.html"
322− >>> relativizeUrlsCompiler
325−Note that we can only use `applyTemplateCompiler` with
281+And Hakyll will translate this to a relative URL for each page. This means we
326−`"templates/default.html"` because we compiled `"templates/default.html"`. If we
282+can host our site at `example.com` and `example.com/subdir` without changing a
327−didn't list a rule for that item, the compilation would fail (Hakyll would not
283+single line of code.
330−Now, let's look at the concrete compiler:
332−- `pageCompiler` starts by reading the [Page], parsing it, and rendering it
334−- `applyTemplateCompiler` applies a [Template] which we have already loaded.
335−- `relativizeUrlsCompiler` will [relativize] the URL's so we have a site we can
338−[Page]: /reference/Hakyll-Web-Page.html
285+More tutorials are in the works...
339−[relativize]: /reference/Hakyll-Web-RelativizeUrls.html
341Various tips and tricks
287Various tips and tricks
342-----------------------
288-----------------------