heldercorreia.com

autodidata, programador e consultor

Olá Pelican

Tenho escrito ultimamente sobre a minha mudança do Wordpress para o Pelican, que é um gerador de sites estáticos. Neste artigo vou explicar que tecnologias usei para otimizar o novo site e torná-lo bastante mais rápido.

Aqui vai um preview dos tópicos que vou falar:

Site estático

A primeira grande otimização foi tornar o site estático. Sites dinâmicos como o Wordpress permitem gerir os conteúdos através de uma área privada de administração. Esses conteúdos ficam guardados numa base de dados e as páginas são criadas dinamicamente a cada pedido (dependendo da agressividade da cache usada).

Isso permite muita flexibilidade, mas também muito overhead. Quando eu comecei a criar páginas web, usava o Dreamweaver (comecei mesmo pelo Notepad). Uma grande desvantagem era a dificuldade em reutilizar áreas comuns. O meu primeiro grande site era um conjunto de mais de 50 páginas estáticas. Se quisesse mudar o menu, o cabeçalho, rodapé ou qualquer outra área que fosse igual em várias páginas, era uma dor de cabeça.

Os sites dinâmicos resolvem esse problema. Também são a melhor solução quando é preciso mostrar conteúdos de forma diferente para certos utilizadores, como quando há acessos priveligiados.

O meu site é muito simples e apenas muda quando eu modifico conteúdos. Neste caso parecia-me um desperdício de recursos do servidor estar continuamente a gerar as mesmas páginas, para não falar do atraso que o utilizador tem ao esperar que o servidor processe o pedido. A cache ajuda a resolver este problema, mas quando ela precisa ser invalidada, algum utilizador fica com a palhinha mais curta.

Porque não tornar então o site dinâmico para mim, e compilar o resultado final num conjunto de ficheiros estáticos? É como ter uma cache muito agressiva, mas sem nenhum utilizador notar perca de performance enquanto ela precisa ser regenerada.

Se não sabe como os geradores de sites estáticos funcionam, eu tenho um sistema de templates dinâmicos, com ficheiros dedicados apenas ao conteúdo, plugins para extender funcionalidade e um ficheiro de configurações para mudar facilmente variáveis que influenciam o resultado ao longo de todas as páginas do site.

O resultado final é um setup bastante mais simples para eu gerir, com completo controlo sobre o HTML final porque o Pelican não polui a página com elementos HTML e inúmeras classes CSS, e em que todos os utilizadores beneficiam do acesso rápido às páginas já otimizadas.

Alojamento privado

O meu alojamento até agora tem sido partilhado. Já sou cliente DreamHost desde 2009. Porém, hoje em dia com a “nuvem”, já podemos ter um servidor com acesso root (como as VPS) a baixo custo. A maior vantagem do alojamento partilhado já não é então o preço, é a parte do servidor ser gerido por nós.

Eu não me importo de gerir a máquina, e sou capaz de abandonar as excelentes funcionalidades oferecidas pela DreamHost, para ter uma máquina mais rápida, com acesso total para instalar o que quiser e ter processos persistentes a correr (a DreamHost não permite ter processos sempre a correr como um daemon Dropbox, por exemplo).

Decidi então mudar para a Digital Ocean. Eles têm servidores muito rápidos com discos SSD. Cobram à hora e podemos lançar um novo servidor em cerca de 50 segundos. Ter um servidor por 24h é o mesmo que ter 24 servidores a correr por 1h.

Nginx FTW

Na Dreamhost eu usava o Apache, mas o Apache carrega em memória o interpretador do PHP mesmo para servir conteúdos estáticos como ficheiros CSS, javascript ou imagens. Isto é, todos os ficheiros do meu site novo.

O Nginx é muito mais eficiente e como já andava a explorá-lo no trabalho, decidi mudar, sem pensar duas vezes.

Com o Nginx consegui manter os mesmos URLs que tinha no Wordpress e criar uma página 404.

location / {
  ...
  # Try to serve the clean url version first
  try_files $uri.html $uri/index.html $uri =404;
}

error_page 404 /404.html;
location /404.html {
  internal;
}

Compressão (gzip)

Eu uso um plugin para o Pelican, gzip_cache, que me comprime os ficheiros produzidos e assim o Nginx não gasta recursos a comprimir os ficheiros que serve. Eles já estão lá prontos a ser servidos diretamente.

location / {
  # Serve a .gz version if it exists
  gzip_static on;
  ...
}

Imagens responsivas

Quando eu fazia upload de uma imagem no WordPress, não me preocupava com a sua dimensão. Podia enviar uma imagem grande e ele cortava-lhe em várias dimensões mais pequenas para ser mais rápida a transferência do ficheiro para os utilizadores.

Com o Pelican isso não existe, mas também não queria estar todas as vezes a criar manualmente várias dimensões das minhas imagens. O problema das imagens responsivas na web já anda em discussão há muito tempo. Por fim decidi-me por um projeto interessante, o Mobify.js.

Com o Mobify.js, não preciso preocupar-me com este problema. Esta biblioteca deteta o ecrã do utilizador e serve uma versão otimizada.

Eu não tenho que fazer nada, nem mudar o ondereço das minhas imagens. A única coisa que tive que fazer foi inserir um código javascript antes de qualquer outro recurso.

Há um ligeiro atraso no carregamento da página (fica em branco por uns milisegundos), devido à necessidade de ter o Capturing, mas penso que valeu a pena.

Tema dinâmico com Jinja2 e Compass

O Jinja é o sistema de templating suportado pelo Pelican. Muito poderoso, flexível e facilita-me bastante a vida.

Como não quis gastar tempo a criar um novo tema, decidi procurar por um já feito. Gosto do tema do Octopress e fiquei muito satisfeito quando o duilio fez um port para o pelican.

Peguei no tema dele e fiz as minhas modificações. Esse tema vem com Compass para um CSS dinâmico, que também recomendo.

Veja como produzo o código das categorias na barra lateral:

{% if categories %}
<section>
  <h1>Categorias</h1>
  <ul id="recent_posts">
    {% for category, articles in categories %}
     <li><a href="{{ SITEURL }}/{{ category.url }}">{{ category }}</a> ({{ articles|count }})</li>
    {% endfor %}
  </ul>
</section>
{% endif %}

Webassets

Sites dinâmicos geralmente também oferecem forma de agregar os ficheiros css e js, e minificá-los para reduzir os pedidos que o browser precisa fazer para o servidor.

Uma vez que também tenho o meu CSS em Compass, uso a excelente biblioteca Webassets para juntar tudo num só ficheiro (um para o css e outro para o js).

Veja por exemplo como eu produzo o ficheiro final de css e js.

{% assets filters="compass,cssmin", output="css/min.css", "main.scss" %}
<link rel="stylesheet" href="{{ SITEURL }}/{{ ASSET_URL }}">
{% endassets %}

{% assets "all_js" %}
<script src="{{ SITEURL }}/{{ ASSET_URL }}"></script>
{% endassets %}

Os detalhes do Bundle all_js está no ficheiro de configuração para tornar o código Jinja mais limpo. Estou lá a juntar vários ficheiros com o filtro “rjsmin”.

Comentários

Os comentários são notoriamente parte de sites dinâmicos, portanto como se mete comentários em sites estáticos? Hoje em dia há serviços como o Disqus que permitem fazer isso mesmo.

Os comentários ficam alojados numa conta minha no Disqus e são carregados com javascript.

Pesquisa

A pesquisa também é outra funcionalidade naturalmente dinâmica. A maior parte dos sites estáticos usam o Google Custom Search, mas eu não gosto de retirar o utilizador do site para mostrar no google resultados da pesquisa do meu próprio site.

Há um plugin para o Pelican, tipue_search, que usa o plugin jQuery de pesquisa feito pela empresa Tipue. Quando eu compilo o meu site, o plugin no Pelican produz um ficheiro JSON com o conteúdo todo indexado. Depois o que o plugin da Tipue faz é iterar esse ficheiro para encontrar os resultados procurados.

Eu não gostei da forma como o plugin da Tipue estava escrito, começando por forçar o HTML que depois teria que estilar, só para a página da pesquisa. Então alterei o código deles, removendo também funcionalidade que não preciso, para tornar a pesquisa mais rápida.

Esperimente usar a caixa de pesquisa neste site para ver o resultado.

Formulário de contato

Muita gente prefere usar um formulário de contato em vez de enviar email. É mais cómodo. Então procurei forma de também ter isso. Inicialmente pensei em correr no servidor uma aplicação Flask para servir algumas funcionalidades dinâmicas, a começar pelo envio de emails. Mas depois lembrei-me de procurar por soluções já existentes como o Disqus para os comentários.

Encontrei o serviço qontacto que basta criar uma conta e adicionar um iframe para ter um formulário de contato num site estático.

Feed RSS

O feed RSS (ficheiro xml) é gerado automaticamente pelo Pelican ao compilar o site.

No site anterior eu usava o Feedburner para ter mais controle sobre o meu feed RSS, assim como dar métricas de uso. No entanto, uma vez que a Google matou o Reader e o Feedburner parou no tempo, é bem possível que num futuro próximo anunciem também o fim de vida deste serviço.

Para me precaver, fui à procura de um serviço que o substitua. Encontrei o Feedpress que faz mais para mim, e é moderno. É preferível mudar de serviço agora que mudei o site do que mais à frente, e aproveitei também para usar o Feedpress com o meu próprio domínio. Assim se decidir uma vez mais mudar de serviço, não tenho que mudar endereço da feed RSS porque poderei controlar o redirecionamento para onde quiser.

No Nginx tenho uma regra assim:

if ($http_user_agent !~ (FeedValidator|FeedPress)) {
  rewrite ^/feeds/atom.xml$ http://feed.heldercorreia.com/helder redirect;
}

Repare que o endereço feed.heldercorreia.com aponta para o serviço do Feedpress.

$ dig feed.heldercorreia.com -t CNAME +short
redirect.feedpress.me.

Newsletter

O Wordpress permitia receber notificação por email na publicação de artigos novos. Recuperei essa funcionalidade através do FeedPress que permite fazer a mesma coisa. O botão para subscrever está no topo, ao lado da pesquisa e do RSS.

Conclusão

Agora sim, tenho uma plataforma simples mas flexível o suficiente. Já não tenho que me preocupar com os problemas de segurança e inúmeros updates. É fácil fazer modificações e posso alojar em qualquer lado.

Pelo menos por agora, estou muito satisfeito.

Comentários