diff --git a/web/tutorials/02-basics.markdown b/web/tutorials/02-basics.markdown index f4d781b..b4c5e22 100644 --- a/web/tutorials/02-basics.markdown +++ b/web/tutorials/02-basics.markdown @@ -86,248 +86,46 @@ more customization. You want to route `contact.markdown` to customRoute $ reverse . toFilePath ``` +Basic compilers +--------------- + More information can be found in the [Routes] module. [Routes]: /reference/Hakyll-Core-Routes.html -## Images - -Let's start of with the `images/haskell-logo.png` file, because the processing -of this file is very simple: it is simply copied to the output directory. Let's -look at the relevant lines in the `hakyll.hs` file: - -~~~~~{.haskell} -match "images/*" $ do - route idRoute - compile copyFileCompiler -~~~~~ - -The first line specifies we will describe the process for compiling everything -in the `images/` folder: hakyll uses globs for this [^pattern]. - -[^pattern]: A little caveat is that these globs are not `String`s but - `Pattern`s, so you need the `OverloadedStrings` extension. - -We can see two simple rules next: [route] and [compile]. - -- [route] determines how the input file(s) get mapped to the output files. - [route] only deals with file names -- not with the actual content! -- [compile], on the other hand, determines how the file content is processed. - -[route]: /reference/Hakyll-Core-Rules.html#v:route -[compile]: /reference/Hakyll-Core-Rules.html#v:compile - -In this case, we select the [idRoute]: which means the file name will be kept -the same (`_site` will always be prepended automatically). This explains the -name of [idRoute]: much like the `id` function in Haskell, it also maps values -to themselves. - -[idRoute]: /reference/Hakyll-Core-Routes.html#v:idRoute - -For our compiler, we use [copyFileCompiler], meaning that we don't process the -content at all, we just copy the file. - -[copyFileCompiler]: /reference/Hakyll-Core-Writable-CopyFile.html#v:copyFileCompiler - -## CSS - -If we look at how the two CSS files are processed, we see something which looks -very familiar: - -~~~~~{.haskell} -match "css/*" $ do - route idRoute - compile compressCssCompiler -~~~~~ - -Indeed, the only difference with the images is that have now chosen for -[compressCssCompiler] -- a compiler which *does* process the content. Let's have -a quick look at the type of [compressCssCompiler]: - -[compressCssCompiler]: /reference/Hakyll-Web-CompressCss.html#v:compressCssCompiler - -~~~~~{.haskell} -compressCssCompiler :: Compiler Resource String -~~~~~ - -Intuitively, we can see this as a process which takes a `Resource` and produces -a `String`. - -- A `Resource` is simply the Hakyll representation of an item -- usually just a - file on the disk. -- The produced string is the processed CSS. - -We can wonder what Hakyll does with the resulting `String`. Well, it simply -writes this to the file specified in the `route`! As you can see, routes and -compilers work together to produce your site. - -## Templates - -Next, we can see that the templates are compiled: - -~~~~~{.haskell} -match "templates/*" $ compile templateCompiler -~~~~~ - -Let's start with the basics: what is a template? An example template gives us a -good impression: - -~~~~~ - - - Hakyll Example - $$title$$ - - -

$$title$$

- - $$body$$ - - -~~~~~ - -A template is a text file to lay out some content. The content it lays out is -called a page -- we'll see that in the next section. The syntax for templates is -intentionally very simplistic. You can bind some content by referencing the name -of the content *field* by using `$$field$$`, and that's it. - -You might have noticed how we specify a compiler (`compile`), but we don't set -any `route`. Why is this? - -We need to compile the template because we will need it later. If we compile a -page later using `templates/default.html`, Hakyll needs to know what -`templates/default.html` is. Note that we could move template compilation to the -bottom of our code. The order doesn't matter -- Hakyll will determine that for -you. But if you don't compile `templates/default.html` as a template, Hakyll -will not be able to take it into account when deciding the compilation order. - -So, the `compile` needs to be there -- but why don't we set a `route` here? -Precisely because we don't want to our template to end up anywhere in our site -directory! We want to use it to lay out other items -- so we need to load -(compile) it, but we don't want to give it a real destination. - -By using the `templates/*` pattern, we compile all templates in one go. - -## Pages - -The code for pages looks suspiciously more complicated: - -~~~~~~{.haskell} -match (list ["about.rst", "index.markdown", "code.lhs"]) $ do - route $ setExtension "html" - compile $ pageCompiler - >>> applyTemplateCompiler "templates/default.html" - >>> relativizeUrlsCompiler -~~~~~~ - -But we'll see shortly that this actually fairly straightforward. Let's begin by -exploring what a *page* is. - -~~~~~~ ---- -title: Home -author: Jasper ---- - -So, I decided to create a site using Hakyll and... -~~~~~~ - -A page consists of two parts: a body, and metadata. As you can see above, the -syntax is not hard. The metadata part is completely optional, this is the same -page without metadata: - -~~~~~~ -So, I decided to create a site using Hakyll and... -~~~~~~ - -Hakyll supports a number of formats for the page body. Markdown, HTML and RST -are probably the most common. Hakyll will automatically guess the right format -if you use the right extension for your page. - -~~~~~~{.haskell} -match (list ["about.rst", "index.markdown", "code.lhs"]) $ do -~~~~~~ - -We see a more complicated pattern here. Some sets of files cannot be described -easily by just one pattern, and here the [list] function can help us out. In -this case, we have three specific pages we want to compile. - -[list]: /reference/Hakyll-Core-Identifier-Pattern.html#v:list - -~~~~~~{.haskell} -route $ setExtension "html" -~~~~~~ - -For our pages, we do not want to use `idRoute` -- after all, we want to generate -`.html` files, not `.markdown` files or something similar! The [setExtension] -route allows you to simply replace the extension of an item, which is what we -want here. - -[setExtension]: /reference/Hakyll-Core-Routes.html#v:setExtension - -~~~~~~{.haskell} -compile $ pageCompiler - >>> applyTemplateCompiler "templates/default.html" - >>> relativizeUrlsCompiler -~~~~~~ - -How should we process these pages? [pageCompiler] is the default compiler for -pages. [pageCompiler] does a few things: - -- It parses the page into body and metadata -- It adds some extra metadata fields such as `$$url$$` and `$$path$$` (you - shouldn't worry about these for now) -- It fill in possible `$$key$$`'s in it's own body -- It renders the page using pandoc - -Which basically means that we end up with a `Page` that has the HTML content we -want as body. But we don't just want the plain content on our website -- we want -to decorate it with a template, for starters. - -[pageCompiler]: /reference/Hakyll-Web-Page.html#v:pageCompiler - -Different compilers can be chained in a pipeline-like way using Arrows. Arrows -form a complicated subject, but fortunately, most Hakyll users need not be -concerned with the details. If you are interested, you can find some information -on the [Understanding arrows] page -- but the only thing you really *need* to -know is that you can chain compilers using the `>>>` operator. - -[Understanding arrows]: http://en.wikibooks.org/wiki/Haskell/Understanding_arrows - -The `>>>` operator is a lot like a flipped function composition (`flip (.)`) in -Haskell, with the important difference that `>>>` is more general and works on -all Arrows -- including Hakyll compilers. - -Here, we apply three compilers sequentially: - -1. We load and render the page using `pageCompiler` -2. We apply the template we previously loaded using [applyTemplateCompiler] -3. We relativize the URL's on the page using [relativizeUrlsCompiler] - -[applyTemplateCompiler]: /reference/Hakyll-Web-Template.html#v:applyTemplateCompiler -[relativizeUrlsCompiler]: /reference/Hakyll-Web-RelativizeUrls.html#v:relativizeUrlsCompiler - -Relativizing URL's is a very handy feature. It means that we can just use -absolute URL's everywhere in our templates and code, e.g.: - -~~~~~{.haskell} - -~~~~~ - -Using the [relativizeUrlsCompiler], Hakyll will change this to: - -~~~~~{.haskell} - -~~~~~ - -when we are compiling `index.html`, or - -~~~~~{.haskell} - -~~~~~ - -when we are compiling (some imaginary) `posts/foo.html`. So Hakyll will -translate this to a relative URL for each page. This means we can host our site -at `example.com` and `example.com/subdir` without changing a single line of -code. - -More tutorials are in the works... +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, use + `pandocCompilerWith`). + +Compilers are very flexible: `Compiler` is a [Monad] and `Item` is a [Functor]. + +[Monad]: http://learnyouahaskell.com/a-fistful-of-monads +[Functor]: http://learnyouahaskell.com/functors-applicative-functors-and-monoids + +A good example to illustrate the `Monad` instance for `Compiler` is + +```haskell +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: + +```haskell +pandocCompiler >>= relativizeUrls :: Compiler (Item String) +``` + +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. diff --git a/web/tutorials/03-compilers.markdown b/web/tutorials/03-compilers.markdown new file mode 100644 index 0000000..59fa0da --- /dev/null +++ b/web/tutorials/03-compilers.markdown @@ -0,0 +1,12 @@ +--- +title: Using and writing Compilers +author: Jasper Van der Jeugt +--- + +Identifier, Item, Compiler +-------------------------- + +Three important, related types are `Identifier`, `Item` and `Compiler`. + +- `Identifier` is a string-like value which uniquely identifies a single item + for your webpage