ShipFast with Dynamic Sitemap

Adding Dynamic Sitemap to ShipFa.st

Step-by-step guide for replacing ShipFa.st default analytics integration with Google Analytics

This is the second step-by-step guide I’m publishing on how to enhance ShipFa.st (by Marc Lou), which has become my go-to boilerplate. ShipFa.st comes with an out-of-the-box support for blogging. It’s a great component that allows you to add content to your website (thus improving SEO) and provide move information to your customers.

What’s missing?

While the blogging feature of ShipFa.st is working great, it’s missing a key component – the various blog pages are missing from the Sitemap, making them less discoverable for search engines.

This step-by-step guide will help you solve that, and make sure your blog pages are all crawlable.

Adding a dynamic sitemap

We’ll start by implementing an endpoint/page that exposes a sitemap. Create a new file named route.ts in the /app/server-sitemap.xml folder, and add the following content::

// app/server-sitemap.xml/route.ts
import { ISitemapField, getServerSideSitemap } from 'next-sitemap'
import { categories, authors, articles } from "@/app/blog/_assets/content";
import config from "@/config";

export function GET(request: Request) {
  const result:ISitemapField[] = []

  categories.forEach(category => {
    result.push({ loc: `https://${config.domainName}/blog/category/${category.slug}`, changefreq: 'weekly', priority: 0.7, lastmod: new Date().toISOString() })
  });
  authors.forEach(author => {
    result.push({ loc: `https://${config.domainName}/blog/author/${author.slug}`, changefreq: 'weekly', priority: 0.7, lastmod: new Date().toISOString() })
  });
  articles.forEach(article => {
    result.push({ loc: `https://${config.domainName}/blog/${article.slug}`, changefreq: 'weekly', priority: 0.7, lastmod: new Date().toISOString() })
  });

  return getServerSideSitemap(result)
}

At this point, you should be able to access the endpoint http://localhost:3000/server-sitemap.xml (use the correct port, based on your dev environment), and see something like this:

Exposing the new sitemap

Once we’re done with the sitemap content, it’s time to make sure it’s discoverable. We’ll include it in the regular sitemap index (hosted at /sitemap.xml in your website), and we’ll also make sure that the endpoint itself doesn’t appear as a page in the “regular” sitemap. Open /next-sitemap.config.js and make the following changes:

module.exports = {
  ...
  exclude: [
    ...
    (process.env.SITE_URL || "https://shipfa.st/") + 'server-sitemap.xml', // <==== Add this
  ],
  robotsTxtOptions: {
    additionalSitemaps: [
      (process.env.SITE_URL || "https://shipfa.st/") + 'server-sitemap.xml', // <==== Add this
    ],
  },
};

Conclusion

To paraphrase George Berkeley:

If a blog post is written in a website, and no one is around to crawl it, was it ever written?

Make sure to expose any dynamic page you generate in your site – a good starting point is whenever you have a dynamic route, you probably need to dynamically generate your sitemap.