OUTDATED! NEW WAY: https://emilpriver.com/blog/sitemap-with-nextjs-after-9-4-update
Originally written at: My website
So, Nextjs is really hyped and a really good framework for developing. Nextjs is shiped with alot of stuffs, but not an generated sitemap (Which i understand is not added by default in Nextjs).
This is 1 way to create an dynamic sitemap without creating a server to handle Nextjs and use getInitialProps instead as normal pages does.
URL
I wanted to be able to use /sitemap.xml as its a standard for sitemaps.
By testing out different type of filename did i later on understand that you are able to use
sitemap.xml.js
as name and it will be rendered when entering /sitemap.xml in your browser.
Something we will use in this small article.
Developing the XML feed.
Create a new file in pages/ folder in your projects map, the name of the file will be used when you want to access your sitemap.
import React from "react";
import axios from "axios";
const sitemapXML = data => {
let latestPost = 0;
let projectsXML = "";
data.map(post => {
const postDate = Date.parse(post.modified);
if (!latestPost || postDate > latestPost) {
latestPost = postDate;
}
const projectURL = `https://domain.ltd/project/${post.slug}/`;
projectsXML += `
<url>
<loc>${projectURL}</loc>
<lastmod>${postDate}</lastmod>
<priority>0.50</priority>
</url>`;
});
return `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://domain.ltd/</loc>
<lastmod>${latestPost}</lastmod>
<priority>1.00</priority>
</url>
<url>
<loc>https://domain.ltd/about/</loc>
<priority>0.80</priority>
</url>
${projectsXML}
</urlset>`;
};
First part of the code.
Here we create the XML feed with dynamic data.
We have some statics paths which is / and /about which we add manually.
but we also have some dynamic data, in my case is the dynamic data all my projects. So in the code do we loop thrue all my projects from an external source and add xml data to a variable which we later on uses to display the data.
class Sitemap extends React.Component {
static async getInitialProps({ res }) {
const data = await axios
.get(
"https://domain.ltd/some/url/"
)
.then(response => response.data);
res.setHeader("Content-Type", "text/xml");
res.write(sitemapXML(data));
res.end();
}
}
export default Sitemap;
In the last part do we use axios to fetch data from an api. This works exactly the same way we do normally fetch data when using SSR with Next.JS.
But instead of using render() or return() do we directly send the XML feed to the client. So now we have working XML feed which is rendered SSR and ready when you need it.
And exempel using the method is my website: https://priver.dev/sitemap.xml
Github GIST if you want to copy the code
Hope this helps you :D
Top comments (25)
Thanks for this Emil, very useful.
I'm just updating my app to take advantage of the new next getStaticProps feature, so I can render my sitemap.xml as a static page at build time, rather than generating it on the server every time.
Do you have any thoughts about how to achieve this ? the res object is not available in getStaticProps, so I can't find a way to serve the xml directly to the client as you do above without rendering it in a page component at which point it ceases to be an xml and appears as a string. Any suggestions?
For sitemap I dunno. But for the
rss.xml
I just added this inside thegetStaticProps
of my/blog
page:I dunno if is a good way, but it works 🤷♂️
Maybe with sitemap is it possible to do something similar?
Thanks, I hadn't thought of that. I'll give it a try.
Any luck with this? I am currently working through the same issue.
I got it working locally fine but not yet pushed to server (I'm using vercel now). Not sure if that allows fs.writes.
Will report back when I've pushed to the server in the next few days.
I use fs.writes but I added on webpack finally...
Thanks!
I tried your solution but do you know how to implement it when you are using Typescript? i need to import existing logic to get data that is written in TS
The
next.config.js
file hasjs
extension. So looks difficult to use TypeScript here. One thing you can do is compile next.config.ts to next.config.js: github.com/vercel/next.js/issues/5...Hi ! great article thank you Emil. I implemented this post my next project it is working dev server but it fails in production. Why it is ? saalla.com/sitemap.xml . this my site. i dont see any error info at console. it just catch 500
Hard for me to help you with a link. I recommend to check logs at Vercel :)
Have you ever encountered an error like this before? maybe it is related to next.config.js
No I have not :/ I recommend to try other solutions as Next have new functions now, I am talking about getServerSidedProps for exempel ☺️
thank you for replies. i ll look them :)
Thanks for this method, i used another one which had to take advantage of experimental features, you could better this code using the sitemap package. eg;
@ook0 I agree with mark in using the sitemap package because it is typesafe and also has this possibility npmjs.com/package/sitemap#create-s...
My goal was to use as less packages as needed, there for didn`t I use sitemap package. But I think sitemap package is a better solution
Yes, I thought as much, I believe it's rather a choice of preference, thanks for the very informative post, both methods work great and in the end, it only comes down to a fight for bytes :)
BTW, here is the method I previously used, github.com/zeit/next.js/issues/905...
as you can see it has to leverage experimental features which are never good in a production env, so thanks for your method, I will be switching all my deployments to this method
and if you would like to go a step further, I included robots using the same method.
Hey Emil,
Thanks for the article it's really helpful. the link to your blog has 404.
Thank you :D I've changed the url
Nice, I will combine this approach with the npm sitemap package npmjs.com/package/sitemap to generate the XML
Hello Mark, why you need "sitemap" package?
Thanks for this Emil, it is clearly. But i got an error in production like this.
[GET] /sitemap.xml
21:12:35:81
2020-07-17T18:12:35.996Z 022e5e7d-a417-40ba-84c0-66ba45030366 ERROR TypeError: Cannot assign to read only property 'undefined' of object '#'
at getServerSideProps (/var/task/.next/serverless/pages/sitemap.xml.js:10268:13)
at renderToHTML (/var/task/node_modules/next/dist/next-server/server/render.js:37:200)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at async renderReqToHTML (/var/task/.next/serverless/pages/sitemap.xml.js:4554:22)
at async render (/var/task/.next/serverless/pages/sitemap.xml.js:4601:22)
it tried it getinitialprops and getserversideprops . i shared screenshot
OMG.... finally a tutorial simple and objective! Thank you very much!
I'm happy it helps :D
I am very interested in your job.
I am a Next JS expert.
I want to work with you. Thanks