on master help sign in
Finish tutorial rewrite
d570ed1Jasper Van der Jeugt
examples/hakyll/tutorial.markdown+120−174
@@ -40,8 +40,9 @@ Let's get started!
40
40
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:
45
46
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.
92
93
93−We can see two simple rules next: `route` and `compile`.
94+We can see two simple rules next: [route] and [compile].
94
95
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.
98
99
100+[route]: /reference/Hakyll-Core-Rules.html#v:route
101+[compile]: /reference/Hakyll-Core-Rules.html#v:compile
102+
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.
103
107
108+[idRoute]: /reference/Hakyll-Core-Routes.html#v:idRoute
109+
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.
106
112
113+[copyFileCompiler]: /reference/Hakyll-Core-Writable-CopyFile.html#v:copyFileCompiler
114+
107### CSS
115### CSS
108
116
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
116~~~~~
124~~~~~
117
125
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]:
129+
130+[compressCssCompiler]: /reference/Hakyll-Web-CompressCss.html#v:compressCssCompiler
121
131
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.
136
146
137−### Pages
147+### Templates
138−
139−TODO
140−
141−Old tutorial
142−------------
143
148
144−Hakyll consists of two important layers:
149+Next, we can see that the templates are compiled:
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.
159
150
160~~~~~{.haskell}
151~~~~~{.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
152+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
185~~~~~
153~~~~~
186
154
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!
190−
191−To create your site, compile and run your `hakyll.hs`:
192
157
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}
158+~~~~~
204−{-# LANGUAGE OverloadedStrings #-}
159+<html>
205−import Control.Arrow ((>>>))
160+ <head>
206−import Control.Monad (forM_)
161+ <title>Hakyll Example - $title$</title>
207−
162+ </head>
208−import Hakyll
163+ <body>
164+ <h1>$title$</h1>
165+
166+ $body$
167+ </body>
168+</html>
209~~~~~
169~~~~~
210
170
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.
215
175
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?
218−main = hakyll $ do
219−~~~~~
220
178
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/`
225−directory.
226
182
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.
228
184
229−[Pattern]: /reference/Hakyll-Core-Identifier-Pattern.html
185+### Pages
230−[Identifier]: /reference/Hakyll-Core-Identifier.html
231
186
232−~~~~~{.haskell}
187+The code for pages looks suspiciously more complicated:
233−match "css/*" $ do
234−~~~~~
235
188
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
195+~~~~~~
240
196
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.
243−~~~~~
244
199
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.
251
205
252−~~~~~{.haskell}
206+So, I decided to create a site using Hakyll and...
253−compile compressCssCompiler
207+~~~~~~
254−~~~~~
255
208
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.
261
212
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
266−~~~~~
267
216
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.
271
220
272−[Template]: /reference/Hakyll-Web-Template.html
221+~~~~~~{.haskell}
222+match (list ["about.rst", "index.markdown", "code.lhs"]) $ do
223+~~~~~~
273
224
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.
276
228
277−~~~~~{.haskell}
229+[list]: /reference/Hakyll-Core-Identifier-Pattern.html#v:list
278−match "templates/*" $ compile templateCompiler
279−~~~~~
280
230
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"
283−later[^1].
233+~~~~~~
284
234
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
238+want here.
287
239
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
290−manually).
291
241
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
246+~~~~~~
296
247
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.
299
250
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.
303
258
304−The [Rules] reference page has a complete listing of the API used.
259+[Understanding arrows]: http://en.wikibooks.org/wiki/Haskell/Understanding_arrows
305
260
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.
307
264
308−The compilation of our pages is slightly more complicated: we're using another
265+Here, we apply three compilers sequentially:
309−DSL there.
310
266
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]
312
270
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.
316
273
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.:
318
276
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
323~~~~~
279~~~~~
324
280
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.
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.
337
284
338−[Page]: /reference/Hakyll-Web-Page.html
285+More tutorials are in the works...
339−[relativize]: /reference/Hakyll-Web-RelativizeUrls.html
340
286
341Various tips and tricks
287Various tips and tricks
342-----------------------
288-----------------------