Next.js Discord

Discord Forum

Sitemap Build Error

Answered
Brown bear posted this in #help-forum
Open in Discord
Brown bearOP
When viewing the sitemap built by my site, it generates the sitemap incorrectly. The following code is used to generate the sitemaps.

import { db } from '@/server/db';
import { MetadataRoute } from 'next';

export async function generateSitemaps() {
  return [{id: 0}, {id: 1}, {id: 2}];
}

export default async function sitemap({
  id: sitemapIndex
}: {
  id: number;
}): Promise<MetadataRoute.Sitemap> {
  // Google's limit is 50,000 URLs per sitemap
  const start = sitemapIndex * 50000;
  const end = start + 50000;
  const addressSlugs = await db.property.findMany({
    where: { addressSlug: { not: null } },
    skip: start, // Skip to the starting index
    take: end - start, // Take the number of properties from start to end
    orderBy: {
      id: 'asc'
    },
    select: { addressSlug: true, updatedAt: true }
  });

  // The addressSlugs field is verified to have all addressSlug fields a string
  return addressSlugs.map(({ addressSlug, updatedAt }) => ({
    url: `https://www.mfvalue.com/estimator/${addressSlug}`,
    lastModified: updatedAt || new Date()
  }));
}


The error can be found here: https://www.mfvalue.com/estimator/sitemap/0.xml
Answered by Brown bear
No, the solution was encoding the string in the link.
View full answer

74 Replies

@Ray does it build correctly if you reduce the number of record to 30000 per page?
Brown bearOP
No, the solution was encoding the string in the link.
Answer
@Ray does it build correctly if you reduce the number of record to 30000 per page?
Brown bearOP
How do you generate a sitemap of sitemaps?
In their docs it seems like you cannot generate them dynamically
Is there a proper way to do it?
@Brown bear In their docs it seems like you cannot generate them dynamically
you can, just do export const dynamic = 'force-dynamic'
if you have big site, it's better to generate a sitemap index and contain all the link of other sitemap in the index
you could also use route handler with dynamic route to make the sitemap but return text/xml instead
@Ray if you have big site, it's better to generate a sitemap index and contain all the link of other sitemap in the index
Brown bearOP
Is it generatable with the normal sitemap generator function?
Is there an option to make it specify sitemap links in xml
Brown bearOP
Can it generate the index sitemap?
@Ray https://www.npmjs.com/package/next-sitemap Or try this package
Brown bearOP
How do you import in config.js files? For some reason I cannot import my database into the file...
:sparkles: [next-sitemap] Loading next-sitemap config: file:///vercel/path0/frontend/next-sitemap.config.js
 :x: [next-sitemap] Error: Cannot find module '@/env'
Require stack:
- /vercel/path0/frontend/next-sitemap.config.js
    at Module._resolveFilename (node:internal/modules/cjs/loader:1134:15)
    at Module._load (node:internal/modules/cjs/loader:975:27)
    at Module.require (node:internal/modules/cjs/loader:1225:19)
    at require (node:internal/modules/helpers:177:18)
    at Object.<anonymous> (/vercel/path0/frontend/next-sitemap.config.js:1:17)
    at Module._compile (node:internal/modules/cjs/loader:1356:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1414:10)
    at Module.load (node:internal/modules/cjs/loader:1197:32)
    at Module._load (node:internal/modules/cjs/loader:1013:12)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/translators:202:29) {
@Ray try ts const { env } = require('./env')
Brown bearOP
import { db } from '@/server/db';

I suppose this becomes "./server/db" then?
Brown bearOP
yes
const { db } = require('./src/server/db')
Brown bearOP
 :x: [next-sitemap] /vercel/path0/frontend/next-sitemap.config.js:1
import { db } from '@/server/db';
^^^^^^
SyntaxError: Cannot use import statement outside a module
    at internalCompileFunction (node:internal/vm:73:18)
    at wrapSafe (node:internal/modules/cjs/loader:1274:20)
    at Module._compile (node:internal/modules/cjs/loader:1320:27)
    at Module._extensions..js (node:internal/modules/cjs/loader:1414:10)
    at Module.load (node:internal/modules/cjs/loader:1197:32)
    at Module._load (node:internal/modules/cjs/loader:1013:12)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/translators:202:29)
    at ModuleJob.run (node:internal/modules/esm/module_job:195:25)
    at async ModuleLoader.import (node:internal/modules/esm/loader:336:24)
    at async ConfigParser.loadBaseConfig (file:///vercel/path0/frontend/node_modules/next-sitemap/dist/esm/parsers/config-parser.js:52:28)
you can't use import there
Brown bearOP
✨ [next-sitemap] Loading next-sitemap config: file:///vercel/path0/frontend/next-sitemap.config.js
 ❌ [next-sitemap] Error: Cannot find module './src/server/db'
Require stack:
- /vercel/path0/frontend/next-sitemap.config.js
    at Module._resolveFilename (node:internal/modules/cjs/loader:1134:15)
    at Module._load (node:internal/modules/cjs/loader:975:27)
    at Module.require (node:internal/modules/cjs/loader:1225:19)
    at require (node:internal/modules/helpers:177:18)
    at Object.<anonymous> (/vercel/path0/frontend/next-sitemap.config.js:1:16)
    at Module._compile (node:internal/modules/cjs/loader:1356:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1414:10)
    at Module.load (node:internal/modules/cjs/loader:1197:32)
    at Module._load (node:internal/modules/cjs/loader:1013:12)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/translators:202:29) {
  code: 'MODULE_NOT_FOUND',
  requireStack: [ '/vercel/path0/frontend/next-sitemap.config.js' ]
}
atleast it tries to import
The path is valid, why wouldn't it import?
@Ray you can't use import there
Brown bearOP
in dev mode the enviorment can quick switch to the module, so the path should be correct
Unless the file is run elsewhere?
Brown bearOP
to generate sitemaps
isnt that what you were referring me to use for creating the sitemaps instead?
Brown bearOP
That uses an api route though.
Every time the sitemap is fetched, I need to do a DB call which is super expensive
as in I need to fetch 2 million records
@Ray I have never needed to import db instance to that config file?
Brown bearOP
is there a way to make it static?
@Brown bear is there a way to make it static?
it is static by default
it is a route handler
Brown bearOP
But doesnt the route need to generate the index sitemap every single time it is called?
no
Brown bearOP
Normal route handler data cannot be statically generated at build time
no
Brown bearOP
so its not an api route?
GET handler is static by default
well you can always try it
just try it with 10 record
Brown bearOP
but how long will it cache for?
How does it know when the data from database changes to revalidate
I just want it to only run once at build time, refreshing each buildtime
@Brown bear but how long will it cache for?
static mean never changed
until you rebuild
or use revalidatePath
@Ray static mean never changed
Brown bearOP
but the screenshot says cached, not treated as static.
Is the behavior you describe applicable to all route handlers?
you can do this in a route.ts file if you like
export const dynamic = 'force-static'
and you should see that route is static in the build report after the build process
Brown bearOP
very interesting
what if the route handler uses the arguments given? Does Nextjs have a way to handle various inputs too without returning the same data?
Brown bearOP
How does it know?
is it through this:
export const dynamic = 'force-static'
yes
read the doc how to opt-out
Brown bearOP
I do notice that querying the /server-sitemap-index.xml page doesnt show any logs in the vercel logs
How can that be?
what log are you expecting?
Brown bearOP
@Ray what log are you expecting?
Brown bearOP
A log like this
I don't think static route will show in here
Brown bearOP
I didnt use export const dynamic = 'force-static'
as I said, it is static by default