nuxt-simple-sitemap
Version:
Powerfully flexible XML Sitemaps that integrate seamlessly, for Nuxt.
108 lines (107 loc) • 5.11 kB
JavaScript
import { defu } from "defu";
import { resolveSitePath } from "site-config-stack/urls";
import { parseURL, withHttps } from "ufo";
import { normaliseSitemapUrls } from "../urlset/normalise.mjs";
import { childSitemapSources, globalSitemapSources, resolveSitemapSources } from "../urlset/sources.mjs";
import { filterSitemapUrls } from "../urlset/filter.mjs";
import { applyI18nEnhancements, normaliseI18nSources } from "../urlset/i18n.mjs";
import { sortSitemapUrls } from "../urlset/sort.mjs";
import { splitForLocales, useSimpleSitemapRuntimeConfig } from "../../utils.mjs";
import { createNitroRouteRuleMatcher } from "../../nitro/kit.mjs";
import { handleEntry, wrapSitemapXml } from "./xml.mjs";
import { useNitroApp } from "#internal/nitro";
export async function buildSitemap(sitemap, resolvers) {
const {
sitemaps,
// enhancing
autoLastmod,
autoI18n,
isI18nMapped,
isMultiSitemap,
// sorting
sortEntries,
// chunking
defaultSitemapsChunkSize,
// xls
version,
xsl,
credits
} = useSimpleSitemapRuntimeConfig();
const isChunking = typeof sitemaps.chunks !== "undefined" && !Number.isNaN(Number(sitemap.sitemapName));
function maybeSort(urls2) {
return sortEntries ? sortSitemapUrls(urls2) : urls2;
}
function maybeSlice(urls2) {
if (isChunking && defaultSitemapsChunkSize) {
const chunk = Number(sitemap.sitemapName);
return urls2.slice(chunk * defaultSitemapsChunkSize, (chunk + 1) * defaultSitemapsChunkSize);
}
return urls2;
}
if (autoI18n?.differentDomains) {
const domain = autoI18n.locales.find((e) => [e.iso, e.code].includes(sitemap.sitemapName))?.domain;
if (domain) {
const _tester = resolvers.canonicalUrlResolver;
resolvers.canonicalUrlResolver = (path) => resolveSitePath(path, {
absolute: true,
withBase: false,
siteUrl: withHttps(domain),
trailingSlash: !_tester("/test/").endsWith("/"),
base: "/"
});
}
}
const sources = sitemap.includeAppSources ? await globalSitemapSources() : [];
sources.push(...await childSitemapSources(sitemap));
let resolvedSources = await resolveSitemapSources(sources);
if (autoI18n)
resolvedSources = normaliseI18nSources(resolvedSources, { autoI18n, isI18nMapped });
const normalisedUrls = normaliseSitemapUrls(resolvedSources.map((e) => e.urls).flat(), resolvers);
const defaults = { ...sitemap.defaults || {} };
if (autoLastmod && defaults?.lastmod)
defaults.lastmod = /* @__PURE__ */ new Date();
const routeRuleMatcher = createNitroRouteRuleMatcher();
let enhancedUrls = normalisedUrls.map((e) => defu(e, sitemap.defaults)).map((e) => {
const path = parseURL(e.loc).pathname;
let routeRules = routeRuleMatcher(path);
if (autoI18n?.locales && autoI18n?.strategy !== "no_prefix") {
const match = splitForLocales(path, autoI18n.locales.map((l) => l.code));
const pathWithoutPrefix = match[1];
if (pathWithoutPrefix && pathWithoutPrefix !== path)
routeRules = defu(routeRules, routeRuleMatcher(pathWithoutPrefix));
}
if (routeRules.sitemap === false)
return false;
if (typeof routeRules.index !== "undefined" && !routeRules.index)
return false;
const hasRobotsDisabled = Object.entries(routeRules.headers || {}).some(([name, value]) => name.toLowerCase() === "x-robots-tag" && value.toLowerCase() === "noindex");
if (routeRules.redirect || hasRobotsDisabled)
return false;
return routeRules.sitemap ? defu(e, routeRules.sitemap) : e;
}).filter(Boolean);
if (autoI18n?.locales)
enhancedUrls = applyI18nEnhancements(enhancedUrls, { isI18nMapped, autoI18n, sitemapName: sitemap.sitemapName });
const filteredUrls = filterSitemapUrls(enhancedUrls, { event: resolvers.event, isMultiSitemap, autoI18n, ...sitemap });
const sortedUrls = maybeSort(filteredUrls);
const slicedUrls = maybeSlice(sortedUrls);
const nitro = useNitroApp();
const ctx = {
urls: slicedUrls,
sitemapName: sitemap.sitemapName
};
await nitro.hooks.callHook("sitemap:resolved", ctx);
const urls = maybeSort(normaliseSitemapUrls(ctx.urls, resolvers));
const urlset = urls.map((e) => {
const keys = Object.keys(e).filter((k) => !k.startsWith("_"));
return [
" <url>",
keys.map((k) => handleEntry(k, e)).filter(Boolean).join("\n"),
" </url>"
].join("\n");
});
return wrapSitemapXml([
'<urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd http://www.google.com/schemas/sitemap-image/1.1 http://www.google.com/schemas/sitemap-image/1.1/sitemap-image.xsd" xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
urlset.join("\n"),
"</urlset>"
], resolvers, { version, xsl, credits });
}