Created
July 6, 2020 18:42
-
-
Save derekbar90/5c056d5ae45c8032e1290db8ec72ae5f to your computer and use it in GitHub Desktop.
NextJS Dynamic Sitemap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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