@@ -0,0 +1,167 @@
1+The Hakyll Tutorial
2+===================
3+
4+Why static websites?
5+--------------------
6+
7+Modern web frameworks make it easy to create huge dynamic websites. Why would
8+anyone still care about a static website?
9+
10+- Static websites are fast, because it's simply files served directly from the
11+ hard disk.
12+- Static websites are secure. Nobody has even found an SQL injection in static
13+ pages.
14+- Static websites are easy to deploy. Just copy them to your webhost using
15+ (S)FTP/rsync/scp and you are done. They work on all webhosts: no CGI or extra
16+ modules needed for the web server.
17+
18+Why Hakyll?
19+-----------
20+
21+Hakyll is a [Haskell] library meant for creating small-to-medium sized static
22+websites. It is a powerful publishing tool, precisely because of the power of
23+Haskell. By using the awesome [pandoc] library, it is able to create your
24+website from a large variety of input formats.
25+
26+[Haskell]: http://haskell.org/
27+[pandoc]:
28+
29+Features include:
30+
31+- easy templating system;
32+- a simple HTTP server for previewing and compiling your website on the go;
33+- powerful syntax highlighting;
34+- modules for common items such as tags and feeds;
35+- easily extensible.
36+
37+A simple brochure site
38+----------------------
39+
40+### The two layers
41+
42+Hakyll consists of two important layers:
43+
44+- A top-level declarative eDSL, used to describe the relations between the
45+ different items,
46+- A lower-level filter-like eDSL built on Arrows.
47+
48+Both layer are used in the configuration file of your website. This
49+configuration file is conventionally called `hakyll.hs` and placed at the root
50+of your website directory.
51+
52+### The Rules DSL
53+
54+The Rules DSL is probably the simpler one. Let's look at a very simple example
55+of a `hakyll.hs`. This piece of code might look a little confusing, but don't
56+worry, we'll walk through it in detail.
57+
58+~~~~~{.haskell}
59+{-# LANGUAGE OverloadedStrings #-}
60+import Control.Arrow ((>>>))
61+import Control.Monad (forM_)
62+
63+import Hakyll
64+
65+main :: IO ()
66+main = hakyll $ do
67+ route "css/*" idRoute
68+ compile "css/*" defaultCompressCss
69+
70+ compile "templates/*" defaultTemplateRead
71+
72+ forM_ ["about.rst", "index.markdown", "code.lhs"] $ \page -> do
73+ route page $ setExtension "html"
74+ compile page $ defaultPageRead
75+ >>> require "templates/default.html" (flip applyTemplate)
76+ >>> defaultRelativizeUrls
77+~~~~~
78+
79+This is enough code to create a small brochure site! You can find all code
80+and files necessary to build this site [right here](TODO: add link!) -- feel
81+free to play around with it!
82+
83+Our code begins with a number of imports. Nothing out of the ordinary here, but
84+do note that we use the `OverloadedStrings` extension for conciseness.
85+
86+~~~~~{.haskell}
87+{-# LANGUAGE OverloadedStrings #-}
88+import Control.Arrow ((>>>))
89+import Control.Monad (forM_)
90+
91+import Hakyll
92+~~~~~
93+
94+Our entry point is simply a `main` function with the type `IO ()` -- as in every
95+other Haskell application. However, we directly wrap it in a `hakyll` function,
96+which marks our declarative eDSL. Inside this function, we no longer operate in
97+the `IO` monad, we operate in the pure `RulesM` monad.
98+
99+~~~~~{.haskell}
100+main :: IO ()
101+main = hakyll $ do
102+~~~~~
103+
104+The `RulesM` monad is composed of a few functions. A first important one is
105+`route`: this creates a new rule for routing items. This rule is applied to all
106+items it matches -- and matching is done using the `"css/*"` [pattern].
107+`idRoute` simply means that an item will be routed to it's own filename. For
108+example, `css/screen.css` will be routed to `css/screen.css` -- not very
109+exciting.
110+
111+[pattern]: TODO: link
112+
113+~~~~~{.haskell}
114+route "css/*" idRoute
115+~~~~~
116+
117+Apart from specifying where the items should go (using `route`), we also have to
118+specify *how* the need to be compiled. This is done using the `compile`
119+function. As second argument, it takes a `Compiler`. These compilers can consist
120+of very complicated constructions, but Hakyll also provides a number of good
121+default compilers. The `defaultCompressCss` compiler will simply compress the
122+CSS found in the files.
123+
124+~~~~~{.haskell}
125+compile "css/*" defaultCompressCss
126+~~~~~
127+
128+Next, we're going to render some pages. We're going to style the results a
129+little, so we're going to need a [template]. We simply compile a template using
130+the `defaultTemplateRead` compiler, it's good enough in most cases.
131+
132+[template]: TODO: link
133+
134+We don't use a route for these templates, after all, we don't want to route them
135+anywhere, we just want to use them to style our pages a little.
136+
137+~~~~~{.haskell}
138+compile "templates/*" defaultTemplateRead
139+~~~~~
140+
141+Now, it's time to actually render our pages. We use the `forM_` monad combinator
142+so we can describe all files at once.
143+
144+~~~~~{.haskell}
145+forM_ ["about.rst", "index.markdown", "code.lhs"] $ \page -> do
146+~~~~~
147+
148+The pages all have different extensions. In our website, we only want to see
149+`.html` files. Hakyll provides a route to do just that:
150+
151+~~~~~{.haskell}
152+route page $ setExtension "html"
153+~~~~~
154+
155+The compilation of our pages is slightly more complicated: we're using another
156+DSL there.
157+
158+### The Compiler DSL
159+
160+The gist of it is that the `Compiler a b` type has two parameters -- it is an
161+Arrow, and we can chain compilers using the `>>>` operator.
162+
163+~~~~~{.haskell}
164+compile page $ defaultPageRead
165+ >>> require "templates/default.html" (flip applyTemplate)
166+ >>> defaultRelativizeUrls
167+~~~~~