Como criar um site simples em Haskell #2
Um dos elementos básicos que usamos para criar um site é um sistema de templates.
Um sistema de templates é uma ponte que conecta dados estáticos (ex: templates HTML) e dados dinâmicos (ex: saída de um código Haskell).
Para este tutorial eu escolhi o Heist, que é o sistema usado pelo Snap Framework.
Nas próximas seções você vai aprender a:
- Fragmentar uma página HTML em múltiplos arquivos
.tpl
(templates) que serão processados pelo Heist para compor o site final. - Escrever o código Haskell para renderizar a
index.html
a partir dos templates e salvá-la na pasta_site/
.
Este é o segundo artigo de um tutorial de 3 partes.
Leia também: Parte 1 e Parte 3.
Fragmentando a “index.html”
Template | Conteúdo |
---|---|
_head.tpl | <head> |
_nav.tpl | <nav> |
_footer.tpl | <footer> |
Uma das funcionalidades básicas de um sistema de templates é permitir o reúso de fragmentos de código na hora de construir as páginas de um site.
Esses fragmentos são separados em diferentes arquivos e o próprio sistema de templates fornece mecanismos para você montar as páginas como se elas fossem um quebra-cabeças.
No nosso site, todas as páginas terão um cabeçalho, um menu de navegação e um rodapé.
Ao invés de repetir o código desses 3 componentes em todas as páginas, vamos colocá-los em arquivos separados e combiná-los em um layout padrão que poderá ser usado por qualquer página.
Crie esses arquivos na pasta templates/
copiando as respectivas tags do arquivo index.html
conforme a tabela acima.
Criando o template padrão
Agora podemos definir um template _default.tpl
contendo a estrutura padrão de todas as páginas do site.
<!-- default.tpl -->
<!DOCTYPE html>
<html lang="pt-br">
<!-- Cabeçalho -->
<apply template="_head">
<apply-content />
</apply>
<body>
<!-- Navegação -->
<apply template="_nav">
<apply-content />
</apply>
<!-- Conteúdo da página -->
<div class="container">
<apply-content />
</div>
<!-- /.container -->
<!-- Rodapé -->
<div class="container">
<hr>
<apply template="_footer">
<apply-content />
</apply>
</div>
<!-- /.container -->
<!-- jQuery -->
<script src="assets/js/jquery.js"></script>
<!-- Bootstrap Core JavaScript -->
<script src="assets/js/bootstrap.min.js"></script>
</body>
</html>
Encare esse código por um tempo e tente entender o que está acontecendo…
Nós definimos a estrutura básica de uma página HTML e usamos a tag <apply>
para preencher as seções usando código que definimos em outros arquivos.
Por exemplo, nas linhas 5–7, nós selecionamos o template _head.tpl
e “aplicamos” o seu conteúdo com a tag <apply-content />
.
Nós fazemos o mesmo para _nav.tpl
e _footer.tpl
.
Criando o “index.tpl”
Não sei se você viu, mas na linha 17 do arquivo _default.tpl
tem uma tag orfã.
Ela é a única que não tem como pai uma tag `<apply template=”…”>`.
Quando isso acontece, o Heist sabe que aquele ponto é onde ele deve inserir o conteúdo das páginas que aplicarem o _default.tpl
.
Assim, podemos definir nosso index.tpl
como:
<!-- index.tpl -->
<apply template="_default">
Copie para cá os componentes definidos em "index.html":
- Lista de categorias
- Carrossel
- Grid de presentes
</apply>
O index.tpl
é o template que representa nossa página inicial.
Para criar outras páginas, é só usar esta mesma estrutura.
Remontando a página inicial
Nas seções anteriores nós incorporamos o “Heist Estripador” e agora é a hora de juntar as partes .tpl
para trazer nossa index.html
de volta à vida.
Este é o código:
{-# LANGUAGE OverloadedStrings #-}
import Heist
import Heist.Interpreted
import Blaze.ByteString.Builder
import Control.Lens
import qualified Data.Text.Lazy as TL
import qualified Data.Text.Lazy.Encoding as TL
import qualified Data.Text.Lazy.IO as TL
heistConfig = emptyHeistConfig
& hcNamespace .~ ""
& hcLoadTimeSplices .~ defaultInterpretedSplices
& hcTemplateLocations .~ [loadTemplates "templates/"]
main = do
heistState <- either (error . unlines) id <$> initHeist heistConfig
Just (builder, _) <- renderTemplate heistState "index"
TL.writeFile "site/index.html" . TL.decodeUtf8 . toLazyByteString $ builder
As linhas 3–9 contêm os módulos que nós importamos.
Nas linhas 11–12 nós definimos a constante heistConfig
, que contém as configurações necessárias para inicializar o Heist .
A função main
faz apenas 3 coisas:
- Linha 17: Inicializa o Heist chamando
initHeist
e, em caso de sucesso, recupera oHeistState
correspondente. Em caso de erro, encerra a execução e escreve a exceção no console. - Linha 18: Renderiza o template
index.tpl
e, em caso de sucesso, recupera oBuilder
correspondente. Em caso de erro, encerra a execução e escreve a exceção no console. - Linha 19: Decodifica a sequência de bytes que compõe o site usando o padrão UTF-8 e escreve o resultado no caminho
site/index.html
.
Agora é só executar esse código para “ressuscitar” a index.html
.
Podemos fazer isso de duas formas:
- Executar
stack build && stack exec gift-list
. - Executar
stack ghci
e chamar a funçãomain
dentro do REPL.
Se tudo estiver certo, você deverá ver um novo index.html
na pasta site/
idêntico ao original.
Na terceira e última parte desse tutorial você vai aprender como inserir dados dinâmicos, provenientes de código Haskell, nos templates. Clique aqui para ler!