@nuxtjs/sitemap 7.2.9 → 7.3.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.
- package/dist/client/200.html +9 -9
- package/dist/client/404.html +9 -9
- package/dist/client/_nuxt/Cp-IABpG.js +1 -0
- package/dist/client/_nuxt/DJVkgDQ2.js +1 -0
- package/dist/client/_nuxt/SmY-NWqO.js +172 -0
- package/dist/client/_nuxt/builds/latest.json +1 -1
- package/dist/client/_nuxt/builds/meta/e48bfd5b-6605-4bbc-a466-32a664787616.json +1 -0
- package/dist/client/_nuxt/{entry.CJ2Eg9q-.css → entry.CgW0_noo.css} +1 -1
- package/dist/client/_nuxt/error-404.CtcyoHAN.css +1 -0
- package/dist/client/_nuxt/error-500.BIlfyoPk.css +1 -0
- package/dist/client/_nuxt/lL_X76lO.js +1 -0
- package/dist/client/index.html +9 -9
- package/dist/content.d.cts +2 -1
- package/dist/content.d.mts +2 -1
- package/dist/content.d.ts +2 -1
- package/dist/module.cjs +83 -42
- package/dist/module.d.cts +3 -1
- package/dist/module.d.mts +3 -1
- package/dist/module.d.ts +3 -1
- package/dist/module.json +3 -3
- package/dist/module.mjs +84 -43
- package/dist/runtime/server/plugins/warm-up.js +20 -4
- package/dist/runtime/server/routes/__sitemap__/debug.d.ts +4 -4
- package/dist/runtime/server/routes/__sitemap__/debug.js +2 -2
- package/dist/runtime/server/routes/__sitemap__/nuxt-content-urls-v3.js +7 -2
- package/dist/runtime/server/routes/sitemap/[sitemap].xml.js +37 -7
- package/dist/runtime/server/routes/sitemap_index.xml.js +11 -3
- package/dist/runtime/server/sitemap/builder/sitemap-index.d.ts +1 -1
- package/dist/runtime/server/sitemap/builder/sitemap-index.js +110 -16
- package/dist/runtime/server/sitemap/builder/sitemap.d.ts +1 -1
- package/dist/runtime/server/sitemap/builder/sitemap.js +62 -36
- package/dist/runtime/server/sitemap/builder/xml.d.ts +2 -3
- package/dist/runtime/server/sitemap/builder/xml.js +182 -80
- package/dist/runtime/server/sitemap/nitro.js +68 -20
- package/dist/runtime/server/sitemap/urlset/normalise.js +21 -19
- package/dist/runtime/server/sitemap/urlset/sort.d.ts +1 -1
- package/dist/runtime/server/sitemap/urlset/sort.js +9 -15
- package/dist/runtime/server/sitemap/utils/chunk.d.ts +10 -0
- package/dist/runtime/server/sitemap/utils/chunk.js +66 -0
- package/dist/runtime/types.d.ts +44 -0
- package/dist/runtime/utils-pure.js +13 -5
- package/dist/types.d.mts +5 -1
- package/package.json +32 -38
- package/content.d.ts +0 -1
- package/dist/client/_nuxt/BQoSv7ci.js +0 -1
- package/dist/client/_nuxt/BuImKM08.js +0 -1
- package/dist/client/_nuxt/DGiw9jHL.js +0 -172
- package/dist/client/_nuxt/LwtYuSjN.js +0 -1
- package/dist/client/_nuxt/builds/meta/491f5d1a-004d-407a-b464-c3363f77bc23.json +0 -1
- package/dist/client/_nuxt/error-404.CmL6pbzl.css +0 -1
- package/dist/client/_nuxt/error-500.CnmYQu0q.css +0 -1
- package/dist/types.d.ts +0 -1
|
@@ -2,9 +2,9 @@ import { resolveSitePath } from "nuxt-site-config/urls";
|
|
|
2
2
|
import { joinURL, withHttps } from "ufo";
|
|
3
3
|
import { preNormalizeEntry } from "../urlset/normalise.js";
|
|
4
4
|
import { childSitemapSources, globalSitemapSources, resolveSitemapSources } from "../urlset/sources.js";
|
|
5
|
-
import {
|
|
5
|
+
import { sortInPlace } from "../urlset/sort.js";
|
|
6
6
|
import { createPathFilter, logger, splitForLocales } from "../../../utils-pure.js";
|
|
7
|
-
import {
|
|
7
|
+
import { parseChunkInfo, sliceUrlsForChunk } from "../utils/chunk.js";
|
|
8
8
|
export function resolveSitemapEntries(sitemap, urls, runtimeConfig, resolvers) {
|
|
9
9
|
const {
|
|
10
10
|
autoI18n,
|
|
@@ -85,9 +85,23 @@ export function resolveSitemapEntries(sitemap, urls, runtimeConfig, resolvers) {
|
|
|
85
85
|
});
|
|
86
86
|
} else {
|
|
87
87
|
for (const l of autoI18n.locales) {
|
|
88
|
-
let loc =
|
|
89
|
-
if (autoI18n.
|
|
90
|
-
|
|
88
|
+
let loc = e._pathWithoutPrefix;
|
|
89
|
+
if (autoI18n.pages) {
|
|
90
|
+
const pageKey = e._pathWithoutPrefix.replace(/^\//, "").replace(/\/index$/, "") || "index";
|
|
91
|
+
const pageMappings = autoI18n.pages[pageKey];
|
|
92
|
+
if (pageMappings && pageMappings[l.code] !== void 0) {
|
|
93
|
+
const customPath = pageMappings[l.code];
|
|
94
|
+
if (customPath === false)
|
|
95
|
+
continue;
|
|
96
|
+
if (typeof customPath === "string")
|
|
97
|
+
loc = customPath.startsWith("/") ? customPath : `/${customPath}`;
|
|
98
|
+
} else if (!autoI18n.differentDomains && !(["prefix_and_default", "prefix_except_default"].includes(autoI18n.strategy) && l.code === autoI18n.defaultLocale)) {
|
|
99
|
+
loc = joinURL(`/${l.code}`, e._pathWithoutPrefix);
|
|
100
|
+
}
|
|
101
|
+
} else {
|
|
102
|
+
if (!autoI18n.differentDomains && !(["prefix_and_default", "prefix_except_default"].includes(autoI18n.strategy) && l.code === autoI18n.defaultLocale))
|
|
103
|
+
loc = joinURL(`/${l.code}`, e._pathWithoutPrefix);
|
|
104
|
+
}
|
|
91
105
|
const _sitemap = isI18nMapped ? l._sitemap : void 0;
|
|
92
106
|
const newEntry = preNormalizeEntry({
|
|
93
107
|
_sitemap,
|
|
@@ -99,14 +113,30 @@ export function resolveSitemapEntries(sitemap, urls, runtimeConfig, resolvers) {
|
|
|
99
113
|
alternatives: [{ code: "x-default", _hreflang: "x-default" }, ...autoI18n.locales].map((locale) => {
|
|
100
114
|
const code = locale.code === "x-default" ? autoI18n.defaultLocale : locale.code;
|
|
101
115
|
const isDefault = locale.code === "x-default" || locale.code === autoI18n.defaultLocale;
|
|
102
|
-
let href =
|
|
103
|
-
if (autoI18n.
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
if (
|
|
107
|
-
|
|
108
|
-
|
|
116
|
+
let href = e._pathWithoutPrefix;
|
|
117
|
+
if (autoI18n.pages) {
|
|
118
|
+
const pageKey = e._pathWithoutPrefix.replace(/^\//, "").replace(/\/index$/, "") || "index";
|
|
119
|
+
const pageMappings = autoI18n.pages[pageKey];
|
|
120
|
+
if (pageMappings && pageMappings[code] !== void 0) {
|
|
121
|
+
const customPath = pageMappings[code];
|
|
122
|
+
if (customPath === false)
|
|
123
|
+
return false;
|
|
124
|
+
if (typeof customPath === "string")
|
|
125
|
+
href = customPath.startsWith("/") ? customPath : `/${customPath}`;
|
|
126
|
+
} else if (autoI18n.strategy === "prefix") {
|
|
109
127
|
href = joinURL("/", code, e._pathWithoutPrefix);
|
|
128
|
+
} else if (["prefix_and_default", "prefix_except_default"].includes(autoI18n.strategy)) {
|
|
129
|
+
if (!isDefault) {
|
|
130
|
+
href = joinURL("/", code, e._pathWithoutPrefix);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
} else {
|
|
134
|
+
if (autoI18n.strategy === "prefix") {
|
|
135
|
+
href = joinURL("/", code, e._pathWithoutPrefix);
|
|
136
|
+
} else if (["prefix_and_default", "prefix_except_default"].includes(autoI18n.strategy)) {
|
|
137
|
+
if (!isDefault) {
|
|
138
|
+
href = joinURL("/", code, e._pathWithoutPrefix);
|
|
139
|
+
}
|
|
110
140
|
}
|
|
111
141
|
}
|
|
112
142
|
if (!filterPath(href))
|
|
@@ -151,16 +181,12 @@ export async function buildSitemapUrls(sitemap, resolvers, runtimeConfig, nitro)
|
|
|
151
181
|
// chunking
|
|
152
182
|
defaultSitemapsChunkSize
|
|
153
183
|
} = runtimeConfig;
|
|
154
|
-
const
|
|
184
|
+
const chunkInfo = parseChunkInfo(sitemap.sitemapName, sitemaps, defaultSitemapsChunkSize);
|
|
155
185
|
function maybeSort(urls) {
|
|
156
|
-
return sortEntries ?
|
|
186
|
+
return sortEntries ? sortInPlace(urls) : urls;
|
|
157
187
|
}
|
|
158
188
|
function maybeSlice(urls) {
|
|
159
|
-
|
|
160
|
-
const chunk = Number(sitemap.sitemapName);
|
|
161
|
-
return urls.slice(chunk * defaultSitemapsChunkSize, (chunk + 1) * defaultSitemapsChunkSize);
|
|
162
|
-
}
|
|
163
|
-
return urls;
|
|
189
|
+
return sliceUrlsForChunk(urls, sitemap.sitemapName, sitemaps, defaultSitemapsChunkSize);
|
|
164
190
|
}
|
|
165
191
|
if (autoI18n?.differentDomains) {
|
|
166
192
|
const domain = autoI18n.locales.find((e) => [e.language, e.code].includes(sitemap.sitemapName))?.domain;
|
|
@@ -175,8 +201,22 @@ export async function buildSitemapUrls(sitemap, resolvers, runtimeConfig, nitro)
|
|
|
175
201
|
});
|
|
176
202
|
}
|
|
177
203
|
}
|
|
178
|
-
|
|
179
|
-
|
|
204
|
+
let effectiveSitemap = sitemap;
|
|
205
|
+
const baseSitemapName = chunkInfo.baseSitemapName;
|
|
206
|
+
if (chunkInfo.isChunked && baseSitemapName !== sitemap.sitemapName && sitemaps[baseSitemapName]) {
|
|
207
|
+
effectiveSitemap = sitemaps[baseSitemapName];
|
|
208
|
+
}
|
|
209
|
+
let sourcesInput = effectiveSitemap.includeAppSources ? await globalSitemapSources() : [];
|
|
210
|
+
sourcesInput.push(...await childSitemapSources(effectiveSitemap));
|
|
211
|
+
if (nitro && resolvers.event) {
|
|
212
|
+
const ctx = {
|
|
213
|
+
event: resolvers.event,
|
|
214
|
+
sitemapName: baseSitemapName,
|
|
215
|
+
sources: sourcesInput
|
|
216
|
+
};
|
|
217
|
+
await nitro.hooks.callHook("sitemap:sources", ctx);
|
|
218
|
+
sourcesInput = ctx.sources;
|
|
219
|
+
}
|
|
180
220
|
const sources = await resolveSitemapSources(sourcesInput, resolvers.event);
|
|
181
221
|
const resolvedCtx = {
|
|
182
222
|
urls: sources.flatMap((s) => s.urls),
|
|
@@ -193,18 +233,4 @@ export async function buildSitemapUrls(sitemap, resolvers, runtimeConfig, nitro)
|
|
|
193
233
|
const sortedUrls = maybeSort(filteredUrls);
|
|
194
234
|
return maybeSlice(sortedUrls);
|
|
195
235
|
}
|
|
196
|
-
export
|
|
197
|
-
const urlset = urls.map((e) => {
|
|
198
|
-
const keys = Object.keys(e).filter((k) => !k.startsWith("_"));
|
|
199
|
-
return [
|
|
200
|
-
" <url>",
|
|
201
|
-
keys.map((k) => handleEntry(k, e)).filter(Boolean).join("\n"),
|
|
202
|
-
" </url>"
|
|
203
|
-
].join("\n");
|
|
204
|
-
});
|
|
205
|
-
return wrapSitemapXml([
|
|
206
|
-
'<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">',
|
|
207
|
-
urlset.join("\n"),
|
|
208
|
-
"</urlset>"
|
|
209
|
-
], resolvers, { version, xsl, credits, minify });
|
|
210
|
-
}
|
|
236
|
+
export { urlsToXml } from "./xml.js";
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { ModuleRuntimeConfig, NitroUrlResolvers } from '../../../types.js';
|
|
2
|
-
export declare function handleEntry(k: string, e: Record<string, any> | (string | Record<string, any>)[]): string | false;
|
|
3
|
-
export declare function wrapSitemapXml(input: string[], resolvers: NitroUrlResolvers, options: Pick<ModuleRuntimeConfig, 'version' | 'xsl' | 'credits' | 'minify'>): string;
|
|
1
|
+
import type { ModuleRuntimeConfig, NitroUrlResolvers, ResolvedSitemapUrl } from '../../../types.js';
|
|
4
2
|
export declare function escapeValueForXml(value: boolean | string | number): string;
|
|
3
|
+
export declare function urlsToXml(urls: ResolvedSitemapUrl[], resolvers: NitroUrlResolvers, { version, xsl, credits, minify }: Pick<ModuleRuntimeConfig, 'version' | 'xsl' | 'credits' | 'minify'>): string;
|
|
@@ -1,86 +1,188 @@
|
|
|
1
|
-
function
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
case "videos":
|
|
6
|
-
return "video";
|
|
7
|
-
// news & others?
|
|
8
|
-
case "news":
|
|
9
|
-
return "news";
|
|
10
|
-
default:
|
|
11
|
-
return k;
|
|
12
|
-
}
|
|
1
|
+
export function escapeValueForXml(value) {
|
|
2
|
+
if (value === true || value === false)
|
|
3
|
+
return value ? "yes" : "no";
|
|
4
|
+
return String(value).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
13
5
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
6
|
+
const URLSET_OPENING_TAG = '<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">';
|
|
7
|
+
function buildUrlXml(url) {
|
|
8
|
+
const capacity = 50;
|
|
9
|
+
const parts = Array.from({ length: capacity });
|
|
10
|
+
let partIndex = 0;
|
|
11
|
+
parts[partIndex++] = " <url>";
|
|
12
|
+
if (url.loc) {
|
|
13
|
+
parts[partIndex++] = ` <loc>${escapeValueForXml(url.loc)}</loc>`;
|
|
14
|
+
}
|
|
15
|
+
if (url.lastmod) {
|
|
16
|
+
parts[partIndex++] = ` <lastmod>${url.lastmod}</lastmod>`;
|
|
17
|
+
}
|
|
18
|
+
if (url.changefreq) {
|
|
19
|
+
parts[partIndex++] = ` <changefreq>${url.changefreq}</changefreq>`;
|
|
20
|
+
}
|
|
21
|
+
if (url.priority !== void 0) {
|
|
22
|
+
const priorityValue = Number.parseFloat(String(url.priority));
|
|
23
|
+
const formattedPriority = priorityValue % 1 === 0 ? String(priorityValue) : priorityValue.toFixed(1);
|
|
24
|
+
parts[partIndex++] = ` <priority>${formattedPriority}</priority>`;
|
|
25
|
+
}
|
|
26
|
+
const keys = Object.keys(url).filter((k) => !k.startsWith("_") && !["loc", "lastmod", "changefreq", "priority"].includes(k));
|
|
27
|
+
for (const key of keys) {
|
|
28
|
+
const value = url[key];
|
|
29
|
+
if (value === void 0 || value === null) continue;
|
|
30
|
+
switch (key) {
|
|
31
|
+
case "alternatives":
|
|
32
|
+
if (Array.isArray(value) && value.length > 0) {
|
|
33
|
+
for (const alt of value) {
|
|
34
|
+
const attrs = Object.entries(alt).map(([k, v]) => `${k}="${escapeValueForXml(v)}"`).join(" ");
|
|
35
|
+
parts[partIndex++] = ` <xhtml:link rel="alternate" ${attrs} />`;
|
|
27
36
|
}
|
|
28
|
-
const attributes = Object.entries(v).filter(([ssk]) => ssk !== sk).map(([ssk, ssv]) => `${ssk}="${escapeValueForXml(ssv)}"`).join(" ");
|
|
29
|
-
return [
|
|
30
|
-
` <${key}:${sk} ${attributes}>`,
|
|
31
|
-
// value is the same sk
|
|
32
|
-
v[sk],
|
|
33
|
-
`</${key}:${sk}>`
|
|
34
|
-
].join("");
|
|
35
|
-
}).join("\n");
|
|
36
|
-
}
|
|
37
|
-
if (typeof sv === "object") {
|
|
38
|
-
if (key === "video") {
|
|
39
|
-
const attributes = Object.entries(sv).filter(([ssk]) => ssk !== sk).map(([ssk, ssv]) => `${ssk}="${escapeValueForXml(ssv)}"`).join(" ");
|
|
40
|
-
return [
|
|
41
|
-
` <${key}:${sk} ${attributes}>`,
|
|
42
|
-
// value is the same sk
|
|
43
|
-
sv[sk],
|
|
44
|
-
`</${key}:${sk}>`
|
|
45
|
-
].join("");
|
|
46
37
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
38
|
+
break;
|
|
39
|
+
case "images":
|
|
40
|
+
if (Array.isArray(value) && value.length > 0) {
|
|
41
|
+
for (const img of value) {
|
|
42
|
+
parts[partIndex++] = " <image:image>";
|
|
43
|
+
parts[partIndex++] = ` <image:loc>${escapeValueForXml(img.loc)}</image:loc>`;
|
|
44
|
+
if (img.title) parts[partIndex++] = ` <image:title>${escapeValueForXml(img.title)}</image:title>`;
|
|
45
|
+
if (img.caption) parts[partIndex++] = ` <image:caption>${escapeValueForXml(img.caption)}</image:caption>`;
|
|
46
|
+
if (img.geo_location) parts[partIndex++] = ` <image:geo_location>${escapeValueForXml(img.geo_location)}</image:geo_location>`;
|
|
47
|
+
if (img.license) parts[partIndex++] = ` <image:license>${escapeValueForXml(img.license)}</image:license>`;
|
|
48
|
+
parts[partIndex++] = " </image:image>";
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
break;
|
|
52
|
+
case "videos":
|
|
53
|
+
if (Array.isArray(value) && value.length > 0) {
|
|
54
|
+
for (const video of value) {
|
|
55
|
+
parts[partIndex++] = " <video:video>";
|
|
56
|
+
parts[partIndex++] = ` <video:title>${escapeValueForXml(video.title)}</video:title>`;
|
|
57
|
+
if (video.thumbnail_loc) {
|
|
58
|
+
parts[partIndex++] = ` <video:thumbnail_loc>${escapeValueForXml(video.thumbnail_loc)}</video:thumbnail_loc>`;
|
|
59
|
+
}
|
|
60
|
+
parts[partIndex++] = ` <video:description>${escapeValueForXml(video.description)}</video:description>`;
|
|
61
|
+
if (video.content_loc) {
|
|
62
|
+
parts[partIndex++] = ` <video:content_loc>${escapeValueForXml(video.content_loc)}</video:content_loc>`;
|
|
63
|
+
}
|
|
64
|
+
if (video.player_loc) {
|
|
65
|
+
const attrs = video.player_loc.allow_embed ? ' allow_embed="yes"' : "";
|
|
66
|
+
const autoplay = video.player_loc.autoplay ? ' autoplay="yes"' : "";
|
|
67
|
+
parts[partIndex++] = ` <video:player_loc${attrs}${autoplay}>${escapeValueForXml(video.player_loc)}</video:player_loc>`;
|
|
68
|
+
}
|
|
69
|
+
if (video.duration !== void 0) {
|
|
70
|
+
parts[partIndex++] = ` <video:duration>${video.duration}</video:duration>`;
|
|
71
|
+
}
|
|
72
|
+
if (video.expiration_date) {
|
|
73
|
+
parts[partIndex++] = ` <video:expiration_date>${video.expiration_date}</video:expiration_date>`;
|
|
74
|
+
}
|
|
75
|
+
if (video.rating !== void 0) {
|
|
76
|
+
parts[partIndex++] = ` <video:rating>${video.rating}</video:rating>`;
|
|
77
|
+
}
|
|
78
|
+
if (video.view_count !== void 0) {
|
|
79
|
+
parts[partIndex++] = ` <video:view_count>${video.view_count}</video:view_count>`;
|
|
80
|
+
}
|
|
81
|
+
if (video.publication_date) {
|
|
82
|
+
parts[partIndex++] = ` <video:publication_date>${video.publication_date}</video:publication_date>`;
|
|
83
|
+
}
|
|
84
|
+
if (video.family_friendly !== void 0) {
|
|
85
|
+
parts[partIndex++] = ` <video:family_friendly>${video.family_friendly === "yes" || video.family_friendly === true ? "yes" : "no"}</video:family_friendly>`;
|
|
86
|
+
}
|
|
87
|
+
if (video.restriction) {
|
|
88
|
+
const relationship = video.restriction.relationship || "allow";
|
|
89
|
+
parts[partIndex++] = ` <video:restriction relationship="${relationship}">${escapeValueForXml(video.restriction.restriction)}</video:restriction>`;
|
|
90
|
+
}
|
|
91
|
+
if (video.platform) {
|
|
92
|
+
const relationship = video.platform.relationship || "allow";
|
|
93
|
+
parts[partIndex++] = ` <video:platform relationship="${relationship}">${escapeValueForXml(video.platform.platform)}</video:platform>`;
|
|
94
|
+
}
|
|
95
|
+
if (video.requires_subscription !== void 0) {
|
|
96
|
+
parts[partIndex++] = ` <video:requires_subscription>${video.requires_subscription === "yes" || video.requires_subscription === true ? "yes" : "no"}</video:requires_subscription>`;
|
|
97
|
+
}
|
|
98
|
+
if (video.price) {
|
|
99
|
+
const prices = Array.isArray(video.price) ? video.price : [video.price];
|
|
100
|
+
for (const price of prices) {
|
|
101
|
+
const attrs = [];
|
|
102
|
+
if (price.currency) attrs.push(`currency="${price.currency}"`);
|
|
103
|
+
if (price.type) attrs.push(`type="${price.type}"`);
|
|
104
|
+
const attrsStr = attrs.length > 0 ? " " + attrs.join(" ") : "";
|
|
105
|
+
parts[partIndex++] = ` <video:price${attrsStr}>${escapeValueForXml(price.price)}</video:price>`;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (video.uploader) {
|
|
109
|
+
const info = video.uploader.info ? ` info="${escapeValueForXml(video.uploader.info)}"` : "";
|
|
110
|
+
parts[partIndex++] = ` <video:uploader${info}>${escapeValueForXml(video.uploader.uploader)}</video:uploader>`;
|
|
111
|
+
}
|
|
112
|
+
if (video.live !== void 0) {
|
|
113
|
+
parts[partIndex++] = ` <video:live>${video.live === "yes" || video.live === true ? "yes" : "no"}</video:live>`;
|
|
114
|
+
}
|
|
115
|
+
if (video.tag) {
|
|
116
|
+
const tags = Array.isArray(video.tag) ? video.tag : [video.tag];
|
|
117
|
+
for (const tag of tags) {
|
|
118
|
+
parts[partIndex++] = ` <video:tag>${escapeValueForXml(tag)}</video:tag>`;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (video.category) {
|
|
122
|
+
parts[partIndex++] = ` <video:category>${escapeValueForXml(video.category)}</video:category>`;
|
|
123
|
+
}
|
|
124
|
+
if (video.gallery_loc) {
|
|
125
|
+
const title = video.gallery_loc.title ? ` title="${escapeValueForXml(video.gallery_loc.title)}"` : "";
|
|
126
|
+
parts[partIndex++] = ` <video:gallery_loc${title}>${escapeValueForXml(video.gallery_loc)}</video:gallery_loc>`;
|
|
127
|
+
}
|
|
128
|
+
parts[partIndex++] = " </video:video>";
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
break;
|
|
132
|
+
case "news":
|
|
133
|
+
if (value) {
|
|
134
|
+
parts[partIndex++] = " <news:news>";
|
|
135
|
+
parts[partIndex++] = " <news:publication>";
|
|
136
|
+
parts[partIndex++] = ` <news:name>${escapeValueForXml(value.publication.name)}</news:name>`;
|
|
137
|
+
parts[partIndex++] = ` <news:language>${escapeValueForXml(value.publication.language)}</news:language>`;
|
|
138
|
+
parts[partIndex++] = " </news:publication>";
|
|
139
|
+
if (value.title) {
|
|
140
|
+
parts[partIndex++] = ` <news:title>${escapeValueForXml(value.title)}</news:title>`;
|
|
141
|
+
}
|
|
142
|
+
if (value.publication_date) {
|
|
143
|
+
parts[partIndex++] = ` <news:publication_date>${value.publication_date}</news:publication_date>`;
|
|
144
|
+
}
|
|
145
|
+
if (value.access) {
|
|
146
|
+
parts[partIndex++] = ` <news:access>${value.access}</news:access>`;
|
|
147
|
+
}
|
|
148
|
+
if (value.genres) {
|
|
149
|
+
parts[partIndex++] = ` <news:genres>${escapeValueForXml(value.genres)}</news:genres>`;
|
|
150
|
+
}
|
|
151
|
+
if (value.keywords) {
|
|
152
|
+
parts[partIndex++] = ` <news:keywords>${escapeValueForXml(value.keywords)}</news:keywords>`;
|
|
153
|
+
}
|
|
154
|
+
if (value.stock_tickers) {
|
|
155
|
+
parts[partIndex++] = ` <news:stock_tickers>${escapeValueForXml(value.stock_tickers)}</news:stock_tickers>`;
|
|
156
|
+
}
|
|
157
|
+
parts[partIndex++] = " </news:news>";
|
|
158
|
+
}
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
66
161
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
export function handleEntry(k, e) {
|
|
70
|
-
return Array.isArray(e[k]) ? handleArray(k, e[k]) : typeof e[k] === "object" ? handleObject(k, e[k]) : ` <${k}>${escapeValueForXml(e[k])}</${k}>`;
|
|
162
|
+
parts[partIndex++] = " </url>";
|
|
163
|
+
return parts.slice(0, partIndex).join("\n");
|
|
71
164
|
}
|
|
72
|
-
export function
|
|
73
|
-
const
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
165
|
+
export function urlsToXml(urls, resolvers, { version, xsl, credits, minify }) {
|
|
166
|
+
const estimatedSize = urls.length + 5;
|
|
167
|
+
const xmlParts = Array.from({ length: estimatedSize });
|
|
168
|
+
let partIndex = 0;
|
|
169
|
+
const xslHref = xsl ? resolvers.relativeBaseUrlResolver(xsl) : false;
|
|
170
|
+
if (xslHref) {
|
|
171
|
+
xmlParts[partIndex++] = `<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet type="text/xsl" href="${xslHref}"?>`;
|
|
172
|
+
} else {
|
|
173
|
+
xmlParts[partIndex++] = '<?xml version="1.0" encoding="UTF-8"?>';
|
|
174
|
+
}
|
|
175
|
+
xmlParts[partIndex++] = URLSET_OPENING_TAG;
|
|
176
|
+
for (const url of urls) {
|
|
177
|
+
xmlParts[partIndex++] = buildUrlXml(url);
|
|
178
|
+
}
|
|
179
|
+
xmlParts[partIndex++] = "</urlset>";
|
|
180
|
+
if (credits) {
|
|
181
|
+
xmlParts[partIndex++] = `<!-- XML Sitemap generated by @nuxtjs/sitemap v${version} at ${(/* @__PURE__ */ new Date()).toISOString()} -->`;
|
|
182
|
+
}
|
|
183
|
+
const xmlContent = xmlParts.slice(0, partIndex);
|
|
184
|
+
if (minify) {
|
|
185
|
+
return xmlContent.join("").replace(/(?<!<[^>]*)\s(?![^<]*>)/g, "");
|
|
186
|
+
}
|
|
187
|
+
return xmlContent.join("\n");
|
|
86
188
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { getQuery, setHeader, createError } from "h3";
|
|
1
|
+
import { getQuery, setHeader, createError, getHeader } from "h3";
|
|
2
2
|
import { fixSlashes } from "nuxt-site-config/urls";
|
|
3
3
|
import { defu } from "defu";
|
|
4
|
-
import { useNitroApp } from "nitropack/runtime";
|
|
4
|
+
import { useNitroApp, defineCachedFunction } from "nitropack/runtime";
|
|
5
5
|
import { logger, mergeOnKey, splitForLocales } from "../../utils-pure.js";
|
|
6
6
|
import { createNitroRouteRuleMatcher } from "../kit.js";
|
|
7
7
|
import { buildSitemapUrls, urlsToXml } from "./builder/sitemap.js";
|
|
8
8
|
import { normaliseEntry, preNormalizeEntry } from "./urlset/normalise.js";
|
|
9
|
-
import {
|
|
9
|
+
import { sortInPlace } from "./urlset/sort.js";
|
|
10
10
|
import { getPathRobotConfig } from "#imports";
|
|
11
11
|
import { useSiteConfig } from "#site-config/server/composables/useSiteConfig";
|
|
12
12
|
import { createSitePathResolver } from "#site-config/server/composables/utils";
|
|
@@ -26,7 +26,7 @@ export function useNitroUrlResolvers(e) {
|
|
|
26
26
|
relativeBaseUrlResolver: createSitePathResolver(e, { absolute: false, withBase: true })
|
|
27
27
|
};
|
|
28
28
|
}
|
|
29
|
-
|
|
29
|
+
async function buildSitemapXml(event, definition, resolvers, runtimeConfig) {
|
|
30
30
|
const { sitemapName } = definition;
|
|
31
31
|
const nitro = useNitroApp();
|
|
32
32
|
if (import.meta.prerender) {
|
|
@@ -41,14 +41,15 @@ export async function createSitemap(event, definition, runtimeConfig) {
|
|
|
41
41
|
});
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
|
-
const
|
|
45
|
-
let sitemapUrls = await buildSitemapUrls(definition, resolvers, runtimeConfig, nitro);
|
|
44
|
+
const sitemapUrls = await buildSitemapUrls(definition, resolvers, runtimeConfig, nitro);
|
|
46
45
|
const routeRuleMatcher = createNitroRouteRuleMatcher();
|
|
47
46
|
const { autoI18n } = runtimeConfig;
|
|
48
|
-
|
|
47
|
+
let validCount = 0;
|
|
48
|
+
for (let i = 0; i < sitemapUrls.length; i++) {
|
|
49
|
+
const u = sitemapUrls[i];
|
|
49
50
|
const path = u._path?.pathname || u.loc;
|
|
50
51
|
if (!getPathRobotConfig(event, { path, skipSiteIndexable: true }).indexable)
|
|
51
|
-
|
|
52
|
+
continue;
|
|
52
53
|
let routeRules = routeRuleMatcher(path);
|
|
53
54
|
if (autoI18n?.locales && autoI18n?.strategy !== "no_prefix") {
|
|
54
55
|
const match = splitForLocales(path, autoI18n.locales.map((l) => l.code));
|
|
@@ -57,15 +58,15 @@ export async function createSitemap(event, definition, runtimeConfig) {
|
|
|
57
58
|
routeRules = defu(routeRules, routeRuleMatcher(pathWithoutPrefix));
|
|
58
59
|
}
|
|
59
60
|
if (routeRules.sitemap === false)
|
|
60
|
-
|
|
61
|
-
if (typeof routeRules.robots !== "undefined" && !routeRules.robots)
|
|
62
|
-
|
|
63
|
-
}
|
|
61
|
+
continue;
|
|
62
|
+
if (typeof routeRules.robots !== "undefined" && !routeRules.robots)
|
|
63
|
+
continue;
|
|
64
64
|
const hasRobotsDisabled = Object.entries(routeRules.headers || {}).some(([name, value]) => name.toLowerCase() === "x-robots-tag" && value.toLowerCase().includes("noindex"));
|
|
65
65
|
if (routeRules.redirect || hasRobotsDisabled)
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
66
|
+
continue;
|
|
67
|
+
sitemapUrls[validCount++] = routeRules.sitemap ? defu(u, routeRules.sitemap) : u;
|
|
68
|
+
}
|
|
69
|
+
sitemapUrls.length = validCount;
|
|
69
70
|
const locSize = sitemapUrls.length;
|
|
70
71
|
const resolvedCtx = {
|
|
71
72
|
urls: sitemapUrls,
|
|
@@ -76,17 +77,64 @@ export async function createSitemap(event, definition, runtimeConfig) {
|
|
|
76
77
|
if (resolvedCtx.urls.length !== locSize) {
|
|
77
78
|
resolvedCtx.urls = resolvedCtx.urls.map((e) => preNormalizeEntry(e, resolvers));
|
|
78
79
|
}
|
|
79
|
-
const maybeSort = (urls2) => runtimeConfig.sortEntries ?
|
|
80
|
+
const maybeSort = (urls2) => runtimeConfig.sortEntries ? sortInPlace(urls2) : urls2;
|
|
80
81
|
const normalizedPreDedupe = resolvedCtx.urls.map((e) => normaliseEntry(e, definition.defaults, resolvers));
|
|
81
82
|
const urls = maybeSort(mergeOnKey(normalizedPreDedupe, "_key").map((e) => normaliseEntry(e, definition.defaults, resolvers)));
|
|
83
|
+
if (definition._isChunking && definition.sitemapName.includes("-")) {
|
|
84
|
+
const parts = definition.sitemapName.split("-");
|
|
85
|
+
const lastPart = parts.pop();
|
|
86
|
+
if (!Number.isNaN(Number(lastPart))) {
|
|
87
|
+
const chunkIndex = Number(lastPart);
|
|
88
|
+
const baseSitemapName = parts.join("-");
|
|
89
|
+
if (urls.length === 0 && chunkIndex > 0) {
|
|
90
|
+
throw createError({
|
|
91
|
+
statusCode: 404,
|
|
92
|
+
message: `Sitemap chunk ${chunkIndex} for "${baseSitemapName}" does not exist.`
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
82
97
|
const sitemap = urlsToXml(urls, resolvers, runtimeConfig);
|
|
83
98
|
const ctx = { sitemap, sitemapName, event };
|
|
84
99
|
await nitro.hooks.callHook("sitemap:output", ctx);
|
|
100
|
+
return ctx.sitemap;
|
|
101
|
+
}
|
|
102
|
+
const buildSitemapXmlCached = defineCachedFunction(
|
|
103
|
+
buildSitemapXml,
|
|
104
|
+
{
|
|
105
|
+
name: "sitemap:xml",
|
|
106
|
+
group: "sitemap",
|
|
107
|
+
maxAge: 60 * 10,
|
|
108
|
+
// Default 10 minutes
|
|
109
|
+
base: "sitemap",
|
|
110
|
+
// Use the sitemap storage
|
|
111
|
+
getKey: (event, definition) => {
|
|
112
|
+
const host = getHeader(event, "host") || getHeader(event, "x-forwarded-host") || "";
|
|
113
|
+
const proto = getHeader(event, "x-forwarded-proto") || "https";
|
|
114
|
+
const sitemapName = definition.sitemapName || "default";
|
|
115
|
+
return `${sitemapName}-${proto}-${host}`;
|
|
116
|
+
},
|
|
117
|
+
swr: true
|
|
118
|
+
// Enable stale-while-revalidate
|
|
119
|
+
}
|
|
120
|
+
);
|
|
121
|
+
export async function createSitemap(event, definition, runtimeConfig) {
|
|
122
|
+
const resolvers = useNitroUrlResolvers(event);
|
|
123
|
+
const shouldCache = !import.meta.dev && runtimeConfig.cacheMaxAgeSeconds > 0;
|
|
124
|
+
const xml = shouldCache ? await buildSitemapXmlCached(event, definition, resolvers, runtimeConfig) : await buildSitemapXml(event, definition, resolvers, runtimeConfig);
|
|
85
125
|
setHeader(event, "Content-Type", "text/xml; charset=UTF-8");
|
|
86
|
-
if (runtimeConfig.cacheMaxAgeSeconds)
|
|
87
|
-
setHeader(event, "Cache-Control", `public, max-age=${runtimeConfig.cacheMaxAgeSeconds},
|
|
88
|
-
|
|
126
|
+
if (runtimeConfig.cacheMaxAgeSeconds) {
|
|
127
|
+
setHeader(event, "Cache-Control", `public, max-age=${runtimeConfig.cacheMaxAgeSeconds}, s-maxage=${runtimeConfig.cacheMaxAgeSeconds}, stale-while-revalidate=3600`);
|
|
128
|
+
const now = /* @__PURE__ */ new Date();
|
|
129
|
+
setHeader(event, "X-Sitemap-Generated", now.toISOString());
|
|
130
|
+
setHeader(event, "X-Sitemap-Cache-Duration", `${runtimeConfig.cacheMaxAgeSeconds}s`);
|
|
131
|
+
const expiryTime = new Date(now.getTime() + runtimeConfig.cacheMaxAgeSeconds * 1e3);
|
|
132
|
+
setHeader(event, "X-Sitemap-Cache-Expires", expiryTime.toISOString());
|
|
133
|
+
const remainingSeconds = Math.floor((expiryTime.getTime() - now.getTime()) / 1e3);
|
|
134
|
+
setHeader(event, "X-Sitemap-Cache-Remaining", `${remainingSeconds}s`);
|
|
135
|
+
} else {
|
|
89
136
|
setHeader(event, "Cache-Control", `no-cache, no-store`);
|
|
137
|
+
}
|
|
90
138
|
event.context._isSitemap = true;
|
|
91
|
-
return
|
|
139
|
+
return xml;
|
|
92
140
|
}
|
|
@@ -75,29 +75,31 @@ export function normaliseEntry(_e, defaults, resolvers) {
|
|
|
75
75
|
delete e.lastmod;
|
|
76
76
|
e.loc = resolve(e.loc, resolvers);
|
|
77
77
|
if (e.alternatives) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
78
|
+
const alternatives = e.alternatives;
|
|
79
|
+
for (let i = 0; i < alternatives.length; i++) {
|
|
80
|
+
const alt = alternatives[i];
|
|
81
|
+
if (typeof alt.href === "string") {
|
|
82
|
+
alt.href = resolve(alt.href, resolvers);
|
|
83
|
+
} else if (typeof alt.href === "object" && alt.href) {
|
|
84
|
+
alt.href = resolve(alt.href.href, resolvers);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
e.alternatives = mergeOnKey(alternatives, "hreflang");
|
|
86
88
|
}
|
|
87
89
|
if (e.images) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
i.loc = resolve(i.loc, resolvers);
|
|
91
|
-
|
|
92
|
-
|
|
90
|
+
const images = e.images;
|
|
91
|
+
for (let i = 0; i < images.length; i++) {
|
|
92
|
+
images[i].loc = resolve(images[i].loc, resolvers);
|
|
93
|
+
}
|
|
94
|
+
e.images = mergeOnKey(images, "loc");
|
|
93
95
|
}
|
|
94
96
|
if (e.videos) {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
if (
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}
|
|
97
|
+
const videos = e.videos;
|
|
98
|
+
for (let i = 0; i < videos.length; i++) {
|
|
99
|
+
if (videos[i].content_loc) {
|
|
100
|
+
videos[i].content_loc = resolve(videos[i].content_loc, resolvers);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
101
103
|
}
|
|
102
104
|
return e;
|
|
103
105
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { ResolvedSitemapUrl, SitemapUrlInput } from '../../../types.js';
|
|
2
|
-
export declare function
|
|
2
|
+
export declare function sortInPlace<T extends SitemapUrlInput[] | ResolvedSitemapUrl[]>(urls: T): T;
|