Compartilhando um blog Astro entre dois sites
Eu queria um dev log no imperfectsystems.com. O blog que já tenho no vdaluz.com funciona bem, então o movimento óbvio era reaproveitar o código dele em vez de escrever um segundo do zero. “Reaproveitar” acabou sendo mais interessante do que eu esperava.
Você não consegue extrair um blog
Meu primeiro instinto foi “extrair o blog para um pacote”. Isso não é uma coisa real em Astro. Rotas moram em src/pages/ e precisam ficar em cada app. Conteúdo é uma pasta de markdown por site. A configuração do Shiki, a configuração do Tailwind e o CSS de tema também são todos por app. O que é de fato portável é menor do que parece: os componentes que renderizam um card de post, uma barra de paginação, a lista de posts relacionados, mais a função de pontuação e o schema de conteúdo.
Então a versão honesta do objetivo não é “blog compartilhado”. É “uma pequena biblioteca de componentes, mais um pouco de cola em cada site”. Assim que enquadrei dessa forma, o design ficou fácil.
Um pacote, duas paletas
vdaluz.com é um site claro/escuro com um destaque azul. imperfectsystems é preto com verde neon. Se os componentes compartilhados tivessem qualquer cor fixa no código, isso desmorona. Eles não têm. Cada componente referencia tokens de design em variáveis CSS como bg, surface, accent. O pacote nunca diz o que eles significam. Cada site define os valores no seu próprio CSS.
Esse é todo o truque. O mesmo PostCard renderiza azul-sobre-branco num site e verde-sobre-preto no outro, sem nenhum fork. Eu também tirei a dependência do tipo CollectionEntry<'blog'> do Astro, trocando por um tipo estrutural simples, então o pacote não se importa com o nome que cada site dá para sua coleção.
Duas formas como o CI me mordeu
O pacote builda localmente na primeira tentativa. Aí eu fiz push, e o CI falhou duas vezes por motivos que nunca aparecem no meu notebook.
Primeiro: uma dependência github:user/repo é reescrita pelo npm para uma URL git+ssh no lockfile. Até uma URL git+https explícita é reescrita. Minha máquina tem uma chave SSH, então clona sem problema. O runner do CI não tem, então o npm ci não conseguia buscar o pacote de jeito nenhum. O ajuste para um repositório público é pular o git por completo e depender de um tarball fixado: https://github.com/vdaluz/astro-blog/archive/refs/tags/v0.1.0.tar.gz. Https simples, anônimo, com um hash de integridade.
Segundo, e mais chato: eu regenerei o lockfile no meu Mac para resolver um conflito de merge. Isso silenciosamente escreveu só o build macOS do rollup no lockfile e descartou o Linux. No runner Linux do CI, o build morreu com Cannot find module @rollup/rollup-linux-x64-gnu. Isso é um bug conhecido do npm com dependências nativas opcionais. O ajuste foi restaurar o lockfile que estava correto e adicionar minha única dependência nova com npm install --package-lock-only, o que mantém os binários de toda plataforma em vez de reduzir para a minha.
A lição que continuo reaprendendo: um build verde na minha máquina não diz nada sobre um runner Linux sem chave SSH. Agora eu rodo npm ci && npm run build no node 22 antes de confiar num push.
Onde isso chegou
imperfectsystems.com/blog está no ar, renderizando pelo pacote compartilhado em pleno neon. vdaluz.com ainda tem sua própria cópia por enquanto, movê-lo para o pacote é o próximo passo. Dois sites, um conjunto de componentes, e algumas cicatrizes de CI para mostrar no caminho.
Leitura relacionada
Entregando um recurso de pacote compartilhado em dois repositórios para uma única rota
Um feed RSS que se dividiu num helper puro no pacote compartilhado e numa rota local por site, além da disciplina de release que uma dependência de tarball fixada por tag exige.
Testar um gate de deploy acabou fazendo o deploy da coisa que eu estava testando
Adicionando astro check e Prettier antes de cada deploy, um erro de tipo que o site irmão já tinha resolvido, e um gatilho manual de build sem nenhum conceito de dry run.
O deploy do Cloudflare Workers Builds que falhou por causa de um arquivo de config discordando de si mesmo
Substituindo o GitHub Actions morto pelo Workers Builds, uma flag --config que faltava e que o workflow antigo sempre teve, e o tipo de token que a API do Builds do Cloudflare se recusa a aceitar.
Você também pode achar útil
Proton Pass
Gerenciador de senhas focado em privacidade, da equipe por trás do Proton Mail.
Como parceiro da Proton, ganho com compras qualificadas dos serviços de privacidade e segurança da Proton (Pass, Mail, VPN, Drive).
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