Generar un sitemap XML dinámico en Nextjs 13.

Tener un sitemap de tu sitio en el que se informe a los motores de búsqueda de todas y cada una de las URL indexables de tu sitio siempre es una buena idea. Si bien no es un requisito indispensable ni carecer de él conlleva la más mínima penalización en el SEO si que es cierto que los motores de búsqueda indexarán con más velocidad tu sitio y además en el caso de tener sitios con muchas URL o que estas sea vayan generando según introducimos contenido, como por ejemplo un blog, no corremos el riesgo de que los motores de búsqueda dejen de indexar algunas URL a las que no hayan podido llegar.

También es cierto que generar sitemap.xml, sobre todo si no tenemos ningún script que automatice el proceso o tu sitio no está en un CMS como wordpress que ofrecen plugins para poder generar estos sitmaps y tu sitio genera nuevas páginas en función del contenido que se va creando es una tarea tediosa ya que cada vez que añadimos contenido nos veríamos obligados a incluir la nueva URL manualmente. Yo personalmente he realizado decenas de scripts para generar los sitemap, pero incluso hacer el script es una pérdida de tiempo que muchas veces no queremos llevar a cabo.

Con NextJs la cosa no cambiaba mucho y nos obligaba a realizar un script para generar un string con el con todas las URL de nuestro sitio que después devolvíamos con un "content-type": "application/xml". No es que fuera muy complicado pero desde el lanzamiento de la versión 13.3 de NextJs aun nos lo han puesto más sencillo.

Para ello, si utilizamos la carpeta app para generar nuestra aplicación, tan solo tendríamos que crear dentro de la raiz un archivo llamado sitemap.js y exportar un función por defecto que devuelve un array de objetos con las URL de nuestro sitemap.

// app/sitemap.js

export default function sitemap() {
    return [
        {
            url: "mysite.com",
            lastModified: new Date()
        },
        {
            url: "mysite.com/about",
            lastModified: new Date()
        },
        {
            url: "mysite.com/contact",
            lastModified: new Date()
        }
    ];
}

Así de simple, ahora si visitamos mysite.com/sitemap.xml veremos nuestro sitemap creado correctamente. Pero supongamos que tengamos un blog y tenemos que ir añadiendo todas las URL de cada post que añadimos. En este caso, tambien podemos exportar una función asíncrona en la que antes de devolver el resultado llamamos a nuestra api para extraer todos los posts:

// app/sitemap.js

export default async function sitemap() {
    // Static pages
    const siteMap = [
        {
            url: "mysite.com",
            lastModified: new Date()
        },
        {
            url: "mysite.com/about",
            lastModified: new Date()
        },
        {
            url: "mysite.com/contact",
            lastModified: new Date()
        }
    ]

    // Fetch all posts
    const response = await fetch(`mysite.com/api/posts/get`);
    const json = await response.json();
    const posts = json.result.posts;

    // Generate
    posts.forEach(post => {
        siteMap.push({
            url: `mysite.com/post/${post.slug}`,
            lastModified: new Date(post.date)
        });
    });

    return siteMap;
}

Con algo así de simple podemos generar un sitemap con todos nuestros posts, cada vez que motor de búsqueda visite en nuestro sitio mysite.com/sitemap.xml verá el sitemap con todas las URL que tienen que ser indexadas siempre actualizado.