@nuxtjs/sitemap 7.2.10 → 7.3.1
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 +10 -9
- package/dist/client/404.html +10 -9
- package/dist/client/_nuxt/{DDzCRRw4.js → 5vafBU9X.js} +1 -1
- package/dist/client/_nuxt/BIHI7g3E.js +1 -0
- package/dist/client/_nuxt/Bn78IMkz.js +172 -0
- package/dist/client/_nuxt/{DdvkoY3I.js → CT3BV8Rj.js} +1 -1
- package/dist/client/_nuxt/Cp-IABpG.js +1 -0
- package/dist/client/_nuxt/builds/latest.json +1 -1
- package/dist/client/_nuxt/builds/meta/5ecca6e1-2b8a-4fc5-a128-35cbc27bf6d7.json +1 -0
- package/dist/client/_nuxt/{entry.BrROiVtQ.css → entry.BzbtAPc0.css} +1 -1
- package/dist/client/_nuxt/error-404.D_zhMyJm.css +1 -0
- package/dist/client/_nuxt/error-500.rdOYVbxo.css +1 -0
- package/dist/client/index.html +10 -9
- package/dist/module.cjs +59 -20
- package/dist/module.json +2 -2
- package/dist/module.mjs +60 -21
- package/dist/runtime/server/plugins/warm-up.js +20 -4
- package/dist/runtime/server/routes/__sitemap__/debug.js +2 -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/package.json +23 -22
- package/dist/client/_nuxt/BLmTiKMJ.js +0 -1
- package/dist/client/_nuxt/BUP090M8.js +0 -172
- package/dist/client/_nuxt/builds/meta/3c351607-eab3-459a-b743-aba04e49a80e.json +0 -1
- package/dist/client/_nuxt/error-404.BMkETmdU.css +0 -1
- package/dist/client/_nuxt/error-500.C3_I-O7u.css +0 -1
package/dist/module.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useNuxt, loadNuxtModuleInstance, createResolver, addTemplate,
|
|
1
|
+
import { useNuxt, loadNuxtModuleInstance, createResolver, addTemplate, extendPages, tryUseNuxt, defineNuxtModule, useLogger, hasNuxtModule, getNuxtModuleVersion, hasNuxtModuleCompatibility, addServerImports, addServerPlugin, resolveModule, addServerHandler, addPrerenderRoutes } from '@nuxt/kit';
|
|
2
2
|
import { withHttps, withBase, parseURL, joinURL, withTrailingSlash, withoutLeadingSlash, withLeadingSlash, withoutTrailingSlash } from 'ufo';
|
|
3
3
|
import { withSiteUrl, installNuxtSiteConfig } from 'nuxt-site-config/kit';
|
|
4
4
|
import { defu } from 'defu';
|
|
@@ -450,9 +450,9 @@ function setupPrerenderHandler(_options, nuxt = useNuxt()) {
|
|
|
450
450
|
}), route._sitemap);
|
|
451
451
|
});
|
|
452
452
|
nitro.hooks.hook("prerender:done", async () => {
|
|
453
|
-
const
|
|
453
|
+
const isNuxt5 = nuxt.options._majorVersion === 5;
|
|
454
454
|
let nitroModule;
|
|
455
|
-
if (
|
|
455
|
+
if (isNuxt5) {
|
|
456
456
|
nitroModule = await import(String("nitro"));
|
|
457
457
|
} else {
|
|
458
458
|
nitroModule = await import(String("nitropack"));
|
|
@@ -740,11 +740,11 @@ const module = defineNuxtModule({
|
|
|
740
740
|
const locale = normalisedLocales.find((l) => l.code === localeCode);
|
|
741
741
|
if (!locale || !pageLocales[localeCode] || pageLocales[localeCode].includes("["))
|
|
742
742
|
continue;
|
|
743
|
-
const alternatives = Object.keys(pageLocales).map((l) => ({
|
|
743
|
+
const alternatives = Object.keys(pageLocales).filter((l) => pageLocales[l] !== false).map((l) => ({
|
|
744
744
|
hreflang: normalisedLocales.find((nl) => nl.code === l)?._hreflang || l,
|
|
745
745
|
href: generatePathForI18nPages({ localeCode: l, pageLocales: pageLocales[l], nuxtI18nConfig, normalisedLocales })
|
|
746
746
|
}));
|
|
747
|
-
if (alternatives.length && nuxtI18nConfig.defaultLocale && pageLocales[nuxtI18nConfig.defaultLocale])
|
|
747
|
+
if (alternatives.length && nuxtI18nConfig.defaultLocale && pageLocales[nuxtI18nConfig.defaultLocale] && pageLocales[nuxtI18nConfig.defaultLocale] !== false)
|
|
748
748
|
alternatives.push({ hreflang: "x-default", href: generatePathForI18nPages({ normalisedLocales, localeCode: nuxtI18nConfig.defaultLocale, pageLocales: pageLocales[nuxtI18nConfig.defaultLocale], nuxtI18nConfig }) });
|
|
749
749
|
i18nPagesSources.urls.push({
|
|
750
750
|
_sitemap: locale._sitemap,
|
|
@@ -774,7 +774,9 @@ const module = defineNuxtModule({
|
|
|
774
774
|
differentDomains: nuxtI18nConfig.differentDomains,
|
|
775
775
|
defaultLocale: nuxtI18nConfig.defaultLocale,
|
|
776
776
|
locales: normalisedLocales,
|
|
777
|
-
strategy: nuxtI18nConfig.strategy
|
|
777
|
+
strategy: nuxtI18nConfig.strategy,
|
|
778
|
+
// @ts-expect-error untyped
|
|
779
|
+
pages: nuxtI18nConfig.pages
|
|
778
780
|
};
|
|
779
781
|
}
|
|
780
782
|
let canI18nMap = config.sitemaps !== false && nuxtI18nConfig.strategy !== "no_prefix";
|
|
@@ -831,6 +833,7 @@ declare module 'nitropack' {
|
|
|
831
833
|
'sitemap:input': (ctx: import('${typesPath}').SitemapInputCtx) => void | Promise<void>
|
|
832
834
|
'sitemap:resolved': (ctx: import('${typesPath}').SitemapRenderCtx) => void | Promise<void>
|
|
833
835
|
'sitemap:output': (ctx: import('${typesPath}').SitemapOutputHookCtx) => void | Promise<void>
|
|
836
|
+
'sitemap:sources': (ctx: import('${typesPath}').SitemapSourcesHookCtx) => void | Promise<void>
|
|
834
837
|
}
|
|
835
838
|
}
|
|
836
839
|
declare module 'vue-router' {
|
|
@@ -840,7 +843,6 @@ declare module 'vue-router' {
|
|
|
840
843
|
}
|
|
841
844
|
`;
|
|
842
845
|
});
|
|
843
|
-
const nitroPreset = resolveNitroPreset();
|
|
844
846
|
const prerenderedRoutes = nuxt.options.nitro.prerender?.routes || [];
|
|
845
847
|
const prerenderSitemap = isNuxtGenerate() || includesSitemapRoot(config.sitemapName, prerenderedRoutes);
|
|
846
848
|
const routeRules = {};
|
|
@@ -852,17 +854,6 @@ declare module 'vue-router' {
|
|
|
852
854
|
"X-Sitemap-Prerendered": (/* @__PURE__ */ new Date()).toISOString()
|
|
853
855
|
};
|
|
854
856
|
}
|
|
855
|
-
if (!nuxt.options.dev && !isNuxtGenerate() && config.cacheMaxAgeSeconds && config.runtimeCacheStorage !== false) {
|
|
856
|
-
routeRules[nitroPreset.includes("vercel") ? "isr" : "swr"] = config.cacheMaxAgeSeconds;
|
|
857
|
-
routeRules.cache = {
|
|
858
|
-
// handle multi-tenancy
|
|
859
|
-
swr: true,
|
|
860
|
-
maxAge: config.cacheMaxAgeSeconds,
|
|
861
|
-
varies: ["X-Forwarded-Host", "X-Forwarded-Proto", "Host"]
|
|
862
|
-
};
|
|
863
|
-
if (typeof config.runtimeCacheStorage === "object")
|
|
864
|
-
routeRules.cache.base = "sitemap";
|
|
865
|
-
}
|
|
866
857
|
if (config.xsl) {
|
|
867
858
|
nuxt.options.nitro.routeRules[config.xsl] = {
|
|
868
859
|
headers: {
|
|
@@ -875,10 +866,16 @@ declare module 'vue-router' {
|
|
|
875
866
|
nuxt.options.nitro.routeRules["/sitemap_index.xml"] = routeRules;
|
|
876
867
|
if (typeof config.sitemaps === "object") {
|
|
877
868
|
for (const k in config.sitemaps) {
|
|
869
|
+
if (k === "index")
|
|
870
|
+
continue;
|
|
878
871
|
nuxt.options.nitro.routeRules[joinURL(config.sitemapsPathPrefix || "", `/${k}.xml`)] = routeRules;
|
|
872
|
+
const sitemapConfig = config.sitemaps[k];
|
|
873
|
+
if (sitemapConfig.chunks) {
|
|
874
|
+
nuxt.options.nitro.routeRules[joinURL(config.sitemapsPathPrefix || "", `/${k}-*.xml`)] = routeRules;
|
|
875
|
+
}
|
|
879
876
|
}
|
|
880
877
|
} else {
|
|
881
|
-
nuxt.options.nitro.routeRules[
|
|
878
|
+
nuxt.options.nitro.routeRules[joinURL(config.sitemapsPathPrefix || "", `/[0-9]+.xml`)] = routeRules;
|
|
882
879
|
}
|
|
883
880
|
} else {
|
|
884
881
|
nuxt.options.nitro.routeRules[`/${config.sitemapName}`] = routeRules;
|
|
@@ -988,13 +985,25 @@ declare module 'vue-router' {
|
|
|
988
985
|
middleware: false
|
|
989
986
|
});
|
|
990
987
|
} else {
|
|
991
|
-
|
|
988
|
+
const sitemapNames = Object.keys(config.sitemaps || {});
|
|
989
|
+
for (const sitemapName of sitemapNames) {
|
|
990
|
+
if (sitemapName === "index")
|
|
991
|
+
continue;
|
|
992
|
+
const sitemapConfig = config.sitemaps[sitemapName];
|
|
992
993
|
addServerHandler({
|
|
993
994
|
route: withLeadingSlash(`${sitemapName}.xml`),
|
|
994
995
|
handler: resolve("./runtime/server/routes/sitemap/[sitemap].xml"),
|
|
995
996
|
lazy: true,
|
|
996
997
|
middleware: false
|
|
997
998
|
});
|
|
999
|
+
if (sitemapConfig.chunks) {
|
|
1000
|
+
addServerHandler({
|
|
1001
|
+
route: `/${sitemapName}-*.xml`,
|
|
1002
|
+
handler: resolve("./runtime/server/routes/sitemap/[sitemap].xml"),
|
|
1003
|
+
lazy: true,
|
|
1004
|
+
middleware: false
|
|
1005
|
+
});
|
|
1006
|
+
}
|
|
998
1007
|
}
|
|
999
1008
|
}
|
|
1000
1009
|
sitemaps.index = {
|
|
@@ -1008,7 +1017,7 @@ declare module 'vue-router' {
|
|
|
1008
1017
|
if (sitemapName === "index")
|
|
1009
1018
|
continue;
|
|
1010
1019
|
const definition = config.sitemaps[sitemapName];
|
|
1011
|
-
|
|
1020
|
+
const sitemapConfig = defu(
|
|
1012
1021
|
{
|
|
1013
1022
|
sitemapName,
|
|
1014
1023
|
_route: withBase(joinURL(config.sitemapsPathPrefix || "", `${sitemapName}.xml`), nuxt.options.app.baseURL || "/"),
|
|
@@ -1017,6 +1026,28 @@ declare module 'vue-router' {
|
|
|
1017
1026
|
{ ...definition, urls: void 0, sources: void 0 },
|
|
1018
1027
|
{ include: config.include, exclude: config.exclude }
|
|
1019
1028
|
);
|
|
1029
|
+
if (definition.chunks) {
|
|
1030
|
+
let chunkSize = config.defaultSitemapsChunkSize || 1e3;
|
|
1031
|
+
if (typeof definition.chunks === "number") {
|
|
1032
|
+
if (definition.chunks <= 0) {
|
|
1033
|
+
logger.warn(`Invalid chunks value (${definition.chunks}) for sitemap "${sitemapName}". Using default.`);
|
|
1034
|
+
} else {
|
|
1035
|
+
chunkSize = definition.chunks;
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
if (definition.chunkSize !== void 0) {
|
|
1039
|
+
if (typeof definition.chunkSize !== "number" || definition.chunkSize <= 0) {
|
|
1040
|
+
logger.warn(`Invalid chunkSize value (${definition.chunkSize}) for sitemap "${sitemapName}". Using default.`);
|
|
1041
|
+
} else {
|
|
1042
|
+
chunkSize = definition.chunkSize;
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
sitemapConfig._isChunking = true;
|
|
1046
|
+
sitemapConfig._chunkSize = chunkSize;
|
|
1047
|
+
sitemapConfig.chunks = definition.chunks;
|
|
1048
|
+
sitemapConfig.chunkSize = definition.chunkSize;
|
|
1049
|
+
}
|
|
1050
|
+
sitemaps[sitemapName] = sitemapConfig;
|
|
1020
1051
|
}
|
|
1021
1052
|
} else {
|
|
1022
1053
|
sitemaps.chunks = {
|
|
@@ -1118,6 +1149,14 @@ declare module 'vue-router' {
|
|
|
1118
1149
|
route: "/__sitemap__/debug.json",
|
|
1119
1150
|
handler: resolve("./runtime/server/routes/__sitemap__/debug")
|
|
1120
1151
|
});
|
|
1152
|
+
if (usingMultiSitemaps) {
|
|
1153
|
+
addServerHandler({
|
|
1154
|
+
route: "/__sitemap__/**:sitemap",
|
|
1155
|
+
handler: resolve("./runtime/server/routes/sitemap/[sitemap].xml"),
|
|
1156
|
+
lazy: true,
|
|
1157
|
+
middleware: true
|
|
1158
|
+
});
|
|
1159
|
+
}
|
|
1121
1160
|
setupDevToolsUI(config, resolve);
|
|
1122
1161
|
}
|
|
1123
1162
|
const imports = [
|
|
@@ -4,20 +4,36 @@ import { useSitemapRuntimeConfig } from "../utils.js";
|
|
|
4
4
|
export default defineNitroPlugin((nitroApp) => {
|
|
5
5
|
const { sitemaps } = useSitemapRuntimeConfig();
|
|
6
6
|
const queue = [];
|
|
7
|
+
const timeoutIds = [];
|
|
7
8
|
const sitemapsWithRoutes = Object.entries(sitemaps).filter(([, sitemap]) => sitemap._route);
|
|
8
9
|
for (const [, sitemap] of sitemapsWithRoutes)
|
|
9
10
|
queue.push(() => nitroApp.localFetch(withLeadingSlash(sitemap._route), {}));
|
|
10
|
-
setTimeout(
|
|
11
|
+
const initialTimeout = setTimeout(
|
|
11
12
|
() => {
|
|
12
13
|
const next = async () => {
|
|
13
|
-
if (queue.length === 0)
|
|
14
|
+
if (queue.length === 0) {
|
|
15
|
+
timeoutIds.length = 0;
|
|
14
16
|
return;
|
|
15
|
-
|
|
16
|
-
|
|
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
|
+
}
|
|
17
27
|
};
|
|
18
28
|
next();
|
|
19
29
|
},
|
|
20
30
|
2500
|
|
21
31
|
/* https://github.com/unjs/nitro/pull/1906 */
|
|
22
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
|
+
});
|
|
23
39
|
});
|
|
@@ -17,13 +17,13 @@ export default defineEventHandler(async (e) => {
|
|
|
17
17
|
for (const s of Object.keys(_sitemaps)) {
|
|
18
18
|
sitemaps[s] = {
|
|
19
19
|
..._sitemaps[s],
|
|
20
|
-
sources: await resolveSitemapSources(await childSitemapSources(_sitemaps[s]))
|
|
20
|
+
sources: await resolveSitemapSources(await childSitemapSources(_sitemaps[s]), e)
|
|
21
21
|
};
|
|
22
22
|
}
|
|
23
23
|
return {
|
|
24
24
|
nitroOrigin,
|
|
25
25
|
sitemaps,
|
|
26
26
|
runtimeConfig,
|
|
27
|
-
globalSources: await resolveSitemapSources(globalSources)
|
|
27
|
+
globalSources: await resolveSitemapSources(globalSources, e)
|
|
28
28
|
};
|
|
29
29
|
});
|
|
@@ -2,19 +2,49 @@ import { createError, defineEventHandler, getRouterParam } from "h3";
|
|
|
2
2
|
import { withoutLeadingSlash, withoutTrailingSlash } from "ufo";
|
|
3
3
|
import { useSitemapRuntimeConfig } from "../../utils.js";
|
|
4
4
|
import { createSitemap } from "../../sitemap/nitro.js";
|
|
5
|
+
import { parseChunkInfo, getSitemapConfig } from "../../sitemap/utils/chunk.js";
|
|
5
6
|
export default defineEventHandler(async (e) => {
|
|
6
7
|
const runtimeConfig = useSitemapRuntimeConfig(e);
|
|
7
8
|
const { sitemaps } = runtimeConfig;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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) {
|
|
11
28
|
return createError({
|
|
12
29
|
statusCode: 404,
|
|
13
30
|
message: `Sitemap "${sitemapName}" not found.`
|
|
14
31
|
});
|
|
15
32
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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);
|
|
20
50
|
});
|
|
@@ -22,9 +22,17 @@ export default defineEventHandler(async (e) => {
|
|
|
22
22
|
const ctx = { sitemap: output, sitemapName: "sitemap", event: e };
|
|
23
23
|
await nitro.hooks.callHook("sitemap:output", ctx);
|
|
24
24
|
setHeader(e, "Content-Type", "text/xml; charset=UTF-8");
|
|
25
|
-
if (runtimeConfig.cacheMaxAgeSeconds)
|
|
26
|
-
setHeader(e, "Cache-Control", `public, max-age=${runtimeConfig.cacheMaxAgeSeconds},
|
|
27
|
-
|
|
25
|
+
if (runtimeConfig.cacheMaxAgeSeconds) {
|
|
26
|
+
setHeader(e, "Cache-Control", `public, max-age=${runtimeConfig.cacheMaxAgeSeconds}, s-maxage=${runtimeConfig.cacheMaxAgeSeconds}, stale-while-revalidate=3600`);
|
|
27
|
+
const now = /* @__PURE__ */ new Date();
|
|
28
|
+
setHeader(e, "X-Sitemap-Generated", now.toISOString());
|
|
29
|
+
setHeader(e, "X-Sitemap-Cache-Duration", `${runtimeConfig.cacheMaxAgeSeconds}s`);
|
|
30
|
+
const expiryTime = new Date(now.getTime() + runtimeConfig.cacheMaxAgeSeconds * 1e3);
|
|
31
|
+
setHeader(e, "X-Sitemap-Cache-Expires", expiryTime.toISOString());
|
|
32
|
+
const remainingSeconds = Math.floor((expiryTime.getTime() - now.getTime()) / 1e3);
|
|
33
|
+
setHeader(e, "X-Sitemap-Cache-Remaining", `${remainingSeconds}s`);
|
|
34
|
+
} else {
|
|
28
35
|
setHeader(e, "Cache-Control", `no-cache, no-store`);
|
|
36
|
+
}
|
|
29
37
|
return ctx.sitemap;
|
|
30
38
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { NitroApp } from 'nitropack/types';
|
|
2
2
|
import type { ModuleRuntimeConfig, NitroUrlResolvers, SitemapIndexEntry } from '../../../types.js';
|
|
3
|
-
export declare function buildSitemapIndex(resolvers: NitroUrlResolvers, runtimeConfig: ModuleRuntimeConfig, nitro?: NitroApp): Promise<SitemapIndexEntry[]>;
|
|
4
3
|
export declare function urlsToIndexXml(sitemaps: SitemapIndexEntry[], resolvers: NitroUrlResolvers, { version, xsl, credits, minify }: Pick<ModuleRuntimeConfig, 'version' | 'xsl' | 'credits' | 'minify'>): string;
|
|
4
|
+
export declare function buildSitemapIndex(resolvers: NitroUrlResolvers, runtimeConfig: ModuleRuntimeConfig, nitro?: NitroApp): Promise<SitemapIndexEntry[]>;
|
|
@@ -1,11 +1,33 @@
|
|
|
1
1
|
import { defu } from "defu";
|
|
2
2
|
import { joinURL } from "ufo";
|
|
3
|
+
import { defineCachedFunction } from "nitropack/runtime";
|
|
4
|
+
import { getHeader } from "h3";
|
|
3
5
|
import { normaliseDate } from "../urlset/normalise.js";
|
|
4
|
-
import { globalSitemapSources, resolveSitemapSources } from "../urlset/sources.js";
|
|
5
|
-
import {
|
|
6
|
-
import { escapeValueForXml
|
|
6
|
+
import { globalSitemapSources, childSitemapSources, resolveSitemapSources } from "../urlset/sources.js";
|
|
7
|
+
import { sortInPlace } from "../urlset/sort.js";
|
|
8
|
+
import { escapeValueForXml } from "./xml.js";
|
|
7
9
|
import { resolveSitemapEntries } from "./sitemap.js";
|
|
8
|
-
|
|
10
|
+
const buildSitemapIndexCached = defineCachedFunction(
|
|
11
|
+
async (event, resolvers, runtimeConfig, nitro) => {
|
|
12
|
+
return buildSitemapIndexInternal(resolvers, runtimeConfig, nitro);
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
name: "sitemap:index",
|
|
16
|
+
group: "sitemap",
|
|
17
|
+
maxAge: 60 * 10,
|
|
18
|
+
// 10 minutes default
|
|
19
|
+
base: "sitemap",
|
|
20
|
+
// Use the sitemap storage
|
|
21
|
+
getKey: (event) => {
|
|
22
|
+
const host = getHeader(event, "host") || getHeader(event, "x-forwarded-host") || "";
|
|
23
|
+
const proto = getHeader(event, "x-forwarded-proto") || "https";
|
|
24
|
+
return `sitemap-index-${proto}-${host}`;
|
|
25
|
+
},
|
|
26
|
+
swr: true
|
|
27
|
+
// Enable stale-while-revalidate
|
|
28
|
+
}
|
|
29
|
+
);
|
|
30
|
+
async function buildSitemapIndexInternal(resolvers, runtimeConfig, nitro) {
|
|
9
31
|
const {
|
|
10
32
|
sitemaps,
|
|
11
33
|
// enhancing
|
|
@@ -20,13 +42,32 @@ export async function buildSitemapIndex(resolvers, runtimeConfig, nitro) {
|
|
|
20
42
|
if (!sitemaps)
|
|
21
43
|
throw new Error("Attempting to build a sitemap index without required `sitemaps` configuration.");
|
|
22
44
|
function maybeSort(urls) {
|
|
23
|
-
return sortEntries ?
|
|
45
|
+
return sortEntries ? sortInPlace(urls) : urls;
|
|
24
46
|
}
|
|
25
|
-
const isChunking = typeof sitemaps.chunks !== "undefined";
|
|
26
47
|
const chunks = {};
|
|
27
|
-
|
|
48
|
+
for (const sitemapName in sitemaps) {
|
|
49
|
+
if (sitemapName === "index" || sitemapName === "chunks") continue;
|
|
50
|
+
const sitemapConfig = sitemaps[sitemapName];
|
|
51
|
+
if (sitemapConfig.chunks || sitemapConfig._isChunking) {
|
|
52
|
+
sitemapConfig._isChunking = true;
|
|
53
|
+
sitemapConfig._chunkSize = typeof sitemapConfig.chunks === "number" ? sitemapConfig.chunks : sitemapConfig.chunkSize || defaultSitemapsChunkSize || 1e3;
|
|
54
|
+
} else {
|
|
55
|
+
chunks[sitemapName] = chunks[sitemapName] || { urls: [] };
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (typeof sitemaps.chunks !== "undefined") {
|
|
28
59
|
const sitemap = sitemaps.chunks;
|
|
29
|
-
|
|
60
|
+
let sourcesInput = await globalSitemapSources();
|
|
61
|
+
if (nitro && resolvers.event) {
|
|
62
|
+
const ctx = {
|
|
63
|
+
event: resolvers.event,
|
|
64
|
+
sitemapName: sitemap.sitemapName,
|
|
65
|
+
sources: sourcesInput
|
|
66
|
+
};
|
|
67
|
+
await nitro.hooks.callHook("sitemap:sources", ctx);
|
|
68
|
+
sourcesInput = ctx.sources;
|
|
69
|
+
}
|
|
70
|
+
const sources = await resolveSitemapSources(sourcesInput, resolvers.event);
|
|
30
71
|
const resolvedCtx = {
|
|
31
72
|
urls: sources.flatMap((s) => s.urls),
|
|
32
73
|
sitemapName: sitemap.sitemapName,
|
|
@@ -41,12 +82,6 @@ export async function buildSitemapIndex(resolvers, runtimeConfig, nitro) {
|
|
|
41
82
|
chunks[chunkIndex] = chunks[chunkIndex] || { urls: [] };
|
|
42
83
|
chunks[chunkIndex].urls.push(url);
|
|
43
84
|
});
|
|
44
|
-
} else {
|
|
45
|
-
for (const sitemap in sitemaps) {
|
|
46
|
-
if (sitemap !== "index") {
|
|
47
|
-
chunks[sitemap] = chunks[sitemap] || { urls: [] };
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
85
|
}
|
|
51
86
|
const entries = [];
|
|
52
87
|
for (const name in chunks) {
|
|
@@ -62,6 +97,48 @@ export async function buildSitemapIndex(resolvers, runtimeConfig, nitro) {
|
|
|
62
97
|
entry.lastmod = normaliseDate(lastmod);
|
|
63
98
|
entries.push(entry);
|
|
64
99
|
}
|
|
100
|
+
for (const sitemapName in sitemaps) {
|
|
101
|
+
if (sitemapName !== "index" && sitemaps[sitemapName]._isChunking) {
|
|
102
|
+
const sitemapConfig = sitemaps[sitemapName];
|
|
103
|
+
const chunkSize = sitemapConfig._chunkSize || defaultSitemapsChunkSize || 1e3;
|
|
104
|
+
let sourcesInput = sitemapConfig.includeAppSources ? await globalSitemapSources() : [];
|
|
105
|
+
sourcesInput.push(...await childSitemapSources(sitemapConfig));
|
|
106
|
+
if (nitro && resolvers.event) {
|
|
107
|
+
const ctx = {
|
|
108
|
+
event: resolvers.event,
|
|
109
|
+
sitemapName: sitemapConfig.sitemapName,
|
|
110
|
+
sources: sourcesInput
|
|
111
|
+
};
|
|
112
|
+
await nitro.hooks.callHook("sitemap:sources", ctx);
|
|
113
|
+
sourcesInput = ctx.sources;
|
|
114
|
+
}
|
|
115
|
+
const sources = await resolveSitemapSources(sourcesInput, resolvers.event);
|
|
116
|
+
const resolvedCtx = {
|
|
117
|
+
urls: sources.flatMap((s) => s.urls),
|
|
118
|
+
sitemapName: sitemapConfig.sitemapName,
|
|
119
|
+
event: resolvers.event
|
|
120
|
+
};
|
|
121
|
+
await nitro?.hooks.callHook("sitemap:input", resolvedCtx);
|
|
122
|
+
const normalisedUrls = resolveSitemapEntries(sitemapConfig, resolvedCtx.urls, { autoI18n, isI18nMapped }, resolvers);
|
|
123
|
+
const totalUrls = normalisedUrls.length;
|
|
124
|
+
const chunkCount = Math.ceil(totalUrls / chunkSize);
|
|
125
|
+
sitemapConfig._chunkCount = chunkCount;
|
|
126
|
+
for (let i = 0; i < chunkCount; i++) {
|
|
127
|
+
const chunkName = `${sitemapName}-${i}`;
|
|
128
|
+
const entry = {
|
|
129
|
+
_sitemapName: chunkName,
|
|
130
|
+
sitemap: resolvers.canonicalUrlResolver(joinURL(sitemapsPathPrefix || "", `/${chunkName}.xml`))
|
|
131
|
+
};
|
|
132
|
+
const chunkUrls = normalisedUrls.slice(i * chunkSize, (i + 1) * chunkSize);
|
|
133
|
+
let lastmod = chunkUrls.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];
|
|
134
|
+
if (!lastmod && autoLastmod)
|
|
135
|
+
lastmod = /* @__PURE__ */ new Date();
|
|
136
|
+
if (lastmod)
|
|
137
|
+
entry.lastmod = normaliseDate(lastmod);
|
|
138
|
+
entries.push(entry);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
65
142
|
if (sitemaps.index) {
|
|
66
143
|
entries.push(...sitemaps.index.sitemaps.map((entry) => {
|
|
67
144
|
return typeof entry === "string" ? { sitemap: entry } : entry;
|
|
@@ -77,9 +154,26 @@ export function urlsToIndexXml(sitemaps, resolvers, { version, xsl, credits, min
|
|
|
77
154
|
e.lastmod ? ` <lastmod>${escapeValueForXml(e.lastmod)}</lastmod>` : false,
|
|
78
155
|
" </sitemap>"
|
|
79
156
|
].filter(Boolean).join("\n")).join("\n");
|
|
80
|
-
|
|
157
|
+
const xmlParts = [
|
|
158
|
+
'<?xml version="1.0" encoding="UTF-8"?>'
|
|
159
|
+
];
|
|
160
|
+
if (xsl) {
|
|
161
|
+
const relativeBaseUrl = resolvers.relativeBaseUrlResolver?.(xsl) ?? xsl;
|
|
162
|
+
xmlParts.push(`<?xml-stylesheet type="text/xsl" href="${escapeValueForXml(relativeBaseUrl)}"?>`);
|
|
163
|
+
}
|
|
164
|
+
xmlParts.push(
|
|
81
165
|
'<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
|
|
82
166
|
sitemapXml,
|
|
83
167
|
"</sitemapindex>"
|
|
84
|
-
|
|
168
|
+
);
|
|
169
|
+
if (credits) {
|
|
170
|
+
xmlParts.push(`<!-- XML Sitemap Index generated by @nuxtjs/sitemap v${version} at ${(/* @__PURE__ */ new Date()).toISOString()} -->`);
|
|
171
|
+
}
|
|
172
|
+
return minify ? xmlParts.join("").replace(/(?<!<[^>]*)\s(?![^<]*>)/g, "") : xmlParts.join("\n");
|
|
173
|
+
}
|
|
174
|
+
export async function buildSitemapIndex(resolvers, runtimeConfig, nitro) {
|
|
175
|
+
if (!import.meta.dev && !!runtimeConfig.cacheMaxAgeSeconds && runtimeConfig.cacheMaxAgeSeconds > 0 && resolvers.event) {
|
|
176
|
+
return buildSitemapIndexCached(resolvers.event, resolvers, runtimeConfig, nitro);
|
|
177
|
+
}
|
|
178
|
+
return buildSitemapIndexInternal(resolvers, runtimeConfig, nitro);
|
|
85
179
|
}
|
|
@@ -7,4 +7,4 @@ export interface NormalizedI18n extends ResolvedSitemapUrl {
|
|
|
7
7
|
}
|
|
8
8
|
export declare function resolveSitemapEntries(sitemap: SitemapDefinition, urls: SitemapUrlInput[], runtimeConfig: Pick<ModuleRuntimeConfig, 'autoI18n' | 'isI18nMapped'>, resolvers?: NitroUrlResolvers): ResolvedSitemapUrl[];
|
|
9
9
|
export declare function buildSitemapUrls(sitemap: SitemapDefinition, resolvers: NitroUrlResolvers, runtimeConfig: ModuleRuntimeConfig, nitro?: NitroApp): Promise<ResolvedSitemapUrl[]>;
|
|
10
|
-
export
|
|
10
|
+
export { urlsToXml } from './xml.js';
|
|
@@ -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;
|