diff --git a/apps/web/app/server-sitemap.xml/route.ts b/apps/web/app/server-sitemap.xml/route.ts deleted file mode 100644 index bb1c6d8ae..000000000 --- a/apps/web/app/server-sitemap.xml/route.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { getServerSideSitemap } from 'next-sitemap'; - -import { createCmsClient } from '@kit/cms'; - -import appConfig from '~/config/app.config'; - -export async function GET() { - const paths = getPaths(); - const contentItems = await getContentItems(); - - return getServerSideSitemap([ - ...paths, - ...contentItems.map((path) => { - return { - loc: new URL(path, appConfig.url).href, - lastmod: new Date().toISOString(), - }; - }), - ]); -} - -function getPaths() { - const paths = [ - '/', - '/faq', - '/blog', - '/docs', - '/pricing', - '/contact', - '/cookie-policy', - '/terms-of-service', - '/privacy-policy', - // add more paths here - ]; - - return paths.map((path) => { - return { - loc: new URL(path, appConfig.url).href, - lastmod: new Date().toISOString(), - }; - }); -} - -async function getContentItems() { - const client = await createCmsClient(); - - const posts = client - .getContentItems({ - collection: 'posts', - limit: Infinity, - }) - .then((response) => response.items) - .then((posts) => posts.map((post) => `/blog/${post.slug}`)); - - const docs = client - .getContentItems({ - collection: 'documentation', - limit: Infinity, - }) - .then((response) => response.items) - .then((docs) => docs.map((doc) => `/docs/${doc.slug}`)); - - return Promise.all([posts, docs]).then((items) => items.flat()); -} diff --git a/apps/web/app/sitemap.xml/route.ts b/apps/web/app/sitemap.xml/route.ts new file mode 100644 index 000000000..6d34cb8f0 --- /dev/null +++ b/apps/web/app/sitemap.xml/route.ts @@ -0,0 +1,85 @@ +import { getServerSideSitemap } from 'next-sitemap'; + +import { createCmsClient } from '@kit/cms'; + +import appConfig from '~/config/app.config'; + +/** + * @description The maximum age of the sitemap in seconds. + * This is used to set the cache-control header for the sitemap. The cache-control header is used to control how long the sitemap is cached. + * By default, the cache-control header is set to 'public, max-age=600, s-maxage=3600'. + * This means that the sitemap will be cached for 600 seconds (10 minutes) and will be considered stale after 3600 seconds (1 hour). + */ +const MAX_AGE = 60; +const S_MAX_AGE = 3600; + +export async function GET() { + const paths = getPaths(); + const contentItems = await getContentItems(); + + const headers = { + 'Cache-Control': `public, max-age=${MAX_AGE}, s-maxage=${S_MAX_AGE}`, + }; + + return getServerSideSitemap([...paths, ...contentItems], headers); +} + +function getPaths() { + const paths = [ + '/', + '/faq', + '/blog', + '/docs', + '/pricing', + '/contact', + '/cookie-policy', + '/terms-of-service', + '/privacy-policy', + // add more paths here + ]; + + return paths.map((path) => { + return { + loc: new URL(path, appConfig.url).href, + lastmod: new Date().toISOString(), + }; + }); +} + +async function getContentItems() { + const client = await createCmsClient(); + + // do not paginate the content items + const limit = Infinity; + const posts = client + .getContentItems({ + collection: 'posts', + limit, + }) + .then((response) => response.items) + .then((posts) => + posts.map((post) => ({ + loc: new URL(`/blog/${post.slug}`, appConfig.url).href, + lastmod: post.publishedAt + ? new Date(post.publishedAt).toISOString() + : new Date().toISOString(), + })), + ); + + const docs = client + .getContentItems({ + collection: 'documentation', + limit, + }) + .then((response) => response.items) + .then((docs) => + docs.map((doc) => ({ + loc: new URL(`/docs/${doc.slug}`, appConfig.url).href, + lastmod: doc.publishedAt + ? new Date(doc.publishedAt).toISOString() + : new Date().toISOString(), + })), + ); + + return Promise.all([posts, docs]).then((items) => items.flat()); +} diff --git a/apps/web/next.config.mjs b/apps/web/next.config.mjs index c110a3aa7..55c476887 100644 --- a/apps/web/next.config.mjs +++ b/apps/web/next.config.mjs @@ -39,6 +39,7 @@ const config = { outputFileTracingIncludes: { '/*': ['./content/**/*'], }, + redirects: getRedirects, experimental: { mdxRs: true, reactCompiler: ENABLE_REACT_COMPILER, @@ -95,6 +96,16 @@ function getRemotePatterns() { ]; } +async function getRedirects() { + return [ + { + source: '/server-sitemap.xml', + destination: '/sitemap.xml', + permanent: true, + }, + ]; +} + /** * @description Aliases modules based on the environment variables * This will speed up the development server by not loading the modules that are not needed