TL:DR watch the video

So, you are SEO conscious and you want to make sure your sitemap.xml is fancy and complete. BUT. You have dynamic routes in your Nuxt project. Yikes! The documentation of @nuxt/sitemap explains:

"By default, the dynamic routes are ignored by the sitemap module. Nuxt cannot automatically provide this type of complex routes. If you want the module to add any route with dynamic parameters, you have to set an array of dynamic routes."

You can either hardcode all your routes or add an async function as the parameter for the routes. However, this is all little tedious or too much manual labor.

A quick example:

// nuxt.config.js
{
  sitemap: {
    hostname: 'https://timbenniks.dev',
    routes: [
      '/writings/low-carbon-websites-luxury-edition/',
      '/writings/i-rebuilt-my-website-again/'
    ]
  }
}

Or a little more complex:

// nuxt.config.js
{
  sitemap: {
    hostname: "https://timbenniks.dev",
    routes: async () => {
      const api = await Prismic.getApi("https://timbenniks.prismic.io/api/v2")
      const writings = await api.query(Prismic.Predicates.at("document.type", "writing"))
      return writings.results.map(writing => `/writings/${writing.uid}`)
    },
  },
}

If you want you can create fancy code to abstract this away but it's not the most fun job out there. You can explore a pretty involved approach in this article.

Enter: the Nuxt crawler

In Nuxt 2.13 the crawler was introduced. When running nuxt generate the crawler crawls (duh) all your pages to create their static representation. This means that somewhere in the magical box that is Nuxt there must be a reference to the newly generated pages and their urls. Why not get these URLs and give them to the sitemap module? This means no more complex code or manual labor to get your sitemap updated at build.

Leverage Nuxt hooks and the crawler to dynamically create your sitemap

First install the sitemap module. Once you have it in place configure it with some basic defaults:

// nuxt.config.js
{
  sitemap: {
    hostname: '<your-url>',
  }
}

When you run nuxt generate you will get a sitemap.xml file without any dynamic routes.

But, when you look at the generate output in your terminal you see that Nuxt actually knows about all pages in your project.

Nuxt generating pages
Nuxt generating pages

In order to grab the generated urls (which include the dynamic pages) we will create a Nuxt build module that uses Nuxt hooks and the generator class.

On to the code

Create a new file called sitemapRouteGenerator and put it in the modules folder. Reference it in the nuxt.config.js file.

// nuxt.config.js
{
  buildModules: [
    '@/modules/sitemapRouteGenerator'
  ]
}

The module will be used during the build, as the buildModules object suggests. In the sitemapRouteGenerator file we'll add the following code.

export default function () {
  this.nuxt.hook('generate:done', (context) => {
    const routesToExclude = [] // Add any route you don't want in your sitemap. Potentially get this from an .env file.
    const allRoutes = Array.from(context.generatedRoutes)
    const routes = allRoutes.filter(route => !routesToExclude.includes(route))

    this.nuxt.options.sitemap.routes = [...routes]
  })
}

In the module we hook into the generate:done event. After Nuxt is done generating the generate:done gives us a context variable. In this data we find the generatedRoutes Set. Now that we have all needed data, we make it into an Array, we filter out the routes we want to ignore and we give routes to the sitemap function.

DONE! That was easy wasn't it? Have any questions, please reach out to me on Twitter.

Props for this idea go to Andrey Gaisinskii.