Generar slug en Gatsby

Hasta hace unos días, este sitio web corría sobre Drupal, por diferentes razones lo migre a Gatsby y lo moví de un servicio de hosting a Vercel, la experiencia ha sido muy buena, más que todo porque me ha permitido aprender.

Aparte del contenido, queria mantener sin varianción la URL de cada post, por la sencilla razón de que, los links a estos post continuen funcionando, como dice Chris Coyier URLs are the single greatest feature of the web.

Un pequeño problema que me encontré al migrar el contenido fue que, el slug default generado por Gatsby no se ajustaba a lo que necesitaba, porque los post los tengo agrupados por año, un folder por año, entonces las URLs me quedaban algo como <dominio>/<year>/<path> y necesitaba que fuera <dominio>/<category>/<path>

El slug

El slug ó path, es la pieza de la URL que identifica, en un formato amigable y de fácil lectura, la sección específica de un sitio web, por ejemplo, la URL completa de este post es https://leivajd.com/nota/generar-slug-gatsby, el slug es la última parte /nota/generar-slug-gatsby.

En un CMS es común poder personalizar el slug y es algo que damos por hecho. Con Gatsby, la generación del slug va a depender del data source que estemos usando, por ejemplo, si estamos usando algún tipo de headless CMS no hace falta generar el slug, como sí es necesario hacerlo cuando el contenido viene de archivos markdown.

Generar slugs

Todo el contenido de este sitio viene de archivos markdown, así que, necesite generar y personalizar los slugs de los posts para que coincidan con los originales. Un paso atrás antes de hablar más sobre slugs.

Gatsby permite generar secciones/pages de manera programatica, es decir, podemos hacer un query con GraphQL para obtener la data y relacionar esa data a un template específico, en este caso, el template de post; cómo crear páginas de manera programatica esta documentado y también es parte del tutorial paso a paso de cómo crear un sitio web con Gatsby.

El slug es fundamental, porque es la manera mediante la cual podemos acceder a ese contenido que generamos programaticamente. En la documentación se cubre el como generar slugs, y depende del plugin gatsby-source-filesystem, mismo que se usa en la configuración de consumir contenido desde archivos mardown.

Algunas opciones de como generar el slug cuando el contenido viene desde archivos mardown.

Agregar el slug en metadata

Posiblemente la manera más sencilla es, agregar el slug en la metada de cada archivo markdown, algo como:

---
slug: "/nota/generar-slug-gatsby"
date: "2020-05-24"
title: "Generar slug en Gatsby"
---

Y después consumir el slug, como se hace en la guía Adding Markdown Pages.

Usar onCreateNode para generar el slug

Podemos usar la función onCreateNode de gatsby-source-filesystem, la cual se ejecuta cuando se crea un node (en mi caso un post), y nos permite agregar un field nuevo. El ejemplo de abajo es de la documentación:

const { createFilePath } = require(`gatsby-source-filesystem`)

exports.onCreateNode = ({ node, getNode, actions }) => {
  const { createNodeField } = actions

  if (node.internal.type === `MarkdownRemark`) {
    const slug = createFilePath({ node, getNode, basePath: `pages` })

    createNodeField({
      node,
      name: `slug`,
      value: slug,
    })
  }
}

El ejemplo anterior hace lo siguiente:

  • se condiciona a que el slug se cree solo cuando el tipo del node es MarkdownRemark
  • se usa la funcion createFilePath para generar el slug basado en el path (ruta) del archivo. Por ejemplo, si la ruta del archivo es 2013/intro-sass.md, el método retorna algo como /2013/intro-sass/
  • se usa la funcion createNodeField para agregar el field slug al nodo que se esta creando

Usar los datos del node para generar el slug

Basado en el punto anterior, y usando la función onCreateNode se puede extraer del node la informacion que se necesite para armar el slug. En mi caso, la metada del markdown se ve algo asi:

---
path: "/generar-slug-gatsby"
date: "2020-05-24"
title: "Generar slug en Gatsby"
type: "nota"
tags: ["JAMstack", "Web"]
---

Y la implementación es algo como esto:

  • se condiciona a que el slug se cree solo cuando el tipo del node es MarkdownRemark
  • se extraen los fields (type y patch)
  • se usa la función createNodeField para agregar el field slug al nodo que se esta creando
exports.onCreateNode = ({ node, getNode, actions }) => {
  const { createNodeField } = actions

  if (node.internal.type === `MarkdownRemark`) {
    const type = node.frontmatter.type
    const path = node.frontmatter.path

    createNodeField({
      node,
      name: `slug`,
      value: `/${type}${path}`,
    })
  }
}

Para no olvidar:

Desarrollo y contenido por José David Leiva 2012 - 2020 / RSS