Skip to content

Instantly share code, notes, and snippets.

@derekbar90
Created July 6, 2020 18:42
Show Gist options
  • Save derekbar90/5c056d5ae45c8032e1290db8ec72ae5f to your computer and use it in GitHub Desktop.
Save derekbar90/5c056d5ae45c8032e1290db8ec72ae5f to your computer and use it in GitHub Desktop.
NextJS Dynamic Sitemap
import { NextApiRequest, NextApiResponse } from 'next';
import { SitemapStream, streamToPromise, EnumChangefreq } from 'sitemap';
import { createGzip } from 'zlib';
import { readdir } from 'fs';
import { promisify } from 'util';
const asyncReaddir = promisify(readdir);
export default async (req: NextApiRequest, res: NextApiResponse) => {
req;
if (!res) return {};
try {
// Set response header
res.setHeader('content-type', 'application/xml');
res.setHeader('Content-Encoding', 'gzip');
// A Transform for turning a Readable stream of either SitemapItemOptions or url strings into a Sitemap.
// The readable stream it transforms must be in object mode.
const smStream = new SitemapStream({
hostname: `https://${process.env.HOST_NAME}`,
});
const pipeline = smStream.pipe(createGzip());
const files = await asyncReaddir('./pages');
const filteredFiles = files
.filter((name: string) => {
return (
// Make sure we leave out any folders until were ready to read slug based links
name.indexOf('.tsx') > -1 &&
// remove any template based files aka _app and _document
name.indexOf('_') !== 0 &&
// remove root as it's not at index in theory
name.indexOf('index') !== 0
)
})
.map((fileName: string) => {
const pageName = fileName.split('.');
return pageName[0];
})
//This part is a hack as we'll make the sitemap say the content has expired a couple hours prior to the request
var lastmod = new Date();
lastmod.setHours(lastmod.getHours() - 2);
// We removed index as it's root so let's be sure to add it to the sitemap
smStream.write({ url: '/', lastmod: lastmod, changefreq: EnumChangefreq.WEEKLY });
// next we'll go through all of the files that are in the pages directory and add each one
for(const fileName of filteredFiles) {
smStream.write({ url: `/${fileName}`, lastmod: lastmod, changefreq: EnumChangefreq.WEEKLY });
}
// Here is an example of where we create a sitemap.xml for some query in our graphql
// Create the client from with-apollo
// const client = createApolloClient()
// Do the query
// const stuff = await client.query(gqlQuery, {});
// Loop through everything and add it to the sitemap
// stuff.map(responseItem => {
// smStream.write({
// url: `/products/${responseItem.slug}`,
// lastmod: responseItem.updatedAt,
// changefreq: EnumChangefreq.WEEKLY,
// });
// });
// Important: Close the stream we are feeding and send it on it's way
smStream.end();
// cache the response
streamToPromise(pipeline);
// stream the response
pipeline.pipe(res).on('error', e => {
throw e;
});
} catch (e) {
res.status(500).end();
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment