UNPKG

create-nttb

Version:

An opinionated Next.js, TypeScript, and Tailwind boilerplate using Atomic Design Methodology for presentation components.

80 lines (72 loc) 2.33 kB
import { headers } from "next/headers"; import { getRequestBaseUrl, getTopLevelRoutes, getRoutePriority, getChangeFreq, } from "../../utils/site"; /** * Revalidation interval (in seconds) for the sitemap.xml route. * * This enables ISR-like behaviour for the generated sitemap: * - The first request after the cache window regenerates the XML. * - Subsequent requests within the window are served from cache. */ export const revalidate = 60; /** * Minimal XML escaping for element text content. * Escapes characters that are significant in XML: * - & < > " ' */ function escapeXml(value: string): string { return value .replace(/&/g, "&amp;") .replace(/</g, "&lt;") .replace(/>/g, "&gt;") .replace(/"/g, "&quot;") .replace(/'/g, "&apos;"); } /** * Route handler for /sitemap.xml. * * This generates a basic XML sitemap that: * - Derives the base URL from the current request headers. * - Discovers top-level routes automatically from src/app. * - Assigns a priority to each route based on its depth. * - Derives a changefreq value automatically based on route depth. * - Sets a shared lastmod timestamp for all entries. * * The result is a fully dynamic sitemap that updates automatically * when new top-level route folders are added under src/app, with * sensible default metadata for search engines. */ export async function GET() { const h = await headers(); const baseUrl = getRequestBaseUrl(h); const routes = getTopLevelRoutes(); const now = new Date().toISOString(); const urls = routes.map((route) => ({ loc: `${baseUrl}${route}`, priority: getRoutePriority(route), lastmod: now, changefreq: getChangeFreq(route), })); const body = `<?xml version="1.0" encoding="UTF-8"?>` + `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">` + urls .map( ({ loc, priority, lastmod, changefreq }) => `<url><loc>${escapeXml(loc)}</loc><lastmod>${escapeXml( lastmod, )}</lastmod><changefreq>${escapeXml( changefreq, )}</changefreq><priority>${escapeXml(String(priority))}</priority></url>`, ) .join("") + `</urlset>`; return new Response(body, { status: 200, headers: { "Content-Type": "application/xml; charset=utf-8" }, }); }