Migrando mi blog a Astro

Migrando mi blog a Astro

Empecé a escribir entradas de blog alrededor de 2010 primero bajo el paraguas de mi empresa Opsou, más tarde en 2018 sentí la necesidad de escribir y compartir mi experiencia y aprendizaje durante el tratamiento de mi cáncer, (1, 2, 3 y me encanta esta sobre el día que fui radiactivo ☢) y este tipo de posts no encajaban en un blog corporativo y técnico, así que creé este blog personal.

Para esa primera iteración, decidí usar Hexo, un generador de sitios estáticos basado en Node.js. Esta fue una buena elección en su momento porque facilitaba la escritura de posts en Markdown y ofrecía muchos temas y plugins para personalizar el blog. En este periodo cambié el tema visual un par de veces.

Blog 2019

En 2022, decidí probar una nueva herramienta de generación de sitios estáticos, Hugo, que está escrita en Go, un lenguaje que me gusta.

Blog 2022

Hugo es agradable y rápido, pero no me gusta el sistema de plantillas. Creo que no es muy legible ni intuitivo. Pienso que eso se puede solucionar dedicando más tiempo a aprender el sistema de plantillas, pero para mí no vale la pena, así que después de cambiar el tema una vez más, decidí probar algo nuevo.

Astro

Astro es bastante diferente de las herramientas anteriores, no es un generador de sitios estáticos, es un framework para construir sitios estáticos. Hexo y Hugo proporcionan todas las características y comportamientos que necesitas para crear un blog de serie y hay una separación clara entre el contenido y el tema, pero Astro es un framework que te permite hacer lo mismo que Hexo y Hugo, pero también te permite crear sitios más complejos, aunque requiere más trabajo para configurar el blog.

Problemas, soluciones y aprendizajes

Lo primero que hice fue mover todo el contenido de Hugo a Astro. La migración inicial fue muy sencilla, simplemente copié el contenido de la carpeta content en Hugo a la carpeta src/content en Astro, con eso ya tenía todo el contenido en el nuevo blog con las funciones básicas.

Contenido enriquecido

Pero como mi blog tenía algunos shortcuts, por ejemplo para incrustar vídeos de YouTube, iframes de code sandbox, Spotify, relaciones entre posts, etc… Esos shortcodes estaban muy acoplados a Hugo y necesitaba encontrar una manera de migrar ese contenido también en Astro.

No quería simplemente crear los mismos shortcuts para Astro y tener el mismo problema en el futuro si volvía a cambiar el motor del blog.

Investigué la sintaxis extendida de markdown y, como Astro utiliza remark para parsear el markdown, Remark tiene muchos plugins para extender la sintaxis de markdown, y uno me resultó muy interesante y útil: Remark directive. Este plugin te permite crear directivas personalizadas en el markdown, por ejemplo:

::youtube[]{id="oXgJ5cmOGQk"}\

:astro-ref[another post](/blog/2022/2022-12-31-2022-in-a-nutshell) # This is a ref to another post in the blog using the real path but it will use the slug

::spotify[]{id="3InlshVKFSitTRj76hUjyB"}

::iframe[]{src="https://codesandbox.io/embed/sergiocarracedo/vue-use-model-helpers?fontsize=14&hidenavigation=1&theme=dark" height="500px" width="100%"}

::asciinema[]{id="1234567"}

Y crear un plugin para reemplazar esta directiva con un componente de Astro personalizado; en el primer caso, un componente para incrustar YouTube es muy sencillo:

/**
 * Remark plugin to replace ::youtube[DESCRIPTION](#YOUTUBEID): with a custom YouTube embed Astro component.
 */
export function remarkDirectiveYoutube() {
  return (tree, file) => {
    visit(tree, ['textDirective', 'leafDirective', 'containerDirective'], (node) => {
      if (node.name !== 'youtube') {
        return
 }

      const data = node.data || (node.data = {})
      const attributes = node.attributes || {}
      const id = attributes.id


      if (node.type === 'textDirective') {
        file.fail(
          'Unexpected `:youtube` text directive, use two colons for a leaf directive',
          node
 )
 }

      if (!id) {
        file.fail('Unexpected missing `id` on `youtube` directive', node)
 }

      node.type = 'mdxJsxFlowElement';
      node.name = 'YoutubeEmbed';
      node.attributes = [
 { type: 'mdxJsxAttribute', name: 'id', value: id }
 ];
      node.children = [];
 });
 }
}

Puedes consultar las otras directivas que creé aquí

Migrando los shortcuts en el contenido

Esta fue la parte fácil de la migración de shortcuts, la parte aburrida y difícil fue migrar los usos, encontrarlos y cambiar el código. Para esto, usé GitHub Copilot en modo agente con un prompt como este:

Find all the uses of {{< youtube XXXXX >}} in the markdown files in `content/blog`and replace it with ::youtube[]{id="XXXXX"}

Funcionó, pero la IA olvidó algunos casos de uso, así que tuve que preguntar de nuevo: Please review all the content again to be sure all the shortcodes were migrated y encontró los que faltaban y los migró.

También usé la IA para migrar el formato del frontmatter de todos los posts, ya que hay cosas que no son fáciles de hacer con regex, como eliminar el prefijo de fecha que tenía en algunos posts, de 2020/12/01/my-post a my-post.

Tailwind CSS

No soy un gran fan de Tailwind, pero quería forzarme a usarlo en un proyecto en el que tuviera todo el control. El tema anterior que usé en Hugo estaba basado en scss para tener reutilización y modularidad, pero Astro se basa en componentes en lugar de fragmentos HTML, esto facilita delegar la reutilización en los componentes en lugar del CSS, haciendo de Tailwind una buena opción para este caso.

Aun así, quiero tener algunas clases de utilidad, así que creé un archivo de configuración de Tailwind personalizado para añadir algunas clases de utilidad que uso en el blog, como link, background, etc… y algunos colores personalizados.

Conclusión

Estoy muy contento con el resultado, tengo un blog que es fácil de mantener y lo suficientemente flexible como para añadir nuevas características en el futuro, principalmente visuales. Espero que os guste, y si encontráis algún problema o tenéis alguna sugerencia, por favor házmelo saber.