Como este site foi construído
Um blog em Phoenix sem banco de dados: o NimblePublisher lê os artigos em Markdown na hora da compilação e eles viram parte do binário.
Este site não tem banco de dados. Os artigos são arquivos Markdown no repositório, lidos na hora da compilação e embutidos no binário. Servir um artigo é achar um elemento numa lista que já está na memória.
Quem faz o trabalho
A peça central é o NimblePublisher, do pessoal da Dashbit. Ele varre um diretório, converte cada arquivo em HTML e chama uma função de construção para cada um:
defmodule Portfolio.Blog do
alias Portfolio.Blog.Post
use NimblePublisher,
build: Post,
from: Application.app_dir(:portfolio, "priv/posts/**/*.md"),
as: :posts,
highlighters: [:makeup_elixir, :makeup_erlang]
@posts Enum.sort_by(@posts, & &1.date, {:desc, Date})
def all(locale), do: Enum.filter(@posts, &(&1.locale == locale))
end
O @posts é um atributo de módulo comum. Depois que o módulo compila, virou constante, e ler um post nunca encosta numa query nem num cache.
O caminho do arquivo é metadado
Cada post mora em priv/posts/{idioma}/{ano}/{mês-dia}-{slug}.md. Idioma, data e slug saem do próprio caminho; o resto vem do frontmatter, no topo do arquivo:
[locale, year, month_day_id] =
filename |> Path.rootname() |> Path.split() |> Enum.take(-3)
Renomear o arquivo, portanto, muda a URL do artigo. O acoplamento é proposital: o repositório vira a fonte de verdade sobre o que está publicado, e o git log acaba contando a história editorial do blog.
O que isso custa
| Markdown no repositório | CMS com banco | |
|---|---|---|
| Publicar | git push |
Salvar no painel |
| Escrever de outro dispositivo | Precisa do repositório | Qualquer navegador |
| Histórico de revisões | git log |
Depende do CMS |
| Custo de infraestrutura | Só o servidor web | Servidor + banco |
| Tempo de resposta | Lista em memória | Query no banco |
A troca de verdade está na segunda linha: para escrever, você precisa do repositório em mãos. Num blog pessoal de quem já vive dentro do git, é um preço baixo pela simplicidade que vem junto.
Um detalhe sobre recompilação
Como os artigos são lidos na compilação, editar um .md precisa disparar uma recompilação do módulo. O NimblePublisher registra cada arquivo como @external_resource, então o Mix já resolve essa parte. Em desenvolvimento, vale ensinar o Phoenix a recarregar o navegador também:
# config/dev.exs
live_reload: [
patterns: [
~r"priv/posts/.*(md)$"
]
]
Salvo o arquivo, a página aberta no navegador se atualiza sozinha.