10 anos depois uma camada nova de tinta no estaminé

Para quem não reparou este meu cantinho da internet já vai em mais de 15 anos e infelizmente não tem sido lá muito bem tratado. Nos últimos 5 anos em particular tinha ficado praticamente estagnado e a última vez que lhe dei uma nova camada de tinta foi em 2009 pelos meus registos. É tempo a mais.

Posto isto tenho andado a trabalhar muito lentamente num novo look para o site desde sensivelmente 2017 mas por todas as razões e mais algumas (mas maioritariamente preguiça) nunca andei muito para a frente com a coisa. No entanto neste último ano a coisa mudou um bocadinho e lá me dediquei mais à coisa mas o grande problema que me impedia de me dedicar muito à epopeia mantinha-se: não estava de todo feliz com a base tecnológica em que o blog estava assente.

A versão anterior do site corria em WordPress com uma série de plugins em cima que infelizmente não ajudavam a manter a coisa corrente e actualizada. Em cima disso trabalhar em cima do código do wordpress não era algo que me deixasse muito a chama acesa mas a ideia de deixar para trás mais de 10 anos de contéudo não era algo que eu achasse aceitável.

O próximo problema foi que eu preferia seriamente usar algum tipo de geração de html estático e não queria de todo ter um runtime a correr no servidor mas soluções como Hugo e afins implicava que teria de abdicar de usar a minha framework de eleição para o frontend (Preact). Outro critério que eu queria atingir era que o site tinha de funcionar sem javascript também. Apesar de eu fazer da linguagem minha profissão continuo a achar que é importante manter o conteúdo online acessível ao maior número de dispositivos possível. Não sinto que tenha atingido totalmente esse objectivo (continuo a ter demasiado javascript a correr) consegui atingir um patamar que acho aceitável.

E com isto chegamos a finais de Fevereiro de 2020 e dou comigo com demasiado tempo livre. Decidi então parar de procrastinar e coloquei a mim próprio uma data limite de 24 de Abril para terminar o que já tinha começado e colocar finalmente uma nova versão do meu blog no ar.

Para fazer isto tive de fazer alguns compromissos: o primeiro é que o conteúdo continua a viver numa instalação de wordpress. Funciona, tem lá os dados todos e honestamente ia demorar sensivelmente o mesmo tempo a extraí-lo para algo diferente sem grandes garantias de ficar tudo a funcionar. O wordpress é também usado como um headless CMS e o html que é servido é totalmente gerado à priori. Exceção feita para os feeds RSS que ainda são servidos pelo WordPress.

O segundo foi que tive de lidar com o suporte sub-óptimo para sites estáticos do Next.js. Funciona perfeitamente depois do contéudo ser gerado mas neste momento cada publicação ou update demora entre 15 minutos e meia hora a regenerar o site inteiro. Parte do problema prende-se com a decisão de ter escolhido wordpress como backend mas outra grande parte prende-se com eu não ter encontrado ainda forma de tornar a geração incremental.

Portanto a solução final passa por usar o wordpress como repositório de dados que são por sua vez consumidos através de API por uma aplicação feita em Next.js que os transforma em ficheiros HTML estáticos que são hidratados com javascript depois de carregado no browser. Em vez de React usei Preact (que é a minha biblioteca de eleição para os meus projectos) porque aprecio a preocupação com manter o tamanho da biblioteca baixo.

Optei também por usar o plugin WPGraphQL mas ainda equaciono voltar atrás na decisão e usar a API REST directamente. Usei-o por curiosidade profissional mas acabei por ter de escrever vários pequenos pedaços de código PHP para colmatar as falhas do plugin ou para interagir com um dos poucos mas importantes plugins que decidi manter: o YARPP para artigos relacionados.

No entanto tudo isto combinado resulta em cerca de 200kb de download por página excluíndo imagens. Obviamente que quando se adicionam estas últimas (e especialmente com o cabeçalho grande do site a viver de fotos minhas que fui adicionando ao longo dos anos) esse número dispara bastante.

E é aqui que vem outra das peças importantes da equação: lidar com imagens. Desde cedo que quis evitar ao máximo que a instalação de wordpress fosse acessível ao mundo em geral logo uma das questões que procurei resolver foi mover o upload de imagens para uma solução de object storage. Para isso usei o plugin S3-Uploads para enviar as imagens para inicialmente para um bucket the Amazon S3. Desativei todas as transformações que o wordpress faz às imagens (geração de miniaturas, aplicar um tamanho máximo) e decidi meter mãos à obra numa solução minha para servir as imagens com dimensões razoáveis.

Para fazer isso desenvolvi um pequeno proxy que chamei de Pulitzer e que aplica uma série de transformações a imagens guardando depois o resultado na mesma solução de object storage para reduzir o custo de processar as imagens em tempo real.

Ora os mais atentos já repararam que disse “inicialmente” quando referi que guardava as imagens em Amazon S3. A verdade é que fruto da forma como o meu desenvolvimento progrediu acabei por não fazer isso e guardar as imagens localmente usando um pedaço de software compatível com S3, o Minio, e um nginx para servir os ficheiros estáticos e invocar o Pulitzer condicionalmente. Originalmente a ideia era colocar este mecanismo de transformação de imagens na AWS, possivelmente com um pequeno lambda em cloudfront a tratar de invocar o meu proxy. Mas a minha inexperiência com a plataforma e o meu receio com os custos escondidos da solução fez-me voltar atrás e correr tudo numa VPS na Digital Ocean como faço há anos.

Posto isto montei um ficheiro docker-compose, coloquei o Traefik a tratar de SSL via Let’s Encrypt e de rotear para os serviços necessários (nginx para as imagens, nginx + php-fpm para o WordPress, etc), e segui em frente.

Tudo isto funciona porque perdi uma boa parte do meu tempo a processar o conteúdo que resulta da api do wordpress em HTML para uma representação intermédia que me permite mapear para componentes (p)react. Galerias, imagens, “lightboxes”, citações, etc. A solução foi escrever um interpretador que converte esse output da API em DOM e o itera transformando numa representação em JSON dos componentes necessários que são à posteriori renderizados no frontend. Não é de todo ideal mas o WordPress guarda o HTML gerado na base de dados e só algumas coisas são guardadas como “shortcodes”. Tentar fazer um parser híbrido que suportasse HTML e estes shortcodes era ainda mais trabalhoso pelo que deixar o JSDom tratar do assunto foi uma solução mais eficaz.

Inicialmente nem existia a representação intermédia mas isso implicava que, em dispositivos móveis, havia um impacto notório ao carregar a página a primeira vez graças ao processo de hidratação que se via forçado a interpretar novamente aquilo que o servidor já tinha feito. Nos casos triviais (como este artigo que é maioritariamente texto) o impacto era mínimo mas em casos complexos com múltiplas imagens, galerias e afins o processo podia criar uma lentidão notória ao abrir a página.

Cheguei a ponderar seriamente abdicar do conteúdo antigo e cheguei mesmo a tentar converter o output do site velho para HTML estático e deixá-lo como estava, preso no tempo, mas no fim de contas o desafio era interessante e este blog serve acima de tudo para satisfazer a minha curiosidade pessoal do que outra coisa.

Posto isto resta-me apenas fazer os possíveis e impossíveis para tentar manter a minha escrita em dia daqui para a frente. Tenho várias coisas que gostaria de escrever (jogos que joguei e anime que vi ou que planeio ver maioritariamente) mas o mais importante é voltar a ganhar o hábito e quebrar o jejum destes últimos anos aqui no cantinho.

Ah! Só uma última coisa. Como podem ter visto a caixa de comentários não sobreviveu. Para qualquer coisa recomendo vivamente um toque no twitter @d3x7r0.