@@ -40,8 +40,9 @@ Let's get started!
4040
4141We're going to discuss a small brochure site to start with. You can find all
4242code 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
44−files we will use:
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
45+number of files we will use:
4546
4647 about.rst A simple page written in RST format
4748 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].
9091[^pattern]: A little caveat is that these globs are not `String`s but
9192 `Pattern`s, so you need the `OverloadedStrings` extension.
9293
93−We can see two simple rules next: `route` and `compile`.
94+We can see two simple rules next: [route] and [compile].
9495
95−- `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−- `compile`, on the other hand, determines how the file content is processed.
96+- [route] determines how the input file(s) get mapped to the output files.
97+ [route] only deals with file names -- not with the actual content!
98+- [compile], on the other hand, determines how the file content is processed.
9899
99−In this case, we select the `idRoute`: which means the file name will be kept
100+[route]: /reference/Hakyll-Core-Rules.html#v:route
101+[compile]: /reference/Hakyll-Core-Rules.html#v:compile
102+
103+In this case, we select the [idRoute]: which means the file name will be kept
100104the 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
102106to themselves.
103107
104−For our compiler, we use `copyFileCompiler`, meaning that we don't process the
108+[idRoute]: /reference/Hakyll-Core-Routes.html#v:idRoute
109+
110+For our compiler, we use [copyFileCompiler], meaning that we don't process the
105111content at all, we just copy the file.
106112
113+[copyFileCompiler]: /reference/Hakyll-Core-Writable-CopyFile.html#v:copyFileCompiler
114+
107115### CSS
108116
109117If we look at how the two CSS files are processed, we see something which looks
@@ -116,8 +124,10 @@ match "css/*" $ do
116124~~~~~
117125
118126Indeed, the only difference with the images is that have now chosen for
119−`compressCssCompiler` -- a compiler which *does* process the content. Let's have
120−a quick look at the type of `compressCssCompiler`:
127+[compressCssCompiler] -- a compiler which *does* process the content. Let's have
128+a quick look at the type of [compressCssCompiler]:
129+
130+[compressCssCompiler]: /reference/Hakyll-Web-CompressCss.html#v:compressCssCompiler
121131
122132~~~~~{.haskell}
123133compressCssCompiler :: Compiler Resource String
@@ -134,209 +144,145 @@ We can wonder what Hakyll does with the resulting `String`. Well, it simply
134144writes this to the file specified in the `route`! As you can see, routes and
135145compilers work together to produce your site.
136146
137−### Pages
138−
139−TODO
140−
141−Old tutorial
142−------------
147+### Templates
143148
144−Hakyll consists of two important layers:
145−
146−- A top-level declarative eDSL, used to describe the relations between the
147− different items,
148−- A lower-level filter-like eDSL built on Arrows.
149−
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.
153−
154−### The Rules DSL
155−
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.
149+Next, we can see that the templates are compiled:
159150
160151~~~~~{.haskell}
161−{-# LANGUAGE OverloadedStrings #-}
162−import Control.Arrow ((>>>))
163−import Control.Monad (forM_)
164−
165−import Hakyll
166−
167−main :: IO ()
168−main = hakyll $ do
169− match "css/*" $ do
170− route idRoute
171− compile compressCssCompiler
172−
173− match "images/*" $ do
174− route idRoute
175− compile copyFileCompiler
176−
177− match "templates/*" $ compile templateCompiler
178−
179− forM_ ["about.rst", "index.markdown", "code.lhs"] $ \page ->
180− match page $ do
181− route $ setExtension "html"
182− compile $ pageCompiler
183− >>> applyTemplateCompiler "templates/default.html"
184− >>> relativizeUrlsCompiler
152+match "templates/*" $ compile templateCompiler
185153~~~~~
186154
187−This is enough code to create a small brochure site! You can find all code
188−and files necessary to build this site [right here](/examples/brochure.zip)
189−-- feel free to play around with it!
190−
191−To create your site, compile and run your `hakyll.hs`:
155+Let's start with the basics: what is a template? An example template gives us a
156+good impression:
192157
193− [jasper@phoenix] ghc --make hakyll.hs
194− [jasper@phoenix] ./hakyll preview
195−
196−Alternatively,
197−
198− [jasper@phoenix] runghc hakyll.hs preview
199−
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.
202−
203−~~~~~{.haskell}
204−{-# LANGUAGE OverloadedStrings #-}
205−import Control.Arrow ((>>>))
206−import Control.Monad (forM_)
207−
208−import Hakyll
158+~~~~~
159+<html>
160+ <head>
161+ <title>Hakyll Example - $title$</title>
162+ </head>
163+ <body>
164+ <h1>$title$</h1>
165+
166+ $body$
167+ </body>
168+</html>
209169~~~~~
210170
211−Our entry point is simply a `main` function with the type `IO ()` -- as in every
212−other Haskell application. However, we directly wrap it in a `hakyll` function,
213−which marks our declarative eDSL. Inside this function, we no longer operate in
214−the `IO` monad, we operate in the pure `RulesM` monad.
171+A template is a text file to lay our some content. The content it lays out is
172+called a page -- we'll see that in the next section. The syntax for templates is
173+intentionally very simplistic. You can bind some content by referencing the name
174+of the content *field* by using `$field$`, and that's it.
215175
216−~~~~~{.haskell}
217−main :: IO ()
218−main = hakyll $ do
219−~~~~~
176+You might have noticed how we specify a compiler (`compile`), but we don't set
177+any `route`. Why is this?
220178
221−The `RulesM` monad is composed of a few functions. Seldomly, you want to apply a
222−compiler to *all* resources. You want to apply a compiler to certain files
223−instead. That's why the `match` function exists. First, let's handle the CSS of
224−our file. We use a `"css/*"` [Pattern] to match all files in the `css/`
225−directory.
179+Precisely because we don't want to our template to end up anywhere in our site
180+directory! We want to use it to lay out other items -- so we need to load
181+(compile) it, but we don't want to give it a real destination.
226182
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.
228184
229−[Pattern]: /reference/Hakyll-Core-Identifier-Pattern.html
230−[Identifier]: /reference/Hakyll-Core-Identifier.html
185+### Pages
231186
232−~~~~~{.haskell}
233−match "css/*" $ do
234−~~~~~
187+The code for pages looks suspiciously more complicated:
235188
236−`route` creates a new rule for routing items. This rule is applied to all items
237−that are currently matched -- in this case, `"css/*"`. `idRoute` simply means
238−that an item will be routed to it's own filename. For example, `css/screen.css`
239−will be routed to `css/screen.css` -- not very exciting.
189+~~~~~~{.haskell}
190+match (list ["about.rst", "index.markdown", "code.lhs"]) $ do
191+ route $ setExtension "html"
192+ compile $ pageCompiler
193+ >>> applyTemplateCompiler "templates/default.html"
194+ >>> relativizeUrlsCompiler
195+~~~~~~
240196
241−~~~~~{.haskell}
242−route idRoute
243−~~~~~
197+But we'll see shortly that this actually fairly straightforward. Let's begin by
198+exploring what a *page* is.
244199
245−Apart from specifying where the items should go (using `route`), we also have to
246−specify *how* they need to be compiled. This is done using the `compile`
247−function. It takes a `Compiler` as its second argument. These compilers can
248−consist of very complicated constructions, but Hakyll also provides a number of
249−good default compilers. The `compressCssCompiler` compiler will simply compress
250−the CSS found in the files.
200+~~~~~~
201+---
202+title: Home
203+author: Jasper
204+---
251205
252−~~~~~{.haskell}
253−compile compressCssCompiler
254−~~~~~
206+So, I decided to create a site using Hakyll and...
207+~~~~~~
255208
256−We can compile our images in a similar way. We use `idRoute` again, but we don't
257−want to change anything -- so we use `copyFileCompiler`. The difference between
258−most other compilers and `copyFileCompiler` is that the lattern will *not*
259−attempt to read the file: it will copy the file directly, so it supports large
260−binary files as well.
209+A page consists of two parts: a body, and metadata. As you can see above, the
210+syntax is not hard. The metadata part is completely optional, this is the same
211+page without metadata:
261212
262−~~~~~{.haskell}
263−match "images/*" $ do
264− route idRoute
265− compile copyFileCompiler
266−~~~~~
213+~~~~~~
214+So, I decided to create a site using Hakyll and...
215+~~~~~~
267216
268−Next, we're going to render some pages. We're going to style the results a
269−little, so we're going to need a [Template]. We simply compile a template using
270−the `templateCompiler` compiler, it's good enough in most cases.
217+Hakyll supports a number of formats for the page body. Markdown, HTML and RST
218+are probably the most common. Hakyll will automatically guess the right format
219+if you use the right extension for your page.
271220
272−[Template]: /reference/Hakyll-Web-Template.html
221+~~~~~~{.haskell}
222+match (list ["about.rst", "index.markdown", "code.lhs"]) $ do
223+~~~~~~
273224
274−We don't use a route for these templates, after all, we don't want to route them
275−anywhere, we just want to use them to style our pages a little.
225+We see a more complicated pattern here. Some sets of files cannot be described
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.
276228
277−~~~~~{.haskell}
278−match "templates/*" $ compile templateCompiler
279−~~~~~
229+[list]: /reference/Hakyll-Core-Identifier-Pattern.html#v:list
280230
281−We can conclude that some rules do not *directly* add an output page on our
282−site. In this case, we compile the template so it is available to the compiler
283−later[^1].
231+~~~~~~{.haskell}
232+route $ setExtension "html"
233+~~~~~~
284234
285−[^1]: Actually, since the rules DSL is declarative, we could also add the
286− template compile rule at the bottom -- this would make no difference.
235+For our pages, we do not want to use `idRoute` -- after all, we want to generate
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
238+want here.
287239
288−Now, it's time to actually render our pages. We use the `forM_` monad combinator
289−so we can describe all files at once (instead of compiling all three files
290−manually).
240+[setExtension]: /reference/Hakyll-Core-Routes.html#v:setExtension
291241
292−~~~~~{.haskell}
293−forM_ ["about.rst", "index.markdown", "code.lhs"] $ \page -> do
294− match page $ do
295−~~~~~
242+~~~~~~{.haskell}
243+compile $ pageCompiler
244+ >>> applyTemplateCompiler "templates/default.html"
245+ >>> relativizeUrlsCompiler
246+~~~~~~
296247
297−The pages all have different extensions. In our website, we only want to see
298−`.html` files. Hakyll provides a route to do just that:
248+How should we process these pages? A simple compiler such as [pageCompiler],
249+which renders the page, is not enough, we also want to apply our template.
299250
300−~~~~~{.haskell}
301−route setExtension "html"
302−~~~~~
251+[pageCompiler]: /reference/Hakyll-Web-Page.html#v:pageCompiler
252+
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.
303258
304−The [Rules] reference page has a complete listing of the API used.
259+[Understanding arrows]: http://en.wikibooks.org/wiki/Haskell/Understanding_arrows
305260
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.
307264
308−The compilation of our pages is slightly more complicated: we're using another
309−DSL there.
265+Here, we apply three compilers sequentially:
310266
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]
312270
313−The gist of it is that the `Compiler a b` type has two parameters -- it is an
314−Arrow, and we can chain compilers using the `>>>` operator. The [Compiler]
315−reference page has some more readable information on this subject.
271+[applyTemplateCompiler]: /reference/Hakyll-Web-Template.html#v:applyTemplateCompiler
272+[relativizeUrlsCompiler]: /reference/Hakyll-Web-RelativizeUrls.html#v:relativizeUrlsCompiler
316273
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.:
318276
319277~~~~~{.haskell}
320−compile pageCompiler
321− >>> applyTemplateCompiler "templates/default.html"
322− >>> relativizeUrlsCompiler
278+<link rel="stylesheet" type="text/css" href="/css/default.css" />
323279~~~~~
324280
325−Note that we can only use `applyTemplateCompiler` with
326−`"templates/default.html"` because we compiled `"templates/default.html"`. If we
327−didn't list a rule for that item, the compilation would fail (Hakyll would not
328−find the template).
329−
330−Now, let's look at the concrete compiler:
331−
332−- `pageCompiler` starts by reading the [Page], parsing it, and rendering it
333− using [pandoc].
334−- `applyTemplateCompiler` applies a [Template] which we have already loaded.
335−- `relativizeUrlsCompiler` will [relativize] the URL's so we have a site we can
336− deploy everywhere.
281+And Hakyll will translate this to a relative URL for each page. This means we
282+can host our site at `example.com` and `example.com/subdir` without changing a
283+single line of code.
337284
338−[Page]: /reference/Hakyll-Web-Page.html
339−[relativize]: /reference/Hakyll-Web-RelativizeUrls.html
285+More tutorials are in the works...
340286
341287Various tips and tricks
342288-----------------------