@nuxtjs/sitemap 7.4.5 → 7.4.7
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.
- package/dist/client/200.html +1 -0
- package/dist/client/404.html +1 -0
- package/dist/client/__sitemap__/style.xsl +190 -0
- package/dist/client/_nuxt/CVMmb_pX.js +1 -0
- package/dist/client/_nuxt/CVO1_9PV.js +1 -0
- package/dist/client/_nuxt/Cp-IABpG.js +1 -0
- package/dist/client/_nuxt/D0r3Knsf.js +1 -0
- package/dist/client/_nuxt/Uwg2rjhu.js +172 -0
- package/dist/client/_nuxt/builds/latest.json +1 -0
- package/dist/client/_nuxt/builds/meta/d2f0f6ff-dbbc-45cd-bac8-0f24a0d6c572.json +1 -0
- package/dist/client/_nuxt/entry.D5V0t8Hh.css +1 -0
- package/dist/client/_nuxt/error-404.BXx3NK2Z.css +1 -0
- package/dist/client/_nuxt/error-500.BYrbHUTO.css +1 -0
- package/dist/client/_nuxt/rHMUQZkV.js +1 -0
- package/dist/client/index.html +1 -0
- package/dist/client/sitemap.xml +7 -0
- package/dist/content.d.mts +232 -0
- package/dist/content.d.ts +232 -0
- package/dist/content.mjs +45 -0
- package/dist/module.d.mts +10 -0
- package/dist/module.d.ts +10 -0
- package/dist/module.json +12 -0
- package/dist/module.mjs +1221 -0
- package/dist/runtime/server/composables/asSitemapUrl.d.ts +2 -0
- package/dist/runtime/server/composables/asSitemapUrl.js +3 -0
- package/dist/runtime/server/composables/defineSitemapEventHandler.d.ts +4 -0
- package/dist/runtime/server/composables/defineSitemapEventHandler.js +2 -0
- package/dist/runtime/server/content-compat.d.ts +1 -0
- package/dist/runtime/server/content-compat.js +2 -0
- package/dist/runtime/server/kit.d.ts +3 -0
- package/dist/runtime/server/kit.js +25 -0
- package/dist/runtime/server/plugins/compression.d.ts +2 -0
- package/dist/runtime/server/plugins/compression.js +8 -0
- package/dist/runtime/server/plugins/nuxt-content-v2.d.ts +2 -0
- package/dist/runtime/server/plugins/nuxt-content-v2.js +39 -0
- package/dist/runtime/server/plugins/warm-up.d.ts +2 -0
- package/dist/runtime/server/plugins/warm-up.js +39 -0
- package/dist/runtime/server/robots-polyfill/getPathRobotConfig.d.ts +5 -0
- package/dist/runtime/server/robots-polyfill/getPathRobotConfig.js +3 -0
- package/dist/runtime/server/routes/__sitemap__/debug.d.ts +40 -0
- package/dist/runtime/server/routes/__sitemap__/debug.js +29 -0
- package/dist/runtime/server/routes/__sitemap__/nuxt-content-urls-v2.d.ts +2 -0
- package/dist/runtime/server/routes/__sitemap__/nuxt-content-urls-v2.js +6 -0
- package/dist/runtime/server/routes/__sitemap__/nuxt-content-urls-v3.d.ts +2 -0
- package/dist/runtime/server/routes/__sitemap__/nuxt-content-urls-v3.js +24 -0
- package/dist/runtime/server/routes/sitemap/[sitemap].xml.d.ts +2 -0
- package/dist/runtime/server/routes/sitemap/[sitemap].xml.js +50 -0
- package/dist/runtime/server/routes/sitemap.xml.d.ts +2 -0
- package/dist/runtime/server/routes/sitemap.xml.js +13 -0
- package/dist/runtime/server/routes/sitemap.xsl.d.ts +2 -0
- package/dist/runtime/server/routes/sitemap.xsl.js +255 -0
- package/dist/runtime/server/routes/sitemap_index.xml.d.ts +2 -0
- package/dist/runtime/server/routes/sitemap_index.xml.js +42 -0
- package/dist/runtime/server/sitemap/builder/sitemap-index.d.ts +13 -0
- package/dist/runtime/server/sitemap/builder/sitemap-index.js +197 -0
- package/dist/runtime/server/sitemap/builder/sitemap.d.ts +16 -0
- package/dist/runtime/server/sitemap/builder/sitemap.js +241 -0
- package/dist/runtime/server/sitemap/builder/xml.d.ts +6 -0
- package/dist/runtime/server/sitemap/builder/xml.js +197 -0
- package/dist/runtime/server/sitemap/nitro.d.ts +4 -0
- package/dist/runtime/server/sitemap/nitro.js +144 -0
- package/dist/runtime/server/sitemap/urlset/normalise.d.ts +6 -0
- package/dist/runtime/server/sitemap/urlset/normalise.js +137 -0
- package/dist/runtime/server/sitemap/urlset/sort.d.ts +2 -0
- package/dist/runtime/server/sitemap/urlset/sort.js +13 -0
- package/dist/runtime/server/sitemap/urlset/sources.d.ts +6 -0
- package/dist/runtime/server/sitemap/urlset/sources.js +143 -0
- package/dist/runtime/server/sitemap/utils/chunk.d.ts +10 -0
- package/dist/runtime/server/sitemap/utils/chunk.js +67 -0
- package/dist/runtime/server/tsconfig.json +3 -0
- package/dist/runtime/server/utils.d.ts +5 -0
- package/dist/runtime/server/utils.js +16 -0
- package/dist/runtime/types.d.ts +458 -0
- package/dist/runtime/types.js +0 -0
- package/dist/runtime/utils-pure.d.ts +14 -0
- package/dist/runtime/utils-pure.js +85 -0
- package/dist/shared/sitemap.DR3_6qqU.mjs +212 -0
- package/dist/types.d.mts +5 -0
- package/dist/utils.d.mts +28 -0
- package/dist/utils.d.ts +28 -0
- package/dist/utils.mjs +368 -0
- package/package.json +2 -2
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { defineEventHandler } from 'h3';
|
|
2
|
+
import type { EventHandlerRequest, EventHandlerResponse } from 'h3';
|
|
3
|
+
import type { SitemapUrlInput } from '../../types.js';
|
|
4
|
+
export declare const defineSitemapEventHandler: typeof defineEventHandler<EventHandlerRequest, EventHandlerResponse<SitemapUrlInput[]>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const queryCollection: any;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { createRouter as createRadixRouter, toRouteMatcher } from "radix3";
|
|
2
|
+
import { defu } from "defu";
|
|
3
|
+
import { parseURL, withoutBase, withoutTrailingSlash } from "ufo";
|
|
4
|
+
import { useRuntimeConfig } from "nitropack/runtime";
|
|
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]) => [path === "/" ? path : withoutTrailingSlash(path), rules])
|
|
14
|
+
)
|
|
15
|
+
})
|
|
16
|
+
);
|
|
17
|
+
return (pathOrUrl) => {
|
|
18
|
+
const path = pathOrUrl[0] === "/" ? pathOrUrl : parseURL(pathOrUrl, app.baseURL).pathname;
|
|
19
|
+
const pathWithoutQuery = withoutQuery(path);
|
|
20
|
+
return defu({}, ..._routeRulesMatcher.matchAll(
|
|
21
|
+
// radix3 does not support trailing slashes
|
|
22
|
+
withoutBase(pathWithoutQuery === "/" ? pathWithoutQuery : withoutTrailingSlash(pathWithoutQuery), app.baseURL)
|
|
23
|
+
).reverse());
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { useCompressionStream } from "h3-compression";
|
|
2
|
+
import { defineNitroPlugin } from "nitropack/runtime";
|
|
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,39 @@
|
|
|
1
|
+
import { defu } from "defu";
|
|
2
|
+
import { defineNitroPlugin } from "nitropack/runtime";
|
|
3
|
+
import { useSitemapRuntimeConfig } from "../utils.js";
|
|
4
|
+
export default defineNitroPlugin((nitroApp) => {
|
|
5
|
+
const { discoverImages, isNuxtContentDocumentDriven } = useSitemapRuntimeConfig();
|
|
6
|
+
nitroApp.hooks.hook("content:file:afterParse", async (content) => {
|
|
7
|
+
const validExtensions = ["md", "mdx"];
|
|
8
|
+
if (content.sitemap === false || content._draft || !validExtensions.includes(content._extension || "") || content._partial || content.robots === false)
|
|
9
|
+
return;
|
|
10
|
+
let images = [];
|
|
11
|
+
if (discoverImages) {
|
|
12
|
+
images = content.body?.children?.filter(
|
|
13
|
+
(c) => c.tag && c.props?.src && ["image", "img", "nuxtimg", "nuxt-img"].includes(c.tag.toLowerCase())
|
|
14
|
+
).map((i) => ({ loc: i.props.src })) || [];
|
|
15
|
+
}
|
|
16
|
+
const sitemapConfig = typeof content.sitemap === "object" ? content.sitemap : {};
|
|
17
|
+
const lastmod = content.modifiedAt || content.updatedAt;
|
|
18
|
+
const defaults = {};
|
|
19
|
+
if (isNuxtContentDocumentDriven)
|
|
20
|
+
defaults.loc = content._path;
|
|
21
|
+
if (content.path)
|
|
22
|
+
defaults.loc = content.path;
|
|
23
|
+
if (images?.length)
|
|
24
|
+
defaults.images = images;
|
|
25
|
+
if (lastmod)
|
|
26
|
+
defaults.lastmod = lastmod;
|
|
27
|
+
const definition = defu(sitemapConfig, defaults);
|
|
28
|
+
if (!definition.loc) {
|
|
29
|
+
if (content.path && content.path && content.path.startsWith("/"))
|
|
30
|
+
definition.loc = content.path;
|
|
31
|
+
if (Object.keys(sitemapConfig).length > 0 && import.meta.dev)
|
|
32
|
+
console.warn(`[@nuxtjs/content] The @nuxt/content file \`${content._path}\` is missing a sitemap \`loc\`.`);
|
|
33
|
+
}
|
|
34
|
+
content.sitemap = definition;
|
|
35
|
+
if (!definition.loc)
|
|
36
|
+
delete content.sitemap;
|
|
37
|
+
return content;
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { withLeadingSlash } from "ufo";
|
|
2
|
+
import { defineNitroPlugin } from "nitropack/runtime";
|
|
3
|
+
import { useSitemapRuntimeConfig } from "../utils.js";
|
|
4
|
+
export default defineNitroPlugin((nitroApp) => {
|
|
5
|
+
const { sitemaps } = useSitemapRuntimeConfig();
|
|
6
|
+
const queue = [];
|
|
7
|
+
const timeoutIds = [];
|
|
8
|
+
const sitemapsWithRoutes = Object.entries(sitemaps).filter(([, sitemap]) => sitemap._route);
|
|
9
|
+
for (const [, sitemap] of sitemapsWithRoutes)
|
|
10
|
+
queue.push(() => nitroApp.localFetch(withLeadingSlash(sitemap._route), {}));
|
|
11
|
+
const initialTimeout = setTimeout(
|
|
12
|
+
() => {
|
|
13
|
+
const next = async () => {
|
|
14
|
+
if (queue.length === 0) {
|
|
15
|
+
timeoutIds.length = 0;
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
try {
|
|
19
|
+
await queue.shift()();
|
|
20
|
+
} catch (error) {
|
|
21
|
+
console.error("[sitemap:warm-up] Error warming up sitemap:", error);
|
|
22
|
+
}
|
|
23
|
+
if (queue.length > 0) {
|
|
24
|
+
const nextTimeout = setTimeout(next, 1e3);
|
|
25
|
+
timeoutIds.push(nextTimeout);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
next();
|
|
29
|
+
},
|
|
30
|
+
2500
|
|
31
|
+
/* https://github.com/unjs/nitro/pull/1906 */
|
|
32
|
+
);
|
|
33
|
+
timeoutIds.push(initialTimeout);
|
|
34
|
+
nitroApp.hooks.hook("close", () => {
|
|
35
|
+
timeoutIds.forEach((id) => clearTimeout(id));
|
|
36
|
+
timeoutIds.length = 0;
|
|
37
|
+
queue.length = 0;
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { SitemapDefinition } from '../../../types.js';
|
|
2
|
+
declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<{
|
|
3
|
+
nitroOrigin: string;
|
|
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.js").SitemapIndexEntry[];
|
|
11
|
+
};
|
|
12
|
+
} & Record<string, Omit<SitemapDefinition, "urls"> & {
|
|
13
|
+
_hasSourceChunk?: boolean;
|
|
14
|
+
}>;
|
|
15
|
+
autoI18n?: import("../../../types.js").AutoI18nConfig;
|
|
16
|
+
isMultiSitemap: boolean;
|
|
17
|
+
isI18nMapped: boolean;
|
|
18
|
+
sitemapsPathPrefix: string | false;
|
|
19
|
+
cacheMaxAgeSeconds: number | false;
|
|
20
|
+
sitemapName: string;
|
|
21
|
+
excludeAppSources: true | (import("../../../types.js").AppSourceContext[]);
|
|
22
|
+
sortEntries: boolean;
|
|
23
|
+
defaultSitemapsChunkSize: number | false;
|
|
24
|
+
xslColumns?: {
|
|
25
|
+
label: string;
|
|
26
|
+
width: `${string}%`;
|
|
27
|
+
select?: string;
|
|
28
|
+
}[] | undefined;
|
|
29
|
+
xslTips: boolean;
|
|
30
|
+
debug: boolean;
|
|
31
|
+
discoverImages: boolean;
|
|
32
|
+
discoverVideos: boolean;
|
|
33
|
+
autoLastmod: boolean;
|
|
34
|
+
xsl: string | false;
|
|
35
|
+
credits: boolean;
|
|
36
|
+
minify: boolean;
|
|
37
|
+
};
|
|
38
|
+
globalSources: import("../../../types.js").SitemapSourceResolved[];
|
|
39
|
+
}>>;
|
|
40
|
+
export default _default;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { defineEventHandler } from "h3";
|
|
2
|
+
import { useSitemapRuntimeConfig } from "../../utils.js";
|
|
3
|
+
import {
|
|
4
|
+
childSitemapSources,
|
|
5
|
+
globalSitemapSources,
|
|
6
|
+
resolveSitemapSources
|
|
7
|
+
} from "../../sitemap/urlset/sources.js";
|
|
8
|
+
import { useNitroOrigin } from "#site-config/server/composables/useNitroOrigin";
|
|
9
|
+
export default defineEventHandler(async (e) => {
|
|
10
|
+
const _runtimeConfig = useSitemapRuntimeConfig();
|
|
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]), e)
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
return {
|
|
24
|
+
nitroOrigin,
|
|
25
|
+
sitemaps,
|
|
26
|
+
runtimeConfig,
|
|
27
|
+
globalSources: await resolveSitemapSources(globalSources, e)
|
|
28
|
+
};
|
|
29
|
+
});
|
|
@@ -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,24 @@
|
|
|
1
|
+
import { defineEventHandler } from "h3";
|
|
2
|
+
import { queryCollection } from "@nuxt/content/server";
|
|
3
|
+
import manifest from "#content/manifest";
|
|
4
|
+
export default defineEventHandler(async (e) => {
|
|
5
|
+
const collections = [];
|
|
6
|
+
for (const collection in manifest) {
|
|
7
|
+
if (manifest[collection].fields.sitemap) {
|
|
8
|
+
collections.push(collection);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
const contentList = [];
|
|
12
|
+
for (const collection of collections) {
|
|
13
|
+
contentList.push(
|
|
14
|
+
queryCollection(e, collection).select("path", "sitemap").where("path", "IS NOT NULL").where("sitemap", "IS NOT NULL").all()
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
const results = await Promise.all(contentList);
|
|
18
|
+
return results.flatMap((c) => {
|
|
19
|
+
return c.filter((c2) => c2.sitemap !== false && c2.path).flatMap((c2) => ({
|
|
20
|
+
loc: c2.path,
|
|
21
|
+
...c2.sitemap || {}
|
|
22
|
+
}));
|
|
23
|
+
}).filter(Boolean);
|
|
24
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { createError, defineEventHandler, getRouterParam } from "h3";
|
|
2
|
+
import { withoutLeadingSlash, withoutTrailingSlash } from "ufo";
|
|
3
|
+
import { useSitemapRuntimeConfig } from "../../utils.js";
|
|
4
|
+
import { createSitemap } from "../../sitemap/nitro.js";
|
|
5
|
+
import { parseChunkInfo, getSitemapConfig } from "../../sitemap/utils/chunk.js";
|
|
6
|
+
export default defineEventHandler(async (e) => {
|
|
7
|
+
const runtimeConfig = useSitemapRuntimeConfig(e);
|
|
8
|
+
const { sitemaps } = runtimeConfig;
|
|
9
|
+
let sitemapName = getRouterParam(e, "sitemap");
|
|
10
|
+
if (!sitemapName) {
|
|
11
|
+
const path = e.path;
|
|
12
|
+
const match = path.match(/(?:\/__sitemap__\/)?([^/]+)\.xml$/);
|
|
13
|
+
if (match) {
|
|
14
|
+
sitemapName = match[1];
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
if (!sitemapName) {
|
|
18
|
+
return createError({
|
|
19
|
+
statusCode: 400,
|
|
20
|
+
message: "Invalid sitemap request"
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
sitemapName = withoutLeadingSlash(withoutTrailingSlash(sitemapName.replace(".xml", "").replace("__sitemap__/", "").replace(runtimeConfig.sitemapsPathPrefix || "", "")));
|
|
24
|
+
const chunkInfo = parseChunkInfo(sitemapName, sitemaps, runtimeConfig.defaultSitemapsChunkSize);
|
|
25
|
+
const isAutoChunked = typeof sitemaps.chunks !== "undefined" && !Number.isNaN(Number(sitemapName));
|
|
26
|
+
const sitemapExists = sitemapName in sitemaps || chunkInfo.baseSitemapName in sitemaps || isAutoChunked;
|
|
27
|
+
if (!sitemapExists) {
|
|
28
|
+
return createError({
|
|
29
|
+
statusCode: 404,
|
|
30
|
+
message: `Sitemap "${sitemapName}" not found.`
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
if (chunkInfo.isChunked && chunkInfo.chunkIndex !== void 0) {
|
|
34
|
+
const baseSitemap = sitemaps[chunkInfo.baseSitemapName];
|
|
35
|
+
if (baseSitemap && !baseSitemap.chunks && !baseSitemap._isChunking) {
|
|
36
|
+
return createError({
|
|
37
|
+
statusCode: 404,
|
|
38
|
+
message: `Sitemap "${chunkInfo.baseSitemapName}" does not support chunking.`
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
if (baseSitemap?._chunkCount !== void 0 && chunkInfo.chunkIndex >= baseSitemap._chunkCount) {
|
|
42
|
+
return createError({
|
|
43
|
+
statusCode: 404,
|
|
44
|
+
message: `Chunk ${chunkInfo.chunkIndex} does not exist for sitemap "${chunkInfo.baseSitemapName}".`
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const sitemapConfig = getSitemapConfig(sitemapName, sitemaps, runtimeConfig.defaultSitemapsChunkSize);
|
|
49
|
+
return createSitemap(e, sitemapConfig, runtimeConfig);
|
|
50
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { defineEventHandler, sendRedirect } from "h3";
|
|
2
|
+
import { withBase } from "ufo";
|
|
3
|
+
import { useRuntimeConfig } from "nitropack/runtime";
|
|
4
|
+
import { useSitemapRuntimeConfig } from "../utils.js";
|
|
5
|
+
import { createSitemap } from "../sitemap/nitro.js";
|
|
6
|
+
export default defineEventHandler(async (e) => {
|
|
7
|
+
const runtimeConfig = useSitemapRuntimeConfig();
|
|
8
|
+
const { sitemaps } = runtimeConfig;
|
|
9
|
+
if ("index" in sitemaps) {
|
|
10
|
+
return sendRedirect(e, withBase("/sitemap_index.xml", useRuntimeConfig().app.baseURL), import.meta.dev ? 302 : 301);
|
|
11
|
+
}
|
|
12
|
+
return createSitemap(e, Object.values(sitemaps)[0], runtimeConfig);
|
|
13
|
+
});
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import { defineEventHandler, getHeader, setHeader, getQuery as h3GetQuery } from "h3";
|
|
2
|
+
import { getQuery, parseURL, withQuery } from "ufo";
|
|
3
|
+
import { useSitemapRuntimeConfig, xmlEscape } from "../utils.js";
|
|
4
|
+
import { useSiteConfig } from "#site-config/server/composables/useSiteConfig";
|
|
5
|
+
import { createSitePathResolver } from "#site-config/server/composables/utils";
|
|
6
|
+
export default defineEventHandler(async (e) => {
|
|
7
|
+
const fixPath = createSitePathResolver(e, { absolute: false, withBase: true });
|
|
8
|
+
const { sitemapName: fallbackSitemapName, cacheMaxAgeSeconds, version, xslColumns, xslTips } = useSitemapRuntimeConfig();
|
|
9
|
+
setHeader(e, "Content-Type", "application/xslt+xml");
|
|
10
|
+
if (cacheMaxAgeSeconds)
|
|
11
|
+
setHeader(e, "Cache-Control", `public, max-age=${cacheMaxAgeSeconds}, must-revalidate`);
|
|
12
|
+
else
|
|
13
|
+
setHeader(e, "Cache-Control", `no-cache, no-store`);
|
|
14
|
+
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>`;
|
|
15
|
+
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 Sitemap v${version}</a>`;
|
|
16
|
+
const { name: siteName, url: siteUrl } = useSiteConfig(e);
|
|
17
|
+
const referrer = getHeader(e, "Referer") || "/";
|
|
18
|
+
const referrerPath = parseURL(referrer).pathname;
|
|
19
|
+
const isNotIndexButHasIndex = referrerPath !== "/sitemap.xml" && referrerPath !== "/sitemap_index.xml" && referrerPath.endsWith(".xml");
|
|
20
|
+
const sitemapName = parseURL(referrer).pathname.split("/").pop()?.split("-sitemap")[0] || fallbackSitemapName;
|
|
21
|
+
const title = `${siteName}${sitemapName !== "sitemap.xml" ? ` - ${sitemapName === "sitemap_index.xml" ? "index" : sitemapName}` : ""}`.replace(/&/g, "&");
|
|
22
|
+
const canonicalQuery = getQuery(referrer).canonical;
|
|
23
|
+
const isShowingCanonical = typeof canonicalQuery !== "undefined" && canonicalQuery !== "false";
|
|
24
|
+
const conditionalTips = [
|
|
25
|
+
'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.',
|
|
26
|
+
`URLs missing? Check Nuxt Devtools Sitemap tab (or the <a href="${xmlEscape(withQuery("/__sitemap__/debug.json", { sitemap: sitemapName }))}" style="color: #398465" target="_blank">debug endpoint</a>).`
|
|
27
|
+
];
|
|
28
|
+
const fetchErrors = [];
|
|
29
|
+
const xslQuery = h3GetQuery(e);
|
|
30
|
+
if (xslQuery.error_messages) {
|
|
31
|
+
const errorMessages = xslQuery.error_messages;
|
|
32
|
+
const errorUrls = xslQuery.error_urls;
|
|
33
|
+
if (errorMessages) {
|
|
34
|
+
const messages = Array.isArray(errorMessages) ? errorMessages : [errorMessages];
|
|
35
|
+
const urls = Array.isArray(errorUrls) ? errorUrls : errorUrls ? [errorUrls] : [];
|
|
36
|
+
messages.forEach((msg, i) => {
|
|
37
|
+
const errorParts = [xmlEscape(msg)];
|
|
38
|
+
if (urls[i]) {
|
|
39
|
+
errorParts.push(xmlEscape(urls[i]));
|
|
40
|
+
}
|
|
41
|
+
fetchErrors.push(`<strong style="color: #dc2626;">Error ${i + 1}:</strong> ${errorParts.join(" - ")}`);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (!isShowingCanonical) {
|
|
46
|
+
const canonicalPreviewUrl = withQuery(referrer, { canonical: "" });
|
|
47
|
+
conditionalTips.push(`Your canonical site URL is <strong>${xmlEscape(siteUrl)}</strong>.`);
|
|
48
|
+
conditionalTips.push(`You can preview your canonical sitemap by visiting <a href="${xmlEscape(canonicalPreviewUrl)}" style="color: #398465; white-space: nowrap;">${xmlEscape(fixPath(canonicalPreviewUrl))}?canonical</a>`);
|
|
49
|
+
} else {
|
|
50
|
+
conditionalTips.push(`You are viewing the canonical sitemap. You can switch to using the request origin: <a href="${xmlEscape(fixPath(referrer))}" style="color: #398465; white-space: nowrap ">${xmlEscape(fixPath(referrer))}</a>`);
|
|
51
|
+
}
|
|
52
|
+
const hasRuntimeErrors = fetchErrors.length > 0;
|
|
53
|
+
const showDevTips = import.meta.dev && xslTips !== false;
|
|
54
|
+
const showSidebar = showDevTips || hasRuntimeErrors;
|
|
55
|
+
const devTips = showDevTips ? conditionalTips.map((t) => `<li><p>${t}</p></li>`).join("\n") : "";
|
|
56
|
+
const runtimeErrors = hasRuntimeErrors ? fetchErrors.map((t) => `<li><p>${t}</p></li>`).join("\n") : "";
|
|
57
|
+
let columns = [...xslColumns];
|
|
58
|
+
if (!columns.length) {
|
|
59
|
+
columns = [
|
|
60
|
+
{ label: "URL", width: "50%" },
|
|
61
|
+
{ label: "Images", width: "25%", select: "count(image:image)" },
|
|
62
|
+
{ label: "Last Updated", width: "25%", select: "concat(substring(sitemap:lastmod,0,11),concat(' ', substring(sitemap:lastmod,12,5)),concat(' ', substring(sitemap:lastmod,20,6)))" }
|
|
63
|
+
];
|
|
64
|
+
}
|
|
65
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
66
|
+
<xsl:stylesheet version="2.0"
|
|
67
|
+
xmlns:html="http://www.w3.org/TR/REC-html40"
|
|
68
|
+
xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"
|
|
69
|
+
xmlns:sitemap="http://www.sitemaps.org/schemas/sitemap/0.9"
|
|
70
|
+
xmlns:xhtml="http://www.w3.org/1999/xhtml"
|
|
71
|
+
xmlns:news="http://www.google.com/schemas/sitemap-news/0.9"
|
|
72
|
+
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
|
73
|
+
<xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/>
|
|
74
|
+
<xsl:template match="/">
|
|
75
|
+
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
76
|
+
<head>
|
|
77
|
+
<title>XML Sitemap</title>
|
|
78
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
|
79
|
+
<style type="text/css">
|
|
80
|
+
body {
|
|
81
|
+
font-family: Inter, Helvetica, Arial, sans-serif;
|
|
82
|
+
font-size: 14px;
|
|
83
|
+
color: #333;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
table {
|
|
87
|
+
border: none;
|
|
88
|
+
border-collapse: collapse;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.bg-yellow-200 {
|
|
92
|
+
background-color: #fef9c3;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.p-5 {
|
|
96
|
+
padding: 1.25rem;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.rounded {
|
|
100
|
+
border-radius: 4px;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.shadow {
|
|
104
|
+
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
#sitemap tr:nth-child(odd) td {
|
|
108
|
+
background-color: #f8f8f8 !important;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
#sitemap tbody tr:hover td {
|
|
112
|
+
background-color: #fff;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
#sitemap tbody tr:hover td, #sitemap tbody tr:hover td a {
|
|
116
|
+
color: #000;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.expl a {
|
|
120
|
+
color: #398465;
|
|
121
|
+
font-weight: 600;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.expl a:visited {
|
|
125
|
+
color: #398465;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
a {
|
|
129
|
+
color: #000;
|
|
130
|
+
text-decoration: none;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
a:visited {
|
|
134
|
+
color: #777;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
a:hover {
|
|
138
|
+
text-decoration: underline;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
td {
|
|
142
|
+
font-size: 12px;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.text-2xl {
|
|
146
|
+
font-size: 2rem;
|
|
147
|
+
font-weight: 600;
|
|
148
|
+
line-height: 1.25;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
th {
|
|
152
|
+
text-align: left;
|
|
153
|
+
padding-right: 30px;
|
|
154
|
+
font-size: 12px;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
thead th {
|
|
158
|
+
border-bottom: 1px solid #000;
|
|
159
|
+
}
|
|
160
|
+
.fixed { position: fixed; }
|
|
161
|
+
.right-2 { right: 2rem; }
|
|
162
|
+
.top-2 { top: 2rem; }
|
|
163
|
+
.w-30 { width: 30rem; }
|
|
164
|
+
p { margin: 0; }
|
|
165
|
+
li { padding-bottom: 0.5rem; line-height: 1.5; }
|
|
166
|
+
h1 { margin: 0; }
|
|
167
|
+
.mb-5 { margin-bottom: 1.25rem; }
|
|
168
|
+
.mb-3 { margin-bottom: 0.75rem; }
|
|
169
|
+
</style>
|
|
170
|
+
</head>
|
|
171
|
+
<body>
|
|
172
|
+
<div style="grid-template-columns: 1fr 1fr; display: grid; margin: 3rem;">
|
|
173
|
+
<div>
|
|
174
|
+
<div id="content">
|
|
175
|
+
<h1 class="text-2xl mb-3">XML Sitemap</h1>
|
|
176
|
+
<h2>${xmlEscape(title)}</h2>
|
|
177
|
+
${isNotIndexButHasIndex ? `<p style="font-size: 12px; margin-bottom: 1rem;"><a href="${xmlEscape(fixPath("/sitemap_index.xml"))}">${xmlEscape(fixPath("/sitemap_index.xml"))}</a></p>` : ""}
|
|
178
|
+
<xsl:if test="count(sitemap:sitemapindex/sitemap:sitemap) > 0">
|
|
179
|
+
<p class="expl" style="margin-bottom: 1rem;">
|
|
180
|
+
This XML Sitemap Index file contains
|
|
181
|
+
<xsl:value-of select="count(sitemap:sitemapindex/sitemap:sitemap)"/> sitemaps.
|
|
182
|
+
</p>
|
|
183
|
+
<table id="sitemap" cellpadding="3">
|
|
184
|
+
<thead>
|
|
185
|
+
<tr>
|
|
186
|
+
<th width="75%">Sitemap</th>
|
|
187
|
+
<th width="25%">Last Modified</th>
|
|
188
|
+
</tr>
|
|
189
|
+
</thead>
|
|
190
|
+
<tbody>
|
|
191
|
+
<xsl:for-each select="sitemap:sitemapindex/sitemap:sitemap">
|
|
192
|
+
<xsl:variable name="sitemapURL">
|
|
193
|
+
<xsl:value-of select="sitemap:loc"/>
|
|
194
|
+
</xsl:variable>
|
|
195
|
+
<tr>
|
|
196
|
+
<td>
|
|
197
|
+
<a href="{$sitemapURL}">
|
|
198
|
+
<xsl:value-of select="sitemap:loc"/>
|
|
199
|
+
</a>
|
|
200
|
+
</td>
|
|
201
|
+
<td>
|
|
202
|
+
<xsl:value-of
|
|
203
|
+
select="concat(substring(sitemap:lastmod,0,11),concat(' ', substring(sitemap:lastmod,12,5)),concat(' ', substring(sitemap:lastmod,20,6)))"/>
|
|
204
|
+
</td>
|
|
205
|
+
</tr>
|
|
206
|
+
</xsl:for-each>
|
|
207
|
+
</tbody>
|
|
208
|
+
</table>
|
|
209
|
+
</xsl:if>
|
|
210
|
+
<xsl:if test="count(sitemap:sitemapindex/sitemap:sitemap) < 1">
|
|
211
|
+
<p class="expl" style="margin-bottom: 1rem;">
|
|
212
|
+
This XML Sitemap contains
|
|
213
|
+
<xsl:value-of select="count(sitemap:urlset/sitemap:url)"/> URLs.
|
|
214
|
+
</p>
|
|
215
|
+
<table id="sitemap" cellpadding="3">
|
|
216
|
+
<thead>
|
|
217
|
+
<tr>
|
|
218
|
+
${columns.map((c) => `<th width="${c.width}">${c.label}</th>`).join("\n")}
|
|
219
|
+
</tr>
|
|
220
|
+
</thead>
|
|
221
|
+
<tbody>
|
|
222
|
+
<xsl:variable name="lower" select="'abcdefghijklmnopqrstuvwxyz'"/>
|
|
223
|
+
<xsl:variable name="upper" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
|
|
224
|
+
<xsl:for-each select="sitemap:urlset/sitemap:url">
|
|
225
|
+
<tr>
|
|
226
|
+
<td>
|
|
227
|
+
<xsl:variable name="itemURL">
|
|
228
|
+
<xsl:value-of select="sitemap:loc"/>
|
|
229
|
+
</xsl:variable>
|
|
230
|
+
<a href="{$itemURL}">
|
|
231
|
+
<xsl:value-of select="sitemap:loc"/>
|
|
232
|
+
</a>
|
|
233
|
+
</td>
|
|
234
|
+
${columns.filter((c) => c.label !== "URL").map((c) => `<td>
|
|
235
|
+
<xsl:value-of select="${c.select}"/>
|
|
236
|
+
</td>`).join("\n")}
|
|
237
|
+
</tr>
|
|
238
|
+
</xsl:for-each>
|
|
239
|
+
</tbody>
|
|
240
|
+
</table>
|
|
241
|
+
</xsl:if>
|
|
242
|
+
</div>
|
|
243
|
+
</div>
|
|
244
|
+
${showSidebar ? `<div class="w-30 top-2 shadow rounded p-5 right-2" style="margin: 0 auto;">
|
|
245
|
+
${showDevTips ? `<div><p><strong>Development Tips</strong></p><ul style="margin: 1rem 0; padding: 0;">${devTips}</ul></div>` : ""}
|
|
246
|
+
${hasRuntimeErrors ? `<div${showDevTips ? ' style="margin-top: 1.5rem; padding-top: 1rem; border-top: 1px solid #e5e7eb;"' : ""}><p><strong style="color: #dc2626;">Runtime Errors</strong></p><ul style="margin: 1rem 0; padding: 0;">${runtimeErrors}</ul></div>` : ""}
|
|
247
|
+
${showDevTips ? `<p style="margin-top: 1rem;">${creditName}</p>` : ""}
|
|
248
|
+
</div>` : ""}
|
|
249
|
+
</div>
|
|
250
|
+
</body>
|
|
251
|
+
</html>
|
|
252
|
+
</xsl:template>
|
|
253
|
+
</xsl:stylesheet>
|
|
254
|
+
`;
|
|
255
|
+
});
|