Cómo generar un sitemap dinámico para tu web app con Sapper (Svelte)

¿Qué son los sitemaps?

Un sitemap es un anglicismo que significa «Mapa del sitio», es decir, un archivo o una url que contiene todas y cada una de las páginas de una web. En este artículo te voy a explicar porqué es tan importante generar uno, cómo debes crearlo correctamente y diferentes maneras de crear uno.

Según la definición de Google:

Los sitemaps son archivos en los que se proporciona información sobre las páginas, los vídeos y otros archivos de un sitio web, así como sobre las relaciones que hay entre ellos. Los buscadores, como Google, leen estos archivos para rastrear los sitios web de forma más eficaz. Los sitemaps informan a Google de qué archivos de un sitio web son importantes según el webmaster y, además, incluyen datos importantes sobre ellos; por ejemplo, en el caso de las páginas, pueden indicar cuándo se actualizaron por última vez, cada cuánto se modifican y si tienen versiones en otros idiomas.

Con un sitemap, además, vas a poder mantener actualizada la lista de enlaces que tiene la web y pasarsela a Google para que la rastree. Es un método muy sencillo y recomendable que tu página web tenga un sitemap.

¿Cómo generar un sitemap con Sapper?

Sapper es un framework hecho con Svelte ya preparado con un enrutamiento flexible basado en sistemas de archivos y SSR. Tal vez conozcas NuxtJS con Vue… pues lo mismo, pero para Svelte 😜

Estructura de un sitemap

Los sitemap se rigen mediante unos protocolos marcados por sitemaps.org, es decir, tienen una estructura concreta. Según estas directrices, un sitemap puede configurarse de la siguiente manera:

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>https://alextomas.com</loc>
    <lastmod>2021-01-25</lastmod>
    <priority>1</priority>
  </url>
  <url>
    <loc>https://alextomas.com/blog</loc>
       <lastmod>2021-01-19</lastmod>
    <priority>1</priority>

  </url>
</urlset>

Dentro de cada etiqueta encontramos cuatro etiquetas de información diferentes:

  • <loc>: URL de la página. Es una etiqueta de uso obligatorio.
  • <lastmod>: Indica la fecha de la última modificación textual o de programación en dicha url. Su uso no es obligatorio.
  • <changefreq> (opcional): Esta etiqueta indica la frecuencia en la que se realizan modificaciones textuales o de código en esa url.
  • <priority> (opcional): Indica en un rago de 0 a 1 la importancia que el webmaster atribuye a esa url en concreto respecto a la web en su conjunto.

Generar un sitemap de forma manual

La forma más sencilla de generar un sitemap en Sapper es haciéndolo de forma manual:

  1. Creas un fichero llamado sitemap.xml en la carpeta static.
  2. Escribes el listado de todos los links que quieras añadir con la siguiente estructura:
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>https://alextomas.com</loc>
    <lastmod>2021-01-25</lastmod>
    <priority>1</priority>
  </url>
  <url>
    <loc>https://alextomas.com/blog</loc>
    <lastmod>2021-01-19</lastmod>
    <priority>1</priority>
  </url>
</urlset>

Esto está bien si no te quieres complicar demasiado o bien tu página es estática y va a tener muy pocos enlaces. Pero… ¿y si tienes un blog que va a tener cientos de entradas? Este ha sido mi caso, mi blog tiene entradas dinámicas (aquí explico cómo generar un blog con Sapper y Markdown, pégale un vistazo).

Resulta que mantener un sitemap actualizado era un fastidio, además que podía equivocarme al escribir alguna ruta, por lo que podría pasarle a Google información errónea y demás. ¿Solución?

Generar un sitemap de forma dinámica

Es una forma un poco más elaborada para generar un sitemap en Sapper pero tampoco es nada de otro mundo. Sigue los siguientes pasos y verás que no tienes problemas:

  1. Creas un fichero en src/routes/sitemap.xml.js.
  2. El código para la generación dinámica del sitemap es el siguiente:
// Importo el listado de posts y los guardo en la variables 'posts'
// En el artículo mencionado antes explico su uso
import posts from './blog/_posts';
// Librería para darle formato a las fechas
import moment from 'moment';

const feed = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
    <url>
        <loc>https://alextomas.com</loc>
        <lastmod>2021-01-25</lastmod>
    </url>
    <url>
        <loc>https://alextomas.com/work-experience</loc>
        <lastmod>2021-01-19</lastmod>
    </url>
    <url>
        <loc>https://alextomas.com/blog</loc>
        <lastmod>2021-01-19</lastmod>
    </url>
    ${posts.map((post) => mountSchemaUrl(post)).join('')} </urlset
>`;
export function get(req, res) {
    res.writeHead(200, { 'Content-Type': 'application/rss+xml' });
    res.end(feed);
}
function mountSchemaUrl({ slug, date }) {
    return `
<url>
    <loc>https://alextomas.com/blog/${slug}</loc>
    <lastmod>${moment(date).format('YYYY-MM-DD')}</lastmod>
</url>
`;
}

Es muy sencillo de entender:

  1. Primero incluyo las páginas estáticas. En mi caso es la home, experiencia laboral y el blog. Que no van a cambiar de ruta nunca.
  2. Luego, recorro el array de posts y llamo a la función mountSchemaUrl que me devuelve la estructura necesaria para cada enlace del post.

¿Cómo puedo ver el sitemap generado?

Si estás en modo desarrollo (npm run dev) puedes acceder a la ruta http://localhost:3000/sitemap.xml y automáticamente verás tu estupendo sitemap.xml, algo como:

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>https://alextomas.com</loc>
    <lastmod>2021-01-25</lastmod>
  </url>
  <url>
    <loc>https://alextomas.com/work-experience</loc>
    <lastmod>2021-01-19</lastmod>
  </url>
  <url>
    <loc>https://alextomas.com/blog</loc>
    <lastmod>2021-01-19</lastmod>
  </url>
  <url>
    <loc>https://alextomas.com/blog/generar-sitemap-sapper-svelte</loc>
    <lastmod>2021-01-27</lastmod>
  </url>
  <url>
    <loc>https://alextomas.com/blog/deplegar-sapper-netlify</loc>
    <lastmod>2021-01-25</lastmod>
  </url>
  <url>
    <loc>https://alextomas.com/blog/estilos-con-svelte</loc>
    <lastmod>2021-01-24</lastmod>
  </url>
  <url>
    <loc>https://alextomas.com/blog/como-cambiar-ubicacion-nombre-capturas-mac</loc>
    <lastmod>2021-01-24</lastmod>
  </url>
  <url>
    <loc>https://alextomas.com/blog/atributos-dinamicos-en-svelte</loc>
    <lastmod>2021-01-22</lastmod>
  </url>
  <url>
    <loc>https://alextomas.com/blog/manejo-de-datos-con-svelte</loc>
    <lastmod>2021-01-21</lastmod>
  </url>
  <url>
    <loc>https://alextomas.com/blog/curso-de-svelte</loc>
    <lastmod>2021-01-20</lastmod>
  </url>
  <url>
    <loc>https://alextomas.com/blog/blog-svelte-sapper-markdown</loc>
    <lastmod>2021-01-18</lastmod>
  </url>
  <url>
    <loc>https://alextomas.com/blog/diferentes-cuentas-y-misma-clave-ssh-en-bitbucket</loc>
    <lastmod>2021-01-05</lastmod>
  </url>
  <url>
    <loc>https://alextomas.com/blog/que-es-svelte</loc>
    <lastmod>2021-01-04</lastmod>
  </url>
</urlset>

¡Enhorabuena, ya tienes tu sitemap dinámico en tu aplicación web con Sapper! 🚀

Problema al hacer export (deploy)

Cuando hagas el deploy y hagas un npm run export para generar las rutas seguramente tengas el mismo problema que tuve yo: La ruta al sitemap no me funcionaba, me daba un 404.

Solución:

En mi caso, añadiendo un enlace al sitemap en el footer fue suficiente. Al compilar, Sapper encuentra el enlace y genera el archivo sitemap.xml accesible. No se porqué pero sin el enlace me daba el error. 😭

Enviar tu sitemap directamente a Google

Para enviar tu sitemap a Google, primero deberás verificar tu sitio con el Google Search Console.

Para enviar tu sitemap:

  1. Selecciona tu sitio web en la consola de Google Search.
  2. Haz clic en Sitemaps en el menú a la izquierda.
  3. En el campo Añadir un sitemap, escribe la url de tu sitemap.xml (en mi casi https://alextomas.com/sitemap.xml).
  4. Haz clic en Enviar.

Enviar sitemap a Google desde Search Console

Y esto es todo. Espero que te pueda servir 🙃