11 Jan, 2023
5 min read
I was asked by my organization to generate a sitemap for the application we were building. It took me a whole week of research and trying out different things before I was able to successfully get it done. So I've decided to save others the trouble by providing a pretty easy solution that works both in production and development mode.
A sitemap shows the pages and routes on a website. It is a map of the URLs on your site that makes it easier for search engines to index your content, increasing the likelihood of ranking in search results.
Search engines like Google read this file to crawl websites, so if you are interested in making your website more SEO friendly, It is rather important to have a sitemap file.
Now let's get to it.
If you already have your Nextjs application ready, navigate to the pages directory, and create a sitemap.xml.tsx file in the root of the directory as so.
In this file, we are going to write a piece of code that generates an XML file which we can see when we navigate to localhost:3000/sitemap.xml.
src/sitemap.xml.tsx
import { NextApiResponse } from "next";
import { adPaths } from "../utils/sitemap/ad";
import { categoryPaths } from "../utils/sitemap/category";
import { dashboardPath } from "../utils/sitemap/dashboard";
import { sellPath } from "../utils/sitemap/sell";
const Sitemap = () => {
return null;
};
const dashboardpath = dashboardPath();
const sellpath = sellPath();
;
export const getServerSideProps = async ({ res }: { res: NextApiResponse }) => {
const adpaths = await adPaths();
const categorypaths = await categoryPaths();
//spreading adPaths and categoryPaths into allPaths array
const allPaths = [
...adpaths,
...categorypaths,
dashboardpath,
sellpath,
];
const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
{" "}
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
$
{allPaths
.map((url) => {
return `
<url>
<loc>${url}</loc>
<lastmod>${new Date().toISOString()}</lastmod>
<changefreq>monthly</changefreq>
<priority>1.0</priority>
</url>
`;
})
.join("")}
</urlset>
`;
res.setHeader("Content-Type", "Text/xml");
res.write(sitemap);
res.end();
return {
props: {},
};
};
export default Sitemap;
In the snippet above we made use of NextJS getServerSideProps This is because we want this file to be pre-rendered before being called on the client (browser) for better SEO.
Note that allPaths array is a concatenation of other arrays, which contains our dynamic and static paths.
Let us take a look at what is in adPaths as an example for generating a dynamic file. Note that this file can be in your utils directory outside pages, for the purpose of writing cleaner code.
// adPaths.tsx
import { Api } from "services/Api";
import { IdType } from "types/types";
const BASE_URL = "https://localhost:3000";
export const adPaths = async () => {
const allAdsResponse = await Api.staticIds.getAdIds(); // can be any api call
const ads = allAdsResponse?.data?.data as IdType[];
const paths = ads?.map((staticPagePath) => {
return `${BASE_URL}/ad/${staticPagePath.slug}`; //returning all the dynamic paths
});
return paths;
};
We made an async function that makes an API call and returns an array of data, which we then map returning what would be our list of dynamic paths for ads.
Now let's take a look at sellPath as an example for generating a static file path.
// sellPath.tsx
const BASE_URL = "https://localhost:3000";
export const sellPath = () => {
return `${BASE_URL}/sell.html`;
};
This file simply returns the file path for that file.
which brings us back to our sitemap.xml.tsx file where we have all our paths concatenated to our allPaths array using the spread operator
import { NextApiResponse } from "next";
import { adPaths } from "../utils/sitemap/ad";
import { categoryPaths } from "../utils/sitemap/category";
import { dashboardPath } from "../utils/sitemap/dashboard";
import { sellPath } from "../utils/sitemap/sell";
const Sitemap = () => {
return null;
};
const dashboardpath = dashboardPath();
const sellpath = sellPath();
//calls our api on the serverside, and enables pre rendering of the data before the client is loaded
export const getServerSideProps = async ({ res }: { res: NextApiResponse }) => {
// triggers the api call
const adpaths = await adPaths();
const categorypaths = await categoryPaths();
//spreading adPaths and categoryPaths into allPaths array
const allPaths = [
...adpaths,
...categorypaths,
dashboardpath,
sellpath,
];
const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${allPaths
.map((url) => {
return `
<url>
<loc>${url}</loc>
<lastmod>${new Date().toISOString()}</lastmod>
<changefreq>monthly</changefreq>
<priority>1.0</priority>
</url>
`;
})
.join("")}
</urlset>
`;
res.setHeader("Content-Type", "Text/xml");
res.write(sitemap);
res.end();
return {
props: {},
};
};
export default Sitemap;
Feel free to reach out to me if you're looking for a developer, have a query, or simply want to connect.