Quelques pages, pas DRY, contenu en HTML
Lourd, mélange contenu / présentation
Wordpress, dotclear, Spip, …
Markdown => contenu plus léger
Templating => keep it DRY
Github pages => easy to set up
Full text -> developer friendly (vim, git, make, …)
Contributions: pull requests
Publication: scp, git, dropbox, …
Ruby: jekyll, nanoc, …
Python: pelican, frozen flask, …
Node: blacksmith, …
Haskell: hakyll, gitit, yst, …
Bibliothèque + DSL => build your own generator
Installe le compilo et l'outil de build / gestion de dépendances
http://www.haskell.org/platform/ (Gnu/Linux, MacOS, Windows)
Pour windows, Mingw + MSYS en plus
cabal update
cabal install hakyll
(peut prendre un peu de temps)
Crée un blog + pages statiques
hakyll-init blog
cd blog
ghc --make site.hs # compile le générateur
./site preview # serveur HTTP + reload
Ne pas oublier de recompiler site.hs
après l'avoir modifié
On n'est pas des animaux, on utilise un Makefile
all: build
build: site
./site build
site: site.hs
ghc --make site.hs
./site clean
preview: site
./site preview
clean: site
./site clean
check: site
./site check
publish: build
git add .
git stash save
git checkout publish || git checkout --orphan publish
find . -maxdepth 1 ! -name '.' ! -name '.git*' ! -name '_site' \
-exec rm -rf {} +
find _site -maxdepth 1 -exec mv {} . \;
rmdir _site
-git add -A && git commit -m "Publish"
git push -f git+ssh://my-remote publish:master
git checkout master
git clean -fdx
-git stash pop
make clean
make preview
make check # détecte les liens cassés
make publish
Ensemble de pipelines Input -> Output
Matching -> Route -> Compilation -> Injection template
Templates "purs" (pas de logique, juste des points d'injection)
main :: IO ()
main = hakyll $ do
rule_1
…
rule_n
helpers
match "images/*" $ do
route idRoute
compile copyFileCompiler
match "css/*" $ do
route idRoute
compile compressCssCompiler
match (fromList [ "about.rst" , "contact.markdown" ]) $ do
route $ setExtension "html"
compile $ pandocCompiler
>>= loadAndApplyTemplate "tpl/default.html" defaultContext
>>= relativizeUrls
Pas de route
-> pas exposé dans le site généré
match "tpl/*" $ compile templateCompiler
postCtx :: Context String
postCtx =
dateField "date" "%B %e, %Y" `mappend`
defaultContext
postList :: ([Item String] -> Compiler [Item String])
-> Compiler String
postList sortFilter = do
posts <- sortFilter =<< loadAll "posts/*"
itemTpl <- loadBody "tpl/post-item.html"
list <- applyTemplateList itemTpl postCtx posts
return list
match "posts/*" $ do
route $ setExtension "html"
compile $ pandocCompiler
>>= loadAndApplyTemplate "tpl/post.html" postCtx
>>= loadAndApplyTemplate "tpl/default.html" postCtx
>>= relativizeUrls
On peut créer des pages ex nihilo
create ["archive.html"] $ do
route idRoute
compile $ do
let ctx =
field "posts" (\_ -> postList recentFirst) `mappend`
constField "title" "Archives" `mappend`
defaultContext
makeItem ""
>>= loadAndApplyTemplate "tpl/archive.html" ctx
>>= loadAndApplyTemplate "tpl/default.html" ctx
>>= relativizeUrls
match "index.html" $ do
route idRoute
compile $ do
let indexCtx = field "posts" $ \_ ->
postList $ fmap (take 3) . recentFirst
getResourceBody
>>= applyAsTemplate indexCtx
>>= loadAndApplyTemplate "tpl/default.html" postCtx
>>= relativizeUrls
Paire (identifiant, contenu)
Permet de transformer un Item
, en gérant les dépendances.
Par exemple : pandocCompiler
Monadique => traduit la nature séquentielle des compilations
On peut y mettre ce qu'on veut. En particulier, du shell
match "assets/css/*.less" $ do
route $ setExtension "css"
compile $ getResourceString >>=
withItemBody (unixFilter "lessc" ["-","--yui-compress","-O2"])
Données injectées dans un template.
Par exemple, defaultContext
injecte :
Dans le fichier :
---
title: Foo bar baz
---
My awesome content
Dans le template :
<article>
<h1>$title$</h1>
$body$
</article>
postCtx :: Context String
postCtx =
dateField "date" "%B %e, %Y" `mappend`
defaultContext
postCtx
extrait la date du nom de fichier et l'injecte dans le template.
mappend
permet de combiner deux contextes (Context
est un monoide)
Possibilité de construire ses propres contextes
Item a -> Compiler String
$func arg$
)Contenu séparé dans des dossiers /en
et /fr
.
Templates en commun
Langue par défaut à la racine du site généré
langs = ["fr", "en"]
defaultLang = "fr"
-- Enlève automatiquement le "/fr" en début d'URL
langRoute = gsubRoute (defaultLang ++ "/") (const "")
setHtmlLang = langRoute `composeRoutes` (setExtension "html")
Dans les routes :
forM_ langs (\lang ->
match $ (fromGlob $ lang ++ "/posts/*") do
route setHtmlLang
compile $ pandocCompiler
>>= loadAndApplyTemplate "tpl/post.html" postCtx
>>= loadAndApplyTemplate "tpl/default.html" postCtx
>>= relativizeUrls
)
Ajouter Disqus à ses articles de blog
tpl/disqus.html
$body$
<section class="disqus">
<script type="text/javascript">
var page_url = "$url$";
<!-- Disqus stuff -->
</script>
</section>
Modification des règles de compilation
match "posts/*" $ do
route $ setExtension "html"
compile $ pandocCompiler
>>= loadAndApplyTemplate "tpl/post.html" postCtx
>>= loadAndApplyTemplate "tpl/disqus.html" postCtx
>>= loadAndApplyTemplate "tpl/default.html" postCtx
>>= relativizeUrls
GUI avec prose.io
Tags pour les articles de blog
Single page site:
Web2day 2013: i18n, factorisation, dépendances inter-pages, génération de fichier ICS, blocs réutilisables, …
https://github.com/CompanyCampus/web2day2013
http://blog.clement.delafargue.name/posts/2013-04-03-web2day-powered-by-hakyll-part-1.html
Source
https://github.com/divarvel/staticsites-talk
Version PDF
https://speakerdeck.com/clementd/hakyll-generation-dynamique-de-sites-statiques