New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a Dynamic Sitemap example that works with the new Dynamic Routes #9051
Comments
@creativiii How are you currently using the |
@danielr18 I am not generating a static Sitemap on build, which is the suggestion I see a lot when googling, so I don't think this solution would work if that's what you're suggesting. Here's an amended version of my
This generates a sitemap with my base url, I then would loop through my desired routes to add other pages. These pages are dynamically generated from the information being pulled from Wordpress so they change fairly often. |
Also since I posted this a user on Spectrum shared their own solution. I never got around to testing it out since I realised that I also need a way to use |
I am making use of the new rewrites feature of NextJS v9.1.4 //next.config.js
experimental: {
modern: true,
async rewrites () {
return [
{source: '/sitemap.xml', destination: '/api/sitemap'},
]
},
catchAllRouting: true
}, Inside of import { SitemapStream, streamToPromise } from 'sitemap'
import { IncomingMessage, ServerResponse } from 'http'
export default async function sitemapFunc(req: IncomingMessage, res: ServerResponse) {
res.setHeader('Content-Type', 'text/xml')
try {
const stories = await fetchContentFromAPI() // call the backend and fetch all stories
const smStream = new SitemapStream({ hostname: 'https://' + req.headers.host })
for (const story of stories) {
smStream.write({
url: story.full_slug,
lastmod: story.published_at
})
}
smStream.end()
const sitemap = await streamToPromise(smStream)
.then(sm => sm.toString())
res.write(sitemap)
res.end()
} catch (e) {
console.log(e)
res.statusCode = 500
res.end()
}
} |
I wonder why my |
@sj-log |
@dohomi Which function did you use for your case? Should I use 'getInitialProps()' at there? |
@sj-log I think you misunderstand: you can do whatever suits your usecase in this function. It is nothing specific to NextJS, it simply returns an array of items and I just gave it the name |
@dohomi Well Thank you for the answer, but I really have no idea how to fetch backend or the service as you mentioned. |
@sj-log what backend do you need to call? I am using a headless CMS (Storyblok). You either can use the native |
@dohomi Perfect!!! Thanks a lot! What about:
|
@MihaiWill you will see this warning as soon you enable any of the |
@dohomi Dear friend, Just I've found another sitemap-generator for nextjs.
dohomi's way to implement is quite simple and good, However, If you still feel 'I don't know what to do' status, please check out the above link. The way I linked, is for a total beginner as easy as I can follow up. Good days. |
I've spent some time looking into this. I didn't want to mess with a custom server, or utilize rewrites. Here's where I landed. // pages/sitemap.xml.js
import React from 'react';
const EXTERNAL_DATA_URL = 'https://jsonplaceholder.typicode.com/posts';
const createSitemap = (posts) => `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${posts
.map(({ id }) => {
return `
<url>
<loc>${`${EXTERNAL_DATA_URL}/${id}`}</loc>
</url>
`;
})
.join('')}
</urlset>
`;
class Sitemap extends React.Component {
static async getServerSideProps({ res }) {
const request = await fetch(EXTERNAL_DATA_URL);
const posts = await request.json();
res.setHeader('Content-Type', 'text/xml');
res.write(createSitemap(posts));
res.end();
}
}
export default Sitemap; |
@leerob took a look at your blog post, really helpful! do you know what I would do to make a dynamic sitemap if my app creates blog post pages on the fly via [slug].tsx? For example, right now https://raskin.me/blog/init(blog) goes to my blog post, but it uses the template [slug].tsx to generate it. Currently the sitemap grabbed the actual "[slug]" name. |
@perryraskin I think you would need to slightly modify your script to look at your const pages = await globby(['posts/*.md', 'pages/**/*.tsx', '!pages/_*{.jsx,.tsx}']); That will fetch all your Markdown files. Then, you'd need to probably replace Give that a shot! |
@leerob nice, that worked great. the sitemap is still showing the [slug] though, should i remove it? i tried doing sitemap.replace but it does not seem to be having any effect |
@perryraskin You'll probably want to exclude the blog folder since you're handling it via const pages = await globby(['posts/*.md', '!pages/blog', 'pages/**/*.tsx', '!pages/_*{.jsx,.tsx}']); Another idea to consider: utilize Once SSG support lands, I'll probably update the blog post to include an example for that. This isn't directly related to your question about the sitemap, but I just figured I'd mention it 😄 |
|
@pspeter3 After reading the new docs, it seems like export async function getServerSideProps({res}) {
const request = await fetch(EXTERNAL_DATA_URL);
const posts = await request.json();
res.setHeader('Content-Type', 'text/xml');
res.write(createSitemap(posts));
res.end();
} |
@leerob Thanks! I'm able to get that to run but I end up with |
@pspeter3 The way I've gotten around that myself is using const sitemap = `
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${pages
.map((page) => {
const path = page
.replace('pages', '')
.replace('.js', '')
.replace('.mdx', '');
const route = path === '/index' ? '' : path;
return `
<url>
<loc>${`https://yoursitehere.com${route}`}</loc>
</url>
`;
})
.join('')}
</urlset>
`; |
Got it. I was actually commenting on something different. I was trying to use Next to generate a static file that does not have a |
@pspeter3 Ahh, sorry for the confusion there – my bad. I agree, I would open up a new issue and try and provide a solid example 👍 |
Added #11115 as the new issue |
Thank you @leerob for putting this together. The exact code wasn't working for me, but got it to work through some small edits (found here). Sharing in case anyone else ran into the same problem.
|
This is a cool hack! Will it work for exporting too? |
@pspeter3 Not sure! First time I tried this. |
@leerob what's the go with generating a sitemap like that for thousands, or even millions of posts? Would that be recommended or beneficial? |
@xaun If there are millions of posts, there are likely multiple sitemaps stitched together. |
@xaun have you tried #9051 (comment) ? It should work for your case as well. |
I have tried something very similar to what you are suggesting and succeded to get a sitemap working in my local machine for both dynamic and static routes but in prod it looks like static routes aren't generated in This is my attempt if it can help someone else, dbertella/cascinarampina@efdfea0#diff-2e0db62b38c8e7637d13c40a1a3034cb516d8899478112624a04b6f1f5c0abde I was thinking will this work in a function at build time and write a static xml file instead of having a ssr page? |
@dbertella that's what I suggest in #9051 (comment) if you want to try that out. |
Hey @BrunoBernardino yours is a good idea. I'm not super familiar with the whole node environment but if I understand correctly what you are doing the only difference with my script is that you generate the list of pages at build time and that's cool indeed. Regarding the lamda it seems you are using an older version of next, would it work the same if you put the function in the api folder? Also @now/node seems to be deprecated in case will it work the same with @vercel/node? The real question is if you move the lamda in the api folder would you still need to install the additional package? I will try to generate the list of static pages at build time btw, see if it work fine with my current implementation and let you know in any case. EDIT. That seems to works fine! Thanks for the tip. I'm running globby in a prebuild script and generate a page.json static file. Other than that the approach with a ssr page seems to work fine I made a PR with the needed changes here |
Awesome to hear it worked! I'm sure newer versions might need some tweaks, but should still work fine. |
I'm actually thinking at a different approach now and going static by default. The issue I have is that I'm trying to use es6 imports in a node.js script and it doesn't like it very much, but I'd probably go back to it when I have time to try to figure it out this is my next attempt https://github.com/dbertella/cascinarampina/pull/9/files |
Hi all 👋🏼 I am currently exploring the possibility of using the My site has a lot of dynamic content, and it would be a heavy / expensive job to dynamically generate a From what I am finding, this will probably require a custom server and / or a custom document. **My first attempt writing a custom document**I exported a
import { GetStaticProps } from "next";
...
/**
* Get static page properties
*
* @param GetStaticPropsContext props
* @return Object
*/
export const getStaticProps: GetStaticProps<SitemapProps> = async () => {
return {
revalidate: 60 * 60 * 24, // 1 day
props: {
nonHtmlDocument: true,
},
};
};
...
import Document from "next/document";
class MyDocument extends Document<{ nonHtmlDocument?: boolean }> {
static renderDocument(document, props) {
return props?.__NEXT_DATA__?.props?.pageProps?.nonHtmlDocument ? (
<>{props?.html}</>
) : (
super.renderDocument(document, props)
);
}
render() {
return this.props?.__NEXT_DATA__?.props?.pageProps?.nonHtmlDocument ? (
<>{this?.props?.html}</>
) : (
<Document {...this.props} />
);
}
}
export default MyDocument; Issues with my attempt:
Does anybody have any ideas? |
Is there a particular reason why you've chosen getStaticProps over an /api route like was suggested here: #9051 (comment)? We've been happy with an /api/sitemap.ts route + a /sitemap.xml => /api/sitemap.xml rewrite + https://vercel.com/docs/edge-network/caching#stale-while-revalidate. It feels less of a hack than trying to turn a react page into a sitemap. |
@lkbr
My main concern was with incremental static regeneration, but I was oblivious to how that was implemented with the Knowing this, I see that my CDN does support the Thank you 🙏🏼 |
tips from everyone here really helped me. Here is how I did this with contenful CMS. This works with incremental static generation as well
|
I implemented @leerob solutions and it works however it's a bit hacky. Is there any plan for NextJS to have a better sitemap solution? There should be an official recommendation on sitemap generation in the docs because it's quite common. I've moved to NextJS mostly because of SEO. So supporting SEO use cases like sitemap generation are very important to me. |
I was recently browsing through the NextJS The approach implements a sitemap generation script that outputs a static I plan to implement a similar sitemap generation script in my project and run it via a cron job (vs on build). This way, I will have more control over when the sitemap is generated & do not have to rely on any cache headers (like in my previous approach). |
@loganstellway that's an interesting idea. If you need dynamic content (that might not exist at build time), you could consider the solution I have in this example repo. |
Tried using functions to generate sitemap, however my generated sitemap is huge so i cannot generate it with lambda. Is there other option of generating sitemap at build / call? Any help would be appreciated! |
@jupardo have you tried the solution I've suggested above? |
We are adding official docs on sitemaps, please leave any feedback there! 🙏 P.S. I was going to clean this up and remove outdated solutions, but I'll leave it for posterity. Again, please share any and all feedback on the PR for adding this to the docs - Thank you! |
Example request
Up until now I've been using a custom Express server with next-routes to handle all my routing. I'm very excited to upgrade and finally move to the Dynamic Routing that was introduced with NextJS 9.
That said, a key part of my site is the Sitemap. At the moment it's very easy for me to have one thanks to my custom
server.js
and the sitemap package however I am completely lost on how to achieve this with dynamic routing.I'm not sure if this would be considered out of scope for NextJS, but Sitemaps are essential for websites and its unfortunate that deciding to use a great feature like Dynamic Routing means that I'd have no obvious way of creating one.
An example showing how to use the existing Sitemap NPM Package would be fantastic, but any solution would work.
I've tried my best to get it to work but haven't gotten anywhere so far.
The text was updated successfully, but these errors were encountered: