Compartir un blog de Astro entre dos sitios
Faltaba un dev log en imperfectsystems.com. El blog que ya existe en vdaluz.com funciona bien, así que el movimiento obvio era reutilizar su código en vez de escribir uno segundo. “Reutilizar” resultó ser más interesante de lo esperado.
No se puede extraer un blog
El primer instinto fue “extraer el blog a un paquete.” Eso no existe realmente en Astro. Las rutas viven en src/pages/ y tienen que quedarse en cada app. El contenido es una carpeta de markdown por sitio. La configuración de Shiki, la de Tailwind, y el CSS del tema también son por app. Lo que realmente es portable es más chico de lo que suena: los componentes que renderizan una tarjeta de post, una barra de paginación, la lista de posts relacionados, más la función de puntaje y el schema de contenido.
Así que la versión honesta del objetivo no es “blog compartido.” Es “una pequeña librería de componentes, más algo de pegamento en cada sitio.” Una vez planteado así, el diseño se volvió fácil.
Un paquete, dos paletas
vdaluz.com es un sitio claro/oscuro con acento azul. imperfectsystems es negro con verde neón. Si los componentes compartidos tuvieran algún color escrito a fuego, esto se caería. No lo tienen. Cada componente hace referencia a tokens de diseño en variables CSS como bg, surface, accent. El paquete nunca dice qué significan. Cada sitio define los valores en su propio CSS.
Ese es todo el truco. El mismo PostCard se renderiza azul sobre blanco en un sitio y verde sobre negro en el otro, sin ninguna bifurcación. También se quitó la dependencia del tipo CollectionEntry<'blog'> de Astro a favor de un tipo estructural plano, así el paquete no le importa cómo cada sitio nombra su colección.
Dos formas en que el CI mordió
El paquete compila local a la primera. Después se hizo push, y el CI falló dos veces por razones que nunca aparecen en la laptop.
Primero: una dependencia github:user/repo es reescrita por npm a una URL git+ssh en el lockfile. Incluso una URL git+https explícita se reescribe. Esta máquina tiene una llave SSH así que clona sin problema. El runner de CI no la tiene, así que npm ci no podía traer el paquete de ninguna forma. El arreglo para un repo público es saltarse git por completo y depender de un tarball fijado a un tag: https://github.com/vdaluz/astro-blog/archive/refs/tags/v0.1.0.tar.gz. Https plano, anónimo, con un hash de integridad.
Segundo, y más traicionero: se regeneró el lockfile en la Mac para resolver un conflicto de merge. Eso escribió en silencio solo la build de macOS de rollup en el lockfile y descartó la de Linux. En el runner de CI con Linux, el build murió con Cannot find module @rollup/rollup-linux-x64-gnu. Es un bug conocido de npm con dependencias nativas opcionales. El arreglo fue restaurar el lockfile bueno conocido y agregar la única dependencia nueva con npm install --package-lock-only, que conserva los binarios de cada plataforma en vez de podar solo a la propia.
La lección que se repite: un build verde en la propia máquina no dice nada sobre un runner de Linux sin llave SSH. Ahora se corre npm ci && npm run build en node 22 antes de confiar en un push.
Dónde quedó
imperfectsystems.com/blog está en vivo, renderizando a través del paquete compartido en pleno neón. vdaluz.com todavía tiene su propia copia por ahora, moverlo al paquete es el siguiente paso. Dos sitios, un solo conjunto de componentes, y un par de cicatrices de CI para mostrar.
Lecturas relacionadas
Vaciar un backlog: cinco arreglos pequeños en una sola versión
Un arreglo de accesibilidad para una decoración muerta, un campo de esquema que validaba pero nunca se renderizaba, y una corrida de formateo que cambió en silencio el estilo de comillas en cuatro archivos.
El error de escape que solo aparece con un segundo parámetro de consulta
Una función de reescritura que funcionaba en cada prueba y cada URL real que había visto, y aun así se habría roto en el momento en que alguien agregara un segundo parámetro de consulta.
Probar la parte del código que documenta su propia trampa
Una advertencia en el README sobre un modo de fallo sutil es una confesión de que el código todavía no tiene pruebas para eso.