Dynamically generate sitemap.xml
Answered
Giant panda posted this in #help-forum
Giant pandaOP
Can I not have a folder called sitemap.xml and a route.ts inside of it?
If the folder is called sitemap (without .xml) the route.ts works. However, if it's with the .xml it gives a 404
Also, this (https://nextjs.org/docs/app/api-reference/file-conventions/metadata/sitemap#generate-a-sitemap) is not enough, as it seems to only work in the root directory. I have a multi-tenant application, so I need multiple sitemaps
If the folder is called sitemap (without .xml) the route.ts works. However, if it's with the .xml it gives a 404
Also, this (https://nextjs.org/docs/app/api-reference/file-conventions/metadata/sitemap#generate-a-sitemap) is not enough, as it seems to only work in the root directory. I have a multi-tenant application, so I need multiple sitemaps
32 Replies
Ocicat
hey @Giant panda there is no
https://nextjs.org/docs/app/api-reference/functions/next-response#json
If it was then I guess this would be possible.
NextResponse.xml() in the route configuration:https://nextjs.org/docs/app/api-reference/functions/next-response#json
If it was then I guess this would be possible.
@Ocicat hey <@131537558453747712> there is no `NextResponse.xml()` in the route configuration:
https://nextjs.org/docs/app/api-reference/functions/next-response#json
If it was then I guess this would be possible.
Giant pandaOP
I think you misunderstand - The route won't even trigger a console.log. It's not about returning a response
@Ocicat hey <@131537558453747712> there is no `NextResponse.xml()` in the route configuration:
https://nextjs.org/docs/app/api-reference/functions/next-response#json
If it was then I guess this would be possible.
Giant pandaOP
I wouldn't need a NextResponse.xml, I can just return it like so:
return `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="https://www.sitemaps.org/schemas/sitemap/0.9">
<!--We manually set the two URLs we know already-->
<url>
<loc>${URL}</loc>
</url>
<url>
<loc>${URL}</loc>
</url>
<url>
<loc>${URL}</loc>
</url>
${posts
.map(({ id }) => {
return `
<url>
<loc>${`${URL}/${id}`}</loc>
</url>
`
})
.join('')}
</urlset>
`
}@joulev idk it works fine for me?
<https://github.com/joulev/debug/tree/nextjs-dynamic-sitemap-1125712788279541871>
<https://debug-git-nextjs-dynamic-sitemap-1125712788279541871-joulev.vercel.app/test/sitemap.xml>
Giant pandaOP
That's weird.. Wondering if it could have something to do with my middleware then
Ocicat
what is the encoding of this? is it
text/xml?you could check by inspecting the response headers
dont even need to check the encoding; simon said a route containing
sitemap.xml cannot work on his machine so i demonstrated by making a route containing sitemap.xml work just like intendedif you want text/xml you can always add the headers
@joulev idk it works fine for me?
<https://github.com/joulev/debug/tree/nextjs-dynamic-sitemap-1125712788279541871>
<https://debug-git-nextjs-dynamic-sitemap-1125712788279541871-joulev.vercel.app/test/sitemap.xml>
Giant pandaOP
https://nextjs.org/docs/app/api-reference/file-conventions/metadata/sitemap#generate-a-sitemap Does this also work in non-root folders for you joulev?
@joulev haven't checked but idt i need to
Giant pandaOP
Ah
Giant pandaOP
Sad
anyway just make a route handler that returns the sitemap.xml content with text/xml...
it works fine
Giant pandaOP
I don't see anything sus in my middleware that would prevent me from having .xml in a route
export default withClerkMiddleware((req: NextRequest) => {
const url = req.nextUrl
// Get hostname of request (e.g. demo.vercel.pub, demo.localhost:3000)
const hostname = req.headers.get('host') || 'demo.useverk.com'
// Get the pathname of the request (e.g. /, /about, /blog/first-post)
const path = url.pathname
if (path.startsWith('/api')) {
return NextResponse.next()
}
const currentHost =
// eslint-disable-next-line turbo/no-undeclared-env-vars
process.env.NODE_ENV === 'production' && process.env.VERCEL === '1'
? hostname.replace(`.useverk.com`, '')
: hostname.replace(`.localhost:3000`, '')
// rewrites for app pages
if (currentHost == 'app') {
if (isPublic(req.nextUrl.pathname)) {
url.pathname = `/app${url.pathname}`
return NextResponse.rewrite(url)
}
const { userId } = getAuth(req)
if (!userId) {
const signInUrl = new URL('/sign-in', req.url)
signInUrl.searchParams.set('redirect_url', req.url)
return NextResponse.redirect(signInUrl)
}
url.pathname = `/app${url.pathname}`
return NextResponse.rewrite(url)
}
// rewrite root application to `/home` folder
if (
hostname === 'localhost:3000' ||
hostname === 'useverk.com' ||
hostname === 'www.useverk.com' ||
hostname === 'www2.useverk.com' ||
hostname.endsWith('vercel.app')
) {
return NextResponse.rewrite(new URL(`/home${path}`, req.url))
}
// rewrite everything else to `/_sites/[site] dynamic route
return NextResponse.rewrite(
new URL(`/sites/${currentHost}${path}${req.nextUrl.search}`, req.nextUrl)
)
})@joulev does removing it fix the problem?
Giant pandaOP
Can't remove the middleware - Debugging on demo.localhost:3000 - Which this part handles:
But I'll try debugging in some other ways, appreciate it
But I'll try debugging in some other ways, appreciate it
// rewrite everything else to `/_sites/[site] dynamic route
return NextResponse.rewrite(
new URL(`/sites/${currentHost}${path}${req.nextUrl.search}`, req.nextUrl)
)@Giant panda Can't remove the middleware - Debugging on demo.localhost:3000 - Which this part handles:
But I'll try debugging in some other ways, appreciate it
ts
// rewrite everything else to `/_sites/[site] dynamic route
return NextResponse.rewrite(
new URL(`/sites/${currentHost}${path}${req.nextUrl.search}`, req.nextUrl)
)
yeah as in, of course removing the middleware will completely break your app. but at least does
/path/to/sitemap.xml work in that case?just suggesting in case it is not a middleware bug so you could be wasting time debugging it
Giant pandaOP
Right, yeah, I'll give it a go
Yeah, it did
That works
well... good luck debugging the middleware then
you might have to report this to the clerk team
@joulev well... good luck debugging the middleware then
Giant pandaOP
Yeah, middleware is not even triggering. I suspect it has something to do with my matcher config though '/((?!_next/|_static/|examples/|[\w-]+\.\w+).*)',
@Giant panda Yeah, middleware is not even triggering. I suspect it has something to do with my matcher config though '/((?!_next/|_static/|examples/|[\\w-]+\\.\\w+).*)',
yes definitely, see that
\.\w+? that matches the .xmlAnswer
@joulev yes definitely, see that `\.\w+`? that matches the `.xml`
Giant pandaOP
I see
