Artigos

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.

3 min
  • elixir
  • phoenix
Ler em English

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.