Construir um blog personalizado do zero em 2026 é uma escolha deliberada. A maioria dos escritores apenas escolhe uma plataforma hospedada e segue em frente. Eu decidi reconstruir meu blog de tecnologia com Astro porque queria ser dono de cada camada da stack e aprender padrões que realmente tornam um site estático mais rápido, e não apenas diferente. O resultado é um site bilíngue que serve conteúdo em japonês e inglês, entrega zero JavaScript por padrão e mantém cada grama de complexidade na minha máquina, em vez de no navegador do visitante.

Aqui estão os cinco padrões que fizeram isso funcionar.

Content Collections com Zod

As Content Collections do Astro fazem mais do que apenas organizar arquivos Markdown em pastas. Elas impõem um contrato entre seu conteúdo e seu código. Eu anexei um schema do Zod a cada coleção de artigos, o que significa que a etapa de build valida o frontmatter antes que uma única página seja renderizada.

O schema exige um campo language que aceita apenas dois valores: ja ou en. Não há ambiguidade sobre qual idioma o leitor receberá. Também adicionei um campo pair que vincula as traduções. Se eu publicar um post sobre Astro em japonês e depois traduzi-lo para o inglês, ambos os arquivos compartilharão o mesmo ID de par. Isso torna a criação de um alternador de idiomas trivial, pois a relação é explícita nos dados, e não inferida pelos nomes dos arquivos.

As datas chegam do frontmatter do Markdown como strings, então o schema as converte automaticamente em objetos Date reais. Isso elimina a lógica de manipulação de strings dentro dos meus templates de página. O benefício mais importante, porém, é o modo de falha. Se um arquivo estiver sem um campo obrigatório ou usar um código de idioma inválido, o build falha imediatamente com um erro claro. Eu corrijo o problema no meu terminal em vez de descobrir um layout quebrado ou um erro 404 silencioso após o deploy.

Pipeline de Conversão de Artigos

Eu não escrevi cada post neste novo formato desde o primeiro dia. Anos de conteúdo residiam no Zenn e no Dev.to, cada plataforma com suas próprias peculiaridades e sintaxes proprietárias. Em vez de copiar e colar e corrigir manualmente, escrevi um script em TypeScript que converte lotes inteiros de artigos em Markdown padrão.

O Zenn usa uma sintaxe de callout personalizada para dicas e avisos. Meu script transforma esses elementos em tags HTML semânticas aside para que sejam renderizados de forma consistente em todo o site. O Dev.to depende de tags Liquid para embeds e blocos especiais. O pipeline traduz esses elementos em links Markdown simples que funcionam em qualquer lugar.

Alguns posts contêm observações destinadas apenas à plataforma original, como um aviso sobre paywalls do Medium ou um caminho de imagem específico do Zenn. Eu os envolvo em comentários HTML para que o conversor possa removê-los durante a migração. O script processa os arquivos linha por linha, mas respeita os limites de código. Quando detecta um bloco de código delimitado, ele ignora as regras de transformação completamente. Corromper um exemplo de sintaxe prejudicaria todo o propósito de um blog de tecnologia, então o parser linha por linha trata blocos de código como zonas intocáveis.

Executar um único comando agora republica anos de escrita sem quebrar um único link ou callout.

Geração de Imagens OGP em Tempo de Build

Imagens de compartilhamento social costumam ser algo deixado para depois. Ou você as desenha manualmente ou instala um serviço de runtime pesado que gera cards sob demanda. Eu não queria nenhum dos dois. Cada imagem de Open Graph neste site é produzida durante o build, para que os visitantes não recebam nada além de uma tag img leve apontando para um PNG estático.

Eu uso o Satori, que recebe marcação JSX e a renderiza em SVG. O resultado é nítido, previsível e fácil de usar com templates. A verdadeira otimização veio do tratamento de fontes. Uma fonte web japonesa completa pode facilmente ultrapassar cinco megabytes. Carregar isso durante o build, quanto mais pedir para um navegador buscá-la, seria absurdo.

Em vez disso, eu uso o subsetting do Google Fonts. O script inspeciona o texto do título de um determinado post e solicita apenas o conjunto exato de glifos necessários para renderizar aquela string. Se um título usa quarenta caracteres japoneses únicos, apenas esses quarenta caracteres viajam pela rede. O build permanece rápido, e a imagem renderizada nunca mostra blocos de "tofu" quebrados porque o subset é preciso. Nada é deixado ao acaso do runtime.

Dark Mode via Tailwind Tokens

Eu me recusei a decorar cada elemento com classes utilitárias dark:. Essa abordagem escala mal e polui o seu markup com ruído. Eu redefini os próprios tokens de cores para que o mesmo nome de classe resolva para valores diferentes, dependendo do tema ativo.

Eu utilizo propriedades customizadas de CSS para cada superfície e cor de texto. No modo claro, --color-white mapeia para #ffffff. No modo escuro, o mesmo nome de variável aponta para um valor quase preto. Meu HTML permanece completamente agnóstico. Um card pode usar bg-ui-surface e text-ui-primary sem se preocupar com a hora do dia. A troca de tema altera as definições das variáveis na raiz, e toda a interface responde instantaneamente.

O único risco dessa abordagem é o flash de conteúdo claro antes do carregamento das folhas de estilo. Eu resolvi isso com um pequeno script inline no head do documento. Ele é executado antes do primeiro paint, verifica o localStorage e a preferência do sistema, e define o atributo data correto imediatamente. Como o script bloqueia a renderização por apenas alguns milissegundos, o visitante nunca vê um clarão branco incômodo antes do modo escuro ser ativado.

Arquitetura de Ilhas e Zero-JS

A premissa central do Astro é que uma página deve começar como HTML estático. O JavaScript entra apenas quando uma interação realmente o exige. Eu levei isso a sério.

Evitei o React para o menu global e o alternador de tema. Ambos são gerenciados com uma pequena quantidade de vanilla JavaScript que reside em um único módulo. Não há overhead de hidratação, nem diffing de virtual DOM, nem runtime de framework para baixar.

A única biblioteca pesada que utilizo é a Mermaid.js para renderizar diagramas a partir de texto. Em vez de importá-la globalmente, eu a envolvi dentro de um Intersection Observer. O observer monitora os containers de diagramas. Quando um usuário rola a página a algumas centenas de pixels de um deles, o script injeta dinamicamente o módulo Mermaid e renderiza o diagrama. Se um post não contiver diagramas, essa biblioteca nunca toca a rede. O carregamento inicial da página permanece leve, e o navegador só paga pelo que o leitor realmente vê.

A Mentalidade Build-First

O fio condutor de cada padrão é direto: se você pode realizar o trabalho durante o build, faça-o lá. Valide seus dados com Zod antes do deploy do site. Converta a sintaxe proprietária da plataforma antecipadamente, em vez de fazê-lo no momento da requisição. Renderize imagens sociais em arquivos estáticos em vez de subir um servidor. Resolva as cores do tema por meio de tokens em vez de enviar lógica para cada cliente. Adie o JavaScript pesado até que o usuário realmente precise dele.

Empurrar a complexidade para a esquerda, para a etapa de build, mantém o runtime previsível, o payload pequeno e o fardo de manutenção gerenciável. O site permanece rápido não por causa de um único truque, mas porque simplesmente há menos acontecendo dentro do navegador do visitante. Essa é a verdadeira recompensa de escolher uma arquitetura estática em 2026.