@nuxtjs/sitemap 2.3.2 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/README.md +60 -569
  2. package/dist/client/200.html +11 -0
  3. package/dist/client/404.html +11 -0
  4. package/dist/client/_nuxt/Icon.I3NdYkjC.css +1 -0
  5. package/dist/client/_nuxt/Icon.wdYGFqbO.js +1 -0
  6. package/dist/client/_nuxt/IconCSS.6oz918NR.css +1 -0
  7. package/dist/client/_nuxt/IconCSS.L-uj6Ouj.js +1 -0
  8. package/dist/client/_nuxt/builds/latest.json +1 -0
  9. package/dist/client/_nuxt/builds/meta/c3bdccb2-d4db-4a94-9e61-39b740a57bf8.json +1 -0
  10. package/dist/client/_nuxt/entry.Soe9IWze.js +15 -0
  11. package/dist/client/_nuxt/entry.UqhvG0ao.css +1 -0
  12. package/dist/client/_nuxt/error-404.DkXpI38i.css +1 -0
  13. package/dist/client/_nuxt/error-404.uz-DxZsp.js +1 -0
  14. package/dist/client/_nuxt/error-500.BsNDeZpL.js +1 -0
  15. package/dist/client/_nuxt/error-500.SLhS9LVu.css +1 -0
  16. package/dist/client/_nuxt/index.lSDm5iYo.js +1 -0
  17. package/dist/client/index.html +11 -0
  18. package/dist/module.cjs +5 -0
  19. package/dist/module.d.mts +350 -0
  20. package/dist/module.d.ts +350 -0
  21. package/dist/module.json +9 -0
  22. package/dist/module.mjs +994 -0
  23. package/dist/runtime/nitro/composables/asSitemapUrl.d.ts +2 -0
  24. package/dist/runtime/nitro/composables/asSitemapUrl.mjs +3 -0
  25. package/dist/runtime/nitro/composables/defineSitemapEventHandler.d.ts +3 -0
  26. package/dist/runtime/nitro/composables/defineSitemapEventHandler.mjs +2 -0
  27. package/dist/runtime/nitro/composables/getPathRobotConfigPolyfill.d.ts +4 -0
  28. package/dist/runtime/nitro/composables/getPathRobotConfigPolyfill.mjs +3 -0
  29. package/dist/runtime/nitro/kit.d.ts +3 -0
  30. package/dist/runtime/nitro/kit.mjs +23 -0
  31. package/dist/runtime/nitro/middleware/[sitemap]-sitemap.xml.d.ts +2 -0
  32. package/dist/runtime/nitro/middleware/[sitemap]-sitemap.xml.mjs +23 -0
  33. package/dist/runtime/nitro/plugins/compression.d.ts +2 -0
  34. package/dist/runtime/nitro/plugins/compression.mjs +8 -0
  35. package/dist/runtime/nitro/plugins/nuxt-content.d.ts +2 -0
  36. package/dist/runtime/nitro/plugins/nuxt-content.mjs +38 -0
  37. package/dist/runtime/nitro/plugins/warm-up.d.ts +2 -0
  38. package/dist/runtime/nitro/plugins/warm-up.mjs +23 -0
  39. package/dist/runtime/nitro/routes/__sitemap__/debug.d.ts +37 -0
  40. package/dist/runtime/nitro/routes/__sitemap__/debug.mjs +29 -0
  41. package/dist/runtime/nitro/routes/__sitemap__/nuxt-content-urls.d.ts +2 -0
  42. package/dist/runtime/nitro/routes/__sitemap__/nuxt-content-urls.mjs +6 -0
  43. package/dist/runtime/nitro/routes/sitemap.xml.d.ts +2 -0
  44. package/dist/runtime/nitro/routes/sitemap.xml.mjs +13 -0
  45. package/dist/runtime/nitro/routes/sitemap.xsl.d.ts +2 -0
  46. package/dist/runtime/nitro/routes/sitemap.xsl.mjs +230 -0
  47. package/dist/runtime/nitro/routes/sitemap_index.xml.d.ts +2 -0
  48. package/dist/runtime/nitro/routes/sitemap_index.xml.mjs +27 -0
  49. package/dist/runtime/nitro/sitemap/builder/sitemap-index.d.ts +2 -0
  50. package/dist/runtime/nitro/sitemap/builder/sitemap-index.mjs +86 -0
  51. package/dist/runtime/nitro/sitemap/builder/sitemap.d.ts +2 -0
  52. package/dist/runtime/nitro/sitemap/builder/sitemap.mjs +107 -0
  53. package/dist/runtime/nitro/sitemap/builder/xml.d.ts +4 -0
  54. package/dist/runtime/nitro/sitemap/builder/xml.mjs +83 -0
  55. package/dist/runtime/nitro/sitemap/nitro.d.ts +4 -0
  56. package/dist/runtime/nitro/sitemap/nitro.mjs +36 -0
  57. package/dist/runtime/nitro/sitemap/urlset/filter.d.ts +5 -0
  58. package/dist/runtime/nitro/sitemap/urlset/filter.mjs +50 -0
  59. package/dist/runtime/nitro/sitemap/urlset/i18n.d.ts +8 -0
  60. package/dist/runtime/nitro/sitemap/urlset/i18n.mjs +128 -0
  61. package/dist/runtime/nitro/sitemap/urlset/normalise.d.ts +3 -0
  62. package/dist/runtime/nitro/sitemap/urlset/normalise.mjs +77 -0
  63. package/dist/runtime/nitro/sitemap/urlset/sort.d.ts +2 -0
  64. package/dist/runtime/nitro/sitemap/urlset/sort.mjs +19 -0
  65. package/dist/runtime/nitro/sitemap/urlset/sources.d.ts +5 -0
  66. package/dist/runtime/nitro/sitemap/urlset/sources.mjs +82 -0
  67. package/dist/runtime/nitro/tsconfig.json +3 -0
  68. package/dist/runtime/nitro/utils.d.ts +4 -0
  69. package/dist/runtime/nitro/utils.mjs +13 -0
  70. package/dist/runtime/types.d.ts +355 -0
  71. package/dist/runtime/types.mjs +0 -0
  72. package/dist/runtime/utils-pure.d.ts +7 -0
  73. package/dist/runtime/utils-pure.mjs +32 -0
  74. package/dist/types.d.mts +18 -0
  75. package/dist/types.d.ts +18 -0
  76. package/package.json +79 -75
  77. package/CHANGELOG.md +0 -256
  78. package/LICENSE +0 -21
  79. package/lib/builder.js +0 -174
  80. package/lib/cache.js +0 -95
  81. package/lib/generator.js +0 -113
  82. package/lib/logger.js +0 -19
  83. package/lib/middleware.js +0 -195
  84. package/lib/module.js +0 -70
  85. package/lib/options.js +0 -136
  86. package/lib/routes.js +0 -55
@@ -0,0 +1,2 @@
1
+ import type { SitemapUrlInput } from '../../types';
2
+ export declare function asSitemapUrl(url: SitemapUrlInput | Record<string, any>): SitemapUrlInput;
@@ -0,0 +1,3 @@
1
+ export function asSitemapUrl(url) {
2
+ return url;
3
+ }
@@ -0,0 +1,3 @@
1
+ import { type EventHandlerRequest, type EventHandlerResponse, defineEventHandler } from 'h3';
2
+ import type { SitemapUrlInput } from '../../types';
3
+ export declare const defineSitemapEventHandler: typeof defineEventHandler<EventHandlerRequest, EventHandlerResponse<SitemapUrlInput[]>>;
@@ -0,0 +1,2 @@
1
+ import { defineEventHandler } from "h3";
2
+ export const defineSitemapEventHandler = defineEventHandler;
@@ -0,0 +1,4 @@
1
+ export declare function getPathRobotConfigPolyfill(): {
2
+ indexable: boolean;
3
+ rule: string;
4
+ };
@@ -0,0 +1,3 @@
1
+ export function getPathRobotConfigPolyfill() {
2
+ return { indexable: true, rule: "index, follow" };
3
+ }
@@ -0,0 +1,3 @@
1
+ import type { NitroRouteRules } from 'nitropack';
2
+ export declare function withoutQuery(path: string): string;
3
+ export declare function createNitroRouteRuleMatcher(): (path: string) => NitroRouteRules;
@@ -0,0 +1,23 @@
1
+ import { createRouter as createRadixRouter, toRouteMatcher } from "radix3";
2
+ import { defu } from "defu";
3
+ import { withoutBase, withoutTrailingSlash } from "ufo";
4
+ import { useRuntimeConfig } from "#imports";
5
+ export function withoutQuery(path) {
6
+ return path.split("?")[0];
7
+ }
8
+ export function createNitroRouteRuleMatcher() {
9
+ const { nitro, app } = useRuntimeConfig();
10
+ const _routeRulesMatcher = toRouteMatcher(
11
+ createRadixRouter({
12
+ routes: Object.fromEntries(
13
+ Object.entries(nitro?.routeRules || {}).map(([path, rules]) => [withoutTrailingSlash(path), rules])
14
+ )
15
+ })
16
+ );
17
+ return (path) => {
18
+ return defu({}, ..._routeRulesMatcher.matchAll(
19
+ // radix3 does not support trailing slashes
20
+ withoutBase(withoutTrailingSlash(withoutQuery(path)), app.baseURL)
21
+ ).reverse());
22
+ };
23
+ }
@@ -0,0 +1,2 @@
1
+ declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<string | import("h3").H3Error<unknown> | undefined>>;
2
+ export default _default;
@@ -0,0 +1,23 @@
1
+ import { createError, defineEventHandler } from "h3";
2
+ import { parseURL } from "ufo";
3
+ import { useSimpleSitemapRuntimeConfig } from "../utils.mjs";
4
+ import { createSitemap } from "../sitemap/nitro.mjs";
5
+ export default defineEventHandler(async (e) => {
6
+ const path = parseURL(e.path).pathname;
7
+ if (!path.endsWith("-sitemap.xml"))
8
+ return;
9
+ const runtimeConfig = useSimpleSitemapRuntimeConfig();
10
+ const { sitemaps } = runtimeConfig;
11
+ const sitemapName = path.replace("-sitemap.xml", "").replace("/", "");
12
+ const isChunking = typeof sitemaps.chunks !== "undefined" && !Number.isNaN(Number(sitemapName));
13
+ if (!(sitemapName in sitemaps) && !isChunking) {
14
+ return createError({
15
+ statusCode: 404,
16
+ message: `Sitemap "${sitemapName}" not found.`
17
+ });
18
+ }
19
+ return createSitemap(e, isChunking ? {
20
+ ...sitemaps.chunks,
21
+ sitemapName
22
+ } : sitemaps[sitemapName], runtimeConfig);
23
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: any;
2
+ export default _default;
@@ -0,0 +1,8 @@
1
+ import { useCompressionStream } from "h3-compression";
2
+ import { defineNitroPlugin } from "#imports";
3
+ export default defineNitroPlugin((nitro) => {
4
+ nitro.hooks.hook("beforeResponse", async (event, response) => {
5
+ if (event.context._isSitemap)
6
+ await useCompressionStream(event, response);
7
+ });
8
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("nitropack/dist/runtime/plugin").NitroAppPlugin;
2
+ export default _default;
@@ -0,0 +1,38 @@
1
+ import { defu } from "defu";
2
+ import { defineNitroPlugin } from "nitropack/dist/runtime/plugin";
3
+ import { useSimpleSitemapRuntimeConfig } from "../utils.mjs";
4
+ export default defineNitroPlugin((nitroApp) => {
5
+ const { discoverImages, isNuxtContentDocumentDriven } = useSimpleSitemapRuntimeConfig();
6
+ nitroApp.hooks.hook("content:file:afterParse", async (content) => {
7
+ if (content.sitemap === false || content._draft || content._extension !== "md" || content._partial || content.indexable === false || content.index === false)
8
+ return;
9
+ let images = [];
10
+ if (discoverImages) {
11
+ images = content.body?.children?.filter(
12
+ (c) => c.tag && c.props?.src && ["image", "img", "nuxtimg", "nuxt-img"].includes(c.tag.toLowerCase())
13
+ ).map((i) => ({ loc: i.props.src })) || [];
14
+ }
15
+ const sitemapConfig = typeof content.sitemap === "object" ? content.sitemap : {};
16
+ const lastmod = content.modifiedAt || content.updatedAt;
17
+ const defaults = {};
18
+ if (isNuxtContentDocumentDriven)
19
+ defaults.loc = content._path;
20
+ if (content.path)
21
+ defaults.loc = content.path;
22
+ if (images.length > 0)
23
+ defaults.images = images;
24
+ if (lastmod)
25
+ defaults.lastmod = lastmod;
26
+ const definition = defu(sitemapConfig, defaults);
27
+ if (!definition.loc) {
28
+ if (content.path && content.path && content.path.startsWith("/"))
29
+ definition.loc = content.path;
30
+ if (Object.keys(sitemapConfig).length > 0 && import.meta.dev)
31
+ console.warn(`[@nuxtjs/content] The @nuxt/content file \`${content._path}\` is missing a sitemap \`loc\`.`);
32
+ }
33
+ content.sitemap = definition;
34
+ if (!definition.loc)
35
+ delete content.sitemap;
36
+ return content;
37
+ });
38
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("nitropack/dist/runtime/plugin").NitroAppPlugin;
2
+ export default _default;
@@ -0,0 +1,23 @@
1
+ import { defineNitroPlugin } from "nitropack/dist/runtime/plugin";
2
+ import { withLeadingSlash } from "ufo";
3
+ import { useSimpleSitemapRuntimeConfig } from "../utils.mjs";
4
+ export default defineNitroPlugin((nitroApp) => {
5
+ const { sitemaps } = useSimpleSitemapRuntimeConfig();
6
+ const queue = [];
7
+ const sitemapsWithRoutes = Object.entries(sitemaps).filter(([, sitemap]) => sitemap._route);
8
+ for (const [, sitemap] of sitemapsWithRoutes)
9
+ queue.push(() => nitroApp.localFetch(withLeadingSlash(sitemap._route), {}));
10
+ setTimeout(
11
+ () => {
12
+ const next = async () => {
13
+ if (queue.length === 0)
14
+ return;
15
+ await queue.shift()();
16
+ setTimeout(next, 1e3);
17
+ };
18
+ next();
19
+ },
20
+ 2500
21
+ /* https://github.com/unjs/nitro/pull/1906 */
22
+ );
23
+ });
@@ -0,0 +1,37 @@
1
+ import type { SitemapDefinition } from '../../../types';
2
+ declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<{
3
+ nitroOrigin: any;
4
+ sitemaps: Record<string, SitemapDefinition>;
5
+ runtimeConfig: {
6
+ version: string;
7
+ isNuxtContentDocumentDriven: boolean;
8
+ sitemaps: {
9
+ index?: (Pick<SitemapDefinition, "sitemapName" | "_route"> & {
10
+ sitemaps: import("../../../types").SitemapIndexEntry[];
11
+ }) | undefined;
12
+ } & Record<string, Omit<SitemapDefinition, "urls" | "sources"> & {
13
+ _hasSourceChunk?: boolean | undefined;
14
+ }>;
15
+ autoI18n?: import("../../../types").AutoI18nConfig | undefined;
16
+ isMultiSitemap: boolean;
17
+ isI18nMapped: boolean;
18
+ cacheMaxAgeSeconds: number | false;
19
+ sitemapName: string;
20
+ excludeAppSources: true | import("../../../types").AppSourceContext[];
21
+ sortEntries: boolean;
22
+ defaultSitemapsChunkSize: number | false;
23
+ xslColumns?: {
24
+ label: string;
25
+ width: `${string}%`;
26
+ select?: string | undefined;
27
+ }[] | undefined;
28
+ xslTips: boolean;
29
+ debug: boolean;
30
+ discoverImages: boolean;
31
+ autoLastmod: boolean;
32
+ xsl: string | false;
33
+ credits: boolean;
34
+ };
35
+ globalSources: import("../../../types").SitemapSourceResolved[];
36
+ }>>;
37
+ export default _default;
@@ -0,0 +1,29 @@
1
+ import { defineEventHandler } from "h3";
2
+ import { useSimpleSitemapRuntimeConfig } from "../../utils.mjs";
3
+ import {
4
+ childSitemapSources,
5
+ globalSitemapSources,
6
+ resolveSitemapSources
7
+ } from "../../sitemap/urlset/sources.mjs";
8
+ import { useNitroOrigin } from "#imports";
9
+ export default defineEventHandler(async (e) => {
10
+ const _runtimeConfig = useSimpleSitemapRuntimeConfig();
11
+ const { sitemaps: _sitemaps } = _runtimeConfig;
12
+ const runtimeConfig = { ..._runtimeConfig };
13
+ delete runtimeConfig.sitemaps;
14
+ const globalSources = await globalSitemapSources();
15
+ const nitroOrigin = useNitroOrigin(e);
16
+ const sitemaps = {};
17
+ for (const s of Object.keys(_sitemaps)) {
18
+ sitemaps[s] = {
19
+ ..._sitemaps[s],
20
+ sources: await resolveSitemapSources(await childSitemapSources(_sitemaps[s]))
21
+ };
22
+ }
23
+ return {
24
+ nitroOrigin,
25
+ sitemaps,
26
+ runtimeConfig,
27
+ globalSources: await resolveSitemapSources(globalSources)
28
+ };
29
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any[]>>;
2
+ export default _default;
@@ -0,0 +1,6 @@
1
+ import { defineEventHandler } from "h3";
2
+ import { serverQueryContent } from "#content/server";
3
+ export default defineEventHandler(async (e) => {
4
+ const contentList = await serverQueryContent(e).find();
5
+ return contentList.map((c) => c.sitemap).filter(Boolean);
6
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<string | void>>;
2
+ export default _default;
@@ -0,0 +1,13 @@
1
+ import { defineEventHandler, sendRedirect } from "h3";
2
+ import { withBase } from "ufo";
3
+ import { useSimpleSitemapRuntimeConfig } from "../utils.mjs";
4
+ import { createSitemap } from "../sitemap/nitro.mjs";
5
+ import { useRuntimeConfig } from "#imports";
6
+ export default defineEventHandler(async (e) => {
7
+ const runtimeConfig = useSimpleSitemapRuntimeConfig();
8
+ const { sitemaps } = runtimeConfig;
9
+ if ("index" in sitemaps) {
10
+ return sendRedirect(e, withBase("/sitemap_index.xml", useRuntimeConfig().app.baseURL), process.dev ? 302 : 301);
11
+ }
12
+ return createSitemap(e, Object.values(sitemaps)[0], runtimeConfig);
13
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<string>>;
2
+ export default _default;
@@ -0,0 +1,230 @@
1
+ import { defineEventHandler, getHeader, setHeader } from "h3";
2
+ import { getQuery, parseURL, withQuery } from "ufo";
3
+ import { useSimpleSitemapRuntimeConfig } from "../utils.mjs";
4
+ import { createSitePathResolver, useSiteConfig } from "#imports";
5
+ export default defineEventHandler(async (e) => {
6
+ const fixPath = createSitePathResolver(e, { absolute: false, withBase: true });
7
+ const { sitemapName: fallbackSitemapName, cacheMaxAgeSeconds, version, xslColumns, xslTips } = useSimpleSitemapRuntimeConfig();
8
+ setHeader(e, "Content-Type", "application/xslt+xml");
9
+ if (cacheMaxAgeSeconds)
10
+ setHeader(e, "Cache-Control", `public, max-age=${cacheMaxAgeSeconds}, must-revalidate`);
11
+ else
12
+ setHeader(e, "Cache-Control", `no-cache, no-store`);
13
+ const svgIcon = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="icon" style="margin-right: 4px; font-size: 25px;" width="1em" height="1em" viewBox="0 0 32 32"><path fill="#93c5fd" d="M4 26h4v4H4zm10 0h4v4h-4zm10 0h4v4h-4zm1-10h-8v-2h-2v2H7a2.002 2.002 0 0 0-2 2v6h2v-6h8v6h2v-6h8v6h2v-6a2.002 2.002 0 0 0-2-2zM9 2v10h14V2zm2 2h2v6h-2zm10 6h-6V4h6z"></path></svg>`;
14
+ const creditName = `<a href="https://github.com/nuxt-modules/sitemap" style="color: black; display: flex; align-items: center; font-weight: 500;" target="_blank" rel="noopener">${svgIcon} Nuxt
15
+ Simple Sitemap v${version}</a>`;
16
+ const { name: siteName, url: siteUrl } = useSiteConfig(e);
17
+ const referrer = getHeader(e, "Referer") || "/";
18
+ const isNotIndexButHasIndex = referrer !== fixPath("/sitemap.xml") && parseURL(referrer).pathname.endsWith("-sitemap.xml");
19
+ const sitemapName = parseURL(referrer).pathname.split("/").pop()?.split("-sitemap")[0] || fallbackSitemapName;
20
+ const title = `${siteName}${sitemapName !== "sitemap.xml" ? ` - ${sitemapName === "sitemap_index.xml" ? "index" : sitemapName}` : ""}`.replace(/&/g, "&amp;");
21
+ const canonicalQuery = getQuery(referrer).canonical;
22
+ const isShowingCanonical = typeof canonicalQuery !== "undefined" && canonicalQuery !== "false";
23
+ const conditionalTips = [
24
+ 'You are looking at a <a href="https://developer.mozilla.org/en-US/docs/Web/XSLT/Transforming_XML_with_XSLT/An_Overview" style="color: #398465" target="_blank">XML stylesheet</a>. Read the <a href="https://nuxtseo.com/sitemap/guides/customising-ui" style="color: #398465" target="_blank">docs</a> to learn how to customize it. View the page source to see the raw XML.',
25
+ `URLs missing? Check Nuxt Devtools Sitemap tab (or the <a href="${withQuery("/__sitemap__/debug.json", { sitemap: sitemapName })}" style="color: #398465" target="_blank">debug endpoint</a>).`
26
+ ];
27
+ if (!isShowingCanonical) {
28
+ const canonicalPreviewUrl = withQuery(referrer, { canonical: "" });
29
+ conditionalTips.push(`Your canonical site URL is <strong>${siteUrl}</strong>.`);
30
+ conditionalTips.push(`You can preview your canonical sitemap by visiting <a href="${canonicalPreviewUrl}" style="color: #398465; white-space: nowrap;">${fixPath(canonicalPreviewUrl)}?canonical</a>`);
31
+ } else {
32
+ conditionalTips.push(`You are viewing the canonical sitemap. You can switch to using the request origin: <a href="${fixPath(referrer)}" style="color: #398465; white-space: nowrap ">${fixPath(referrer)}</a>`);
33
+ }
34
+ const tips = conditionalTips.map((t) => `<li><p>${t}</p></li>`).join("\n");
35
+ const showTips = process.dev && xslTips !== false;
36
+ let columns = [...xslColumns];
37
+ if (!columns.length) {
38
+ columns = [
39
+ { label: "URL", width: "50%" },
40
+ { label: "Images", width: "25%", select: "count(image:image)" },
41
+ { label: "Last Updated", width: "25%", select: "concat(substring(sitemap:lastmod,0,11),concat(' ', substring(sitemap:lastmod,12,5)),concat(' ', substring(sitemap:lastmod,20,6)))" }
42
+ ];
43
+ }
44
+ return `<?xml version="1.0" encoding="UTF-8"?>
45
+ <xsl:stylesheet version="2.0"
46
+ xmlns:html="http://www.w3.org/TR/REC-html40"
47
+ xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"
48
+ xmlns:sitemap="http://www.sitemaps.org/schemas/sitemap/0.9"
49
+ xmlns:xhtml="http://www.w3.org/1999/xhtml"
50
+ xmlns:news="http://www.google.com/schemas/sitemap-news/0.9"
51
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
52
+ <xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/>
53
+ <xsl:template match="/">
54
+ <html xmlns="http://www.w3.org/1999/xhtml">
55
+ <head>
56
+ <title>XML Sitemap</title>
57
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
58
+ <style type="text/css">
59
+ body {
60
+ font-family: Inter, Helvetica, Arial, sans-serif;
61
+ font-size: 14px;
62
+ color: #333;
63
+ }
64
+
65
+ table {
66
+ border: none;
67
+ border-collapse: collapse;
68
+ }
69
+
70
+ .bg-yellow-200 {
71
+ background-color: #fef9c3;
72
+ }
73
+
74
+ .p-5 {
75
+ padding: 1.25rem;
76
+ }
77
+
78
+ .rounded {
79
+ border-radius: 4px;
80
+ }
81
+
82
+ .shadow {
83
+ box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
84
+ }
85
+
86
+ #sitemap tr:nth-child(odd) td {
87
+ background-color: #f8f8f8 !important;
88
+ }
89
+
90
+ #sitemap tbody tr:hover td {
91
+ background-color: #fff;
92
+ }
93
+
94
+ #sitemap tbody tr:hover td, #sitemap tbody tr:hover td a {
95
+ color: #000;
96
+ }
97
+
98
+ .expl a {
99
+ color: #398465
100
+ font-weight: 600;
101
+ }
102
+
103
+ .expl a:visited {
104
+ color: #398465
105
+ }
106
+
107
+ a {
108
+ color: #000;
109
+ text-decoration: none;
110
+ }
111
+
112
+ a:visited {
113
+ color: #777;
114
+ }
115
+
116
+ a:hover {
117
+ text-decoration: underline;
118
+ }
119
+
120
+ td {
121
+ font-size: 12px;
122
+ }
123
+
124
+ .text-2xl {
125
+ font-size: 2rem;
126
+ font-weight: 600;
127
+ line-height: 1.25;
128
+ }
129
+
130
+ th {
131
+ text-align: left;
132
+ padding-right: 30px;
133
+ font-size: 12px;
134
+ }
135
+
136
+ thead th {
137
+ border-bottom: 1px solid #000;
138
+ }
139
+ .fixed { position: fixed; }
140
+ .right-2 { right: 2rem; }
141
+ .top-2 { top: 2rem; }
142
+ .w-30 { width: 30rem; }
143
+ p { margin: 0; }
144
+ li { padding-bottom: 0.5rem; line-height: 1.5; }
145
+ h1 { margin: 0; }
146
+ .mb-5 { margin-bottom: 1.25rem; }
147
+ .mb-3 { margin-bottom: 0.75rem; }
148
+ </style>
149
+ </head>
150
+ <body>
151
+ <div style="grid-template-columns: 1fr 1fr; display: grid; margin: 3rem;">
152
+ <div>
153
+ <div id="content">
154
+ <h1 class="text-2xl mb-3">XML Sitemap</h1>
155
+ <h2>${title}</h2>
156
+ ${isNotIndexButHasIndex ? `<p style="font-size: 12px; margin-bottom: 1rem;"><a href="${fixPath("/sitemap_index.xml")}">${fixPath("/sitemap_index.xml")}</a></p>` : ""}
157
+ <xsl:if test="count(sitemap:sitemapindex/sitemap:sitemap) &gt; 0">
158
+ <p class="expl" style="margin-bottom: 1rem;">
159
+ This XML Sitemap Index file contains
160
+ <xsl:value-of select="count(sitemap:sitemapindex/sitemap:sitemap)"/> sitemaps.
161
+ </p>
162
+ <table id="sitemap" cellpadding="3">
163
+ <thead>
164
+ <tr>
165
+ <th width="75%">Sitemap</th>
166
+ <th width="25%">Last Modified</th>
167
+ </tr>
168
+ </thead>
169
+ <tbody>
170
+ <xsl:for-each select="sitemap:sitemapindex/sitemap:sitemap">
171
+ <xsl:variable name="sitemapURL">
172
+ <xsl:value-of select="sitemap:loc"/>
173
+ </xsl:variable>
174
+ <tr>
175
+ <td>
176
+ <a href="{$sitemapURL}">
177
+ <xsl:value-of select="sitemap:loc"/>
178
+ </a>
179
+ </td>
180
+ <td>
181
+ <xsl:value-of
182
+ select="concat(substring(sitemap:lastmod,0,11),concat(' ', substring(sitemap:lastmod,12,5)),concat(' ', substring(sitemap:lastmod,20,6)))"/>
183
+ </td>
184
+ </tr>
185
+ </xsl:for-each>
186
+ </tbody>
187
+ </table>
188
+ </xsl:if>
189
+ <xsl:if test="count(sitemap:sitemapindex/sitemap:sitemap) &lt; 1">
190
+ <p class="expl" style="margin-bottom: 1rem;">
191
+ This XML Sitemap contains
192
+ <xsl:value-of select="count(sitemap:urlset/sitemap:url)"/> URLs.
193
+ </p>
194
+ <table id="sitemap" cellpadding="3">
195
+ <thead>
196
+ <tr>
197
+ ${columns.map((c) => `<th width="${c.width}">${c.label}</th>`).join("\n")}
198
+ </tr>
199
+ </thead>
200
+ <tbody>
201
+ <xsl:variable name="lower" select="'abcdefghijklmnopqrstuvwxyz'"/>
202
+ <xsl:variable name="upper" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
203
+ <xsl:for-each select="sitemap:urlset/sitemap:url">
204
+ <tr>
205
+ <td>
206
+ <xsl:variable name="itemURL">
207
+ <xsl:value-of select="sitemap:loc"/>
208
+ </xsl:variable>
209
+ <a href="{$itemURL}">
210
+ <xsl:value-of select="sitemap:loc"/>
211
+ </a>
212
+ </td>
213
+ ${columns.filter((c) => c.label !== "URL").map((c) => `<td>
214
+ <xsl:value-of select="${c.select}"/>
215
+ </td>`).join("\n")}
216
+ </tr>
217
+ </xsl:for-each>
218
+ </tbody>
219
+ </table>
220
+ </xsl:if>
221
+ </div>
222
+ </div>
223
+ ${showTips ? `<div class="w-30 top-2 shadow rounded p-5 right-2" style="margin: 0 auto;"><p><strong>Sitemap Tips (development only)</strong></p><ul style="margin: 1rem; padding: 0;">${tips}</ul><p style="margin-top: 1rem;">${creditName}</p></div>` : ""}
224
+ </div>
225
+ </body>
226
+ </html>
227
+ </xsl:template>
228
+ </xsl:stylesheet>
229
+ `;
230
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<string>>;
2
+ export default _default;
@@ -0,0 +1,27 @@
1
+ import { defineEventHandler, getQuery, setHeader } from "h3";
2
+ import { fixSlashes } from "site-config-stack/urls";
3
+ import { useSimpleSitemapRuntimeConfig } from "../utils.mjs";
4
+ import { buildSitemapIndex } from "../sitemap/builder/sitemap-index.mjs";
5
+ import { createSitePathResolver, useNitroApp, useSiteConfig } from "#imports";
6
+ export default defineEventHandler(async (e) => {
7
+ const canonicalQuery = getQuery(e).canonical;
8
+ const isShowingCanonical = typeof canonicalQuery !== "undefined" && canonicalQuery !== "false";
9
+ const runtimeConfig = useSimpleSitemapRuntimeConfig();
10
+ const siteConfig = useSiteConfig(e);
11
+ let sitemap = await buildSitemapIndex({
12
+ event: e,
13
+ canonicalUrlResolver: createSitePathResolver(e, { canonical: isShowingCanonical || !import.meta.dev, absolute: true, withBase: true }),
14
+ relativeBaseUrlResolver: createSitePathResolver(e, { absolute: false, withBase: true }),
15
+ fixSlashes: (path) => fixSlashes(siteConfig.trailingSlash, path)
16
+ }, runtimeConfig);
17
+ const nitro = useNitroApp();
18
+ const ctx = { sitemap, sitemapName: "sitemap" };
19
+ await nitro.hooks.callHook("sitemap:output", ctx);
20
+ sitemap = ctx.sitemap;
21
+ setHeader(e, "Content-Type", "text/xml; charset=UTF-8");
22
+ if (runtimeConfig.cacheMaxAgeSeconds)
23
+ setHeader(e, "Cache-Control", `public, max-age=${runtimeConfig.cacheMaxAgeSeconds}, must-revalidate`);
24
+ else
25
+ setHeader(e, "Cache-Control", `no-cache, no-store`);
26
+ return sitemap;
27
+ });
@@ -0,0 +1,2 @@
1
+ import type { ModuleRuntimeConfig, NitroUrlResolvers } from '../../../types';
2
+ export declare function buildSitemapIndex(resolvers: NitroUrlResolvers, runtimeConfig: ModuleRuntimeConfig): Promise<string>;
@@ -0,0 +1,86 @@
1
+ import { defu } from "defu";
2
+ import { appendHeader } from "h3";
3
+ import { normaliseDate, normaliseSitemapUrls } from "../urlset/normalise.mjs";
4
+ import { globalSitemapSources, resolveSitemapSources } from "../urlset/sources.mjs";
5
+ import { applyI18nEnhancements } from "../urlset/i18n.mjs";
6
+ import { filterSitemapUrls } from "../urlset/filter.mjs";
7
+ import { sortSitemapUrls } from "../urlset/sort.mjs";
8
+ import { escapeValueForXml, wrapSitemapXml } from "./xml.mjs";
9
+ export async function buildSitemapIndex(resolvers, runtimeConfig) {
10
+ const {
11
+ sitemaps,
12
+ // enhancing
13
+ autoLastmod,
14
+ // chunking
15
+ defaultSitemapsChunkSize,
16
+ autoI18n,
17
+ isI18nMapped,
18
+ sortEntries,
19
+ // xls
20
+ version,
21
+ xsl,
22
+ credits
23
+ } = runtimeConfig;
24
+ if (!sitemaps)
25
+ throw new Error("Attempting to build a sitemap index without required `sitemaps` configuration.");
26
+ function maybeSort(urls) {
27
+ return sortEntries ? sortSitemapUrls(urls) : urls;
28
+ }
29
+ const isChunking = typeof sitemaps.chunks !== "undefined";
30
+ const chunks = {};
31
+ if (isChunking) {
32
+ const sitemap = sitemaps.chunks;
33
+ const sources = await resolveSitemapSources(await globalSitemapSources());
34
+ const normalisedUrls = normaliseSitemapUrls(sources.map((e) => e.urls).flat(), resolvers);
35
+ let enhancedUrls = normalisedUrls.map((e) => defu(e, sitemap.defaults));
36
+ if (autoI18n?.locales)
37
+ enhancedUrls = applyI18nEnhancements(enhancedUrls, { isI18nMapped, autoI18n, sitemapName: sitemap.sitemapName });
38
+ const filteredUrls = filterSitemapUrls(enhancedUrls, { ...sitemap, autoI18n, isMultiSitemap: true });
39
+ const sortedUrls = maybeSort(filteredUrls);
40
+ sortedUrls.forEach((url, i) => {
41
+ const chunkIndex = Math.floor(i / defaultSitemapsChunkSize);
42
+ chunks[chunkIndex] = chunks[chunkIndex] || { urls: [] };
43
+ chunks[chunkIndex].urls.push(url);
44
+ });
45
+ } else {
46
+ for (const sitemap in sitemaps) {
47
+ if (sitemap !== "index") {
48
+ chunks[sitemap] = chunks[sitemap] || { urls: [] };
49
+ }
50
+ }
51
+ }
52
+ if (import.meta.prerender) {
53
+ appendHeader(
54
+ resolvers.event,
55
+ "x-nitro-prerender",
56
+ Object.keys(chunks).map((name) => encodeURIComponent(`/${name}-sitemap.xml`)).join(", ")
57
+ );
58
+ }
59
+ const entries = [];
60
+ for (const name in chunks) {
61
+ const sitemap = chunks[name];
62
+ const entry = {
63
+ sitemap: resolvers.canonicalUrlResolver(`${name}-sitemap.xml`)
64
+ };
65
+ let lastmod = sitemap.urls.filter((a) => !!a?.lastmod).map((a) => typeof a.lastmod === "string" ? new Date(a.lastmod) : a.lastmod).sort((a, b) => (b?.getTime() || 0) - (a?.getTime() || 0))?.[0];
66
+ if (!lastmod && autoLastmod)
67
+ lastmod = /* @__PURE__ */ new Date();
68
+ if (lastmod)
69
+ entry.lastmod = normaliseDate(lastmod);
70
+ entries.push(entry);
71
+ }
72
+ if (sitemaps.index)
73
+ entries.push(...sitemaps.index.sitemaps);
74
+ const sitemapXml = entries.map((e) => [
75
+ " <sitemap>",
76
+ ` <loc>${escapeValueForXml(e.sitemap)}</loc>`,
77
+ // lastmod is optional
78
+ e.lastmod ? ` <lastmod>${escapeValueForXml(e.lastmod)}</lastmod>` : false,
79
+ " </sitemap>"
80
+ ].filter(Boolean).join("\n")).join("\n");
81
+ return wrapSitemapXml([
82
+ '<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
83
+ sitemapXml,
84
+ "</sitemapindex>"
85
+ ], resolvers, { version, xsl, credits });
86
+ }
@@ -0,0 +1,2 @@
1
+ import type { ModuleRuntimeConfig, NitroUrlResolvers, SitemapDefinition } from '../../../types';
2
+ export declare function buildSitemap(sitemap: SitemapDefinition, resolvers: NitroUrlResolvers, runtimeConfig: ModuleRuntimeConfig): Promise<string>;