Pular para o conteúdo
Development

O favicon que ficou quebrado por meses e ninguém teria percebido

Por Victor Da Luz
astroperformancedev-logsite

Um spike de revisão de performance tinha sinalizado quatro coisas pequenas no imperfectsystems.com: a homepage estava renderizando no servidor sem motivo, dois PNGs de logo eram bem maiores do que precisavam ser, e o favicon “provavelmente” não funcionava. Esse último ficou martelando na minha cabeça. Não “não funciona”, “provavelmente não funciona”. Ninguém tinha realmente olhado.

A metade fácil

A homepage foi o fix mais simples do lote inteiro: uma linha, export const prerender = true;. Todo componente de página que ela renderiza puxa de constantes definidas em build-time, nada dinâmico em nenhum ponto da árvore. Antes, toda visita invocava o Worker para renderizar HTML idêntico. Depois, é um arquivo estático. O build confirmou: dist/client/index.html apareceu na lista de rotas pré-renderizadas pela primeira vez e, de bônus, dois stylesheets idênticos byte a byte que antes eram enviados separadamente para a homepage e o blog se juntaram em um só. Não mexi nisso de propósito. Simplesmente parou de ser um problema.

Os logos foram quase tão simples, depois que descobri que não tinha a ferramenta que esperava. O plano pedia WebP, mas essa máquina não tem nenhum encoder de WebP, sem cwebp, sem ImageMagick, e o sips se recusa a escrever nesse formato. O que ela tem é pngquant e oxipng, então fiquei no PNG. O logo principal foi de 772K para 159K com uma passada de qualidade de paleta ajustada alta o suficiente para eu não conseguir ver banding no brilho do degradê (tentei uma configuração mais agressiva primeiro, tirou mais 20K, mas dava para começar a ver o efeito, então recuei). O logo do header foi o ganho maior: ele é renderizado em 32 pixels, mas o arquivo fonte tinha 291. Redimensionar para 96 para retina, comprimir, pronto, de 98K para menos de 5K.

O favicon foi onde “provavelmente” virou “de fato”

O SVG tinha três linhas: um rect de fundo preto e uma tag <image> apontando para o PNG do logo existente como arquivo externo. Código com aparência completamente razoável. O problema é que os navegadores carregam favicons SVG num modo de renderização travado, a mesma restrição que se aplica a um <img src="icon.svg"> simples, e referências a recursos externos são descartadas silenciosamente nesse modo. Sem erro, sem warning no console. A tag de imagem simplesmente não pinta nada, e você fica olhando para o que quer que fosse a forma de fundo.

O fix é parar de referenciar um arquivo externo e embutir o dado da imagem diretamente no SVG como uma URI data: em base64. Uma vez inline, não há referência externa para bloquear. Gerei a URI a partir do logo recém-otimizado (já minúsculo) e escrevi no SVG, um arquivo autocontido em vez de um com uma falha silenciosa de runtime embutida.

Aqui está a parte que quase pulei: eu poderia ter dado isso como concluído, já que a sintaxe é padrão e bem documentada, e seguido em frente confiando nela. Mas “provavelmente renderiza como um rect vazio” era exatamente o tipo de afirmação que fez essa coisa toda ser sinalizada em primeiro lugar, e eu não queria trocar um palpite não verificado por outro, mesmo um bem informado. O qlmanage, o mesmo motor por trás do Quick Look do macOS, consegue rasterizar um SVG direto para uma miniatura PNG pela linha de comando. Rodei contra o arquivo corrigido: logo do chip, limpo, cores corretas. Essa é a diferença entre “isso deveria funcionar agora” e “eu olhei e funciona”.

O que ficou comigo

O favicon provavelmente estava quebrado desde que o arquivo foi criado. Nada quebra quando um favicon falha silenciosamente, a aba só mostra um ícone genérico ou nada, e não há erro nenhum para tropeçar. É o tipo de bug que sobrevive indefinidamente justamente porque a falha não parece nada. O fix levou dez minutos. Perceber que precisava de fix exigiu alguém escrever “verificar, não assumir” na fase de checagem e depois realmente fazer isso, em vez de confiar num SVG de três linhas com aparência plausível, ou, com a mesma facilidade, confiar num fix com aparência plausível sem nunca renderizá-lo.

Leitura relacionada

Development

Dando um rosto para cada link compartilhado

Uma proteção de og:image que nunca disparava, um valor padrão de uma linha que resolveu, um card de terminal feito sob medida, e uma pegadinha de retina no Chrome headless.

Ler
Development

Screenshots para um app sem simulador

O MusicKit não retorna nada no simulador, então as capturas de marketing vieram do serviço simulado que o app já tinha, mais as capas reais da API de busca da iTunes.

Ler
Development

O CSP que só quebrou em produção

Quatro falhas atrás de um único header: middleware morto, regras de _headers que se combinam em vez de sobrescrever, um worker de blob URL sob script-src, e um script que só o edge injeta.

Ler

Você também pode achar útil

Airalo

eSIM Airalo

eSIM de dados local para viagens - sem necessidade de trocar um SIM físico.

Este é meu link de indicação da Airalo. Você recebe um desconto no seu primeiro eSIM e eu ganho crédito da Airalo para o meu.

Saiba mais
Proton

Proton Mail

E-mail criptografado de ponta a ponta, com arquitetura de acesso zero.

Como parceiro da Proton, ganho com compras qualificadas dos serviços de privacidade e segurança da Proton (Pass, Mail, VPN, Drive).

Saiba mais
AdGuard

AdGuard para iOS

Bloqueio de anúncios e rastreadores em todo o sistema no iOS, sem necessidade de um servidor DNS separado.

Como afiliado da AdGuard, ganho com compras qualificadas.

Saiba mais