O favicon que ficou quebrado por meses e ninguém teria percebido
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
Rotas de dev log filtradas por projeto, e a sessão concorrente que me pegou de surpresa
Consertar dois links sem destino exigiu construir filtragem por tag, até uma colisão do git de uma sessão concorrente me pegar no meio do lançamento.
Destacando os pacotes compartilhados dos quais este site depende silenciosamente
Contagem de estrelas não vende bem infraestrutura. Adicionei uma subseção escrita à mão, e uma suposição sobre ferramentas não sobreviveu à checagem.
Fazer rebase de um PR de afiliados sobre um build que o dependabot quebrou silenciosamente
Uma atualização agrupada de 12 pacotes escondia uma major do Tailwind que quebrou o build e outra do Astro em silêncio, por uma branch não mesclada.
Você também pode achar útil
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 maisProton 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 maisAdGuard 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