Dynamic sitemaps in NuxtJS

6 min read
dynamic-sitemaps-in-nuxtjs

Sitemaps are a very important tool for SEO now. They help search engines direct their crawlers to the pages you want.

Sitemaps are a very important tool for SEO now. They help search engines direct their crawlers to the pages you want. Google defines sitemaps as below in their documentation.

“A sitemap is a file where you provide information about the pages, videos, and other files on your site, and the relationships between them. Search engines like Google read this file to crawl your site more efficiently.”

So now that we understand the importance of sitemaps, how can we implement them in our dynamic site? Let’s say you have a blogging site. You probably have an API or some kind of CMS that you use to fetch the blogs. After getting your data you will render it in your template. These pages are dynamically rendered and are built when a user visits them. This scenario works for most modern web frameworks now. With this approach comes the problem of how can I dynamically generate a sitemap for all my blog pages?

I built my site using NuxtJS in SSR mode. My solution when I faced this problem was NuxtJS server-side middleware. To use server middlewares in NuxtJS we create a serverMiddleware directory in the root of the project. After this, we create a sitemap directory to include all of the files needed for our sitemap middleware.

The first file in our sitemap directory is going to be index.js. This file is a basic express app initialization and bootstrapping.

const express = require('express') const app = express() const sitemap = require('./routes') app.use(sitemap) module.exports = { path: '/sitemap', handler: app }

In line 4 you can see I imported a routes.js file that will handle the routing of this express app.

import axios from 'axios' const { Router } = require('express') const router = Router() const { generateSitemap } = require('./parser') router.get('/.xml', function (req, res, next) { try { const sitemapIndex = [ { loc: 'https://dummy-domain.com', lastmod: '2021-11-04T07:23:16.040Z', priority: 1 }, { loc: 'https://dummy-domain.com/about', lastmod: '2021-11-04T07:23:16.040Z', priority: 1 }, { loc: 'https://dummy-domain.com/sitemap/blogs.xml', lastmod: '2021-11-04T07:23:16.040Z', priority: 1 } ] if (sitemapIndex) { res.setHeader('Content-Type', 'application/xml') res.send( generateSitemap(sitemapIndex, `https://${req.headers.host}`) ) } } catch (e) { next(e) } }) router.get('/blogs.xml', async function (req, res, next) { try { const { data } = await axios.get('https://api.dummy-domain.com/getAllBlogs') const sitemapIndex = [] data.forEach((blog) => { sitemapIndex.push({ loc: `https://dummy-domain.com/blog/${blog.slug}`, lastmod: blog.createdAt, priority: 0.8 }) }) if (sitemapIndex) { res.setHeader('Content-Type', 'application/xml') res.send( generateSitemap(sitemapIndex, `https://${req.headers.host}`) ) } } catch (e) { next(e) } })

So what this router does is, capture sitemap.xml and sitemap/blogs.xml and generate the sitemaps accordingly. For sitemap.xml we have two static pages that we want to index so we add those to the sitemapIndex. sitemap/blogs.xml is where the dynamic pages come in. I have an API where I fetch all blogs. After I get the blogs I loop all blogs and I build my sitemapIndex using the blogs slug and createdAt date. After building the sitemapIndex the next step is parsing this index into a proper XML format that GoogleBot recognizes.

const xmlHeader = '<?xml version="1.0" encoding="UTF-8"?>' module.exports = { generateSitemap (sitemap, host) { let xml = `${xmlHeader}<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:mobile="http://www.google.com/schemas/sitemap-mobile/1.0" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1">` sitemap.forEach((item) => { xml += `<url><loc>${item.loc}</loc><lastmod>${item.lastmod}</lastmod><priority>${item.priority}</priority></url>` }) xml += '</urlset>' return xml } }

So in parser.js I set up an XML from the loc, lastmod, and priority properties of the sitemapIndex. Now that we have our sitemap ready we have to include our server middleware in our nuxt config.

nuxt.config.js serverMiddleware: [ '~/serverMiddleware/sitemap' ]

And now we have a dynamic sitemap that changes whenever we add a new blog or delete it. We can now submit this sitemap in our google search console for google to discover our pages.

Disclaimer: You have to host your site in hosting services that support server-side rendering with NodeJS servers like Vercel for this to work.

Let me know if you have any questions or comments and see you in the next one. 😉

Comments (0)
No comments yet