@nuxtjs/sitemap 7.4.11 → 7.5.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 +1 -1
- package/dist/client/404.html +1 -1
- package/dist/client/_nuxt/BZzBMR0a.js +155 -0
- package/dist/client/_nuxt/{CjT5ejtq.js → BcLzIRTJ.js} +1 -1
- package/dist/client/_nuxt/{DBmpb9dG.js → CQIolwG-.js} +1 -1
- package/dist/client/_nuxt/builds/latest.json +1 -1
- package/dist/client/_nuxt/builds/meta/c9c08595-dc8d-4073-931c-6ba959692bc1.json +1 -0
- package/dist/client/_nuxt/error-404.DKXSOdpM.css +1 -0
- package/dist/client/_nuxt/error-500.rUXo3Kq4.css +1 -0
- package/dist/client/index.html +1 -1
- package/dist/client/sitemap.xml +1 -1
- package/dist/module.d.mts +14 -2
- package/dist/module.d.ts +14 -2
- package/dist/module.json +1 -1
- package/dist/module.mjs +83 -31
- package/dist/runtime/server/routes/__zero-runtime/sitemap/[sitemap].xml.d.ts +2 -0
- package/dist/runtime/server/routes/__zero-runtime/sitemap/[sitemap].xml.js +8 -0
- package/dist/runtime/server/routes/__zero-runtime/sitemap.xml.d.ts +2 -0
- package/dist/runtime/server/routes/__zero-runtime/sitemap.xml.js +8 -0
- package/dist/runtime/server/routes/__zero-runtime/sitemap_index.xml.d.ts +2 -0
- package/dist/runtime/server/routes/__zero-runtime/sitemap_index.xml.js +8 -0
- package/dist/runtime/server/routes/sitemap/[sitemap].xml.d.ts +1 -1
- package/dist/runtime/server/routes/sitemap/[sitemap].xml.js +3 -50
- package/dist/runtime/server/routes/sitemap.xml.js +3 -13
- package/dist/runtime/server/routes/sitemap_index.xml.js +3 -42
- package/dist/runtime/server/sitemap/builder/sitemap.js +16 -13
- package/dist/runtime/server/sitemap/builder/xml.js +1 -1
- package/dist/runtime/server/sitemap/event-handlers.d.ts +4 -0
- package/dist/runtime/server/sitemap/event-handlers.js +77 -0
- package/dist/runtime/server/sitemap/urlset/normalise.js +4 -2
- package/dist/runtime/server/sitemap/urlset/sources.d.ts +3 -2
- package/dist/runtime/server/sitemap/urlset/sources.js +16 -6
- package/dist/runtime/types.d.ts +25 -1
- package/dist/runtime/utils-pure.d.ts +6 -0
- package/dist/runtime/utils-pure.js +20 -0
- package/dist/types.d.mts +7 -1
- package/package.json +8 -7
- package/dist/client/_nuxt/FE81ed4p.js +0 -155
- package/dist/client/_nuxt/builds/meta/ef370d03-581a-4487-a7bd-237af16aab04.json +0 -1
- package/dist/client/_nuxt/error-404.DC9fsYfS.css +0 -1
- package/dist/client/_nuxt/error-500.DPVweS-0.css +0 -1
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { appendHeader, createError, getRouterParam, sendRedirect, setHeader } from "h3";
|
|
2
|
+
import { joinURL, withBase, withoutLeadingSlash, withoutTrailingSlash } from "ufo";
|
|
3
|
+
import { useRuntimeConfig, useNitroApp } from "nitropack/runtime";
|
|
4
|
+
import { useSitemapRuntimeConfig } from "../utils.js";
|
|
5
|
+
import { createSitemap, useNitroUrlResolvers } from "./nitro.js";
|
|
6
|
+
import { buildSitemapIndex, urlsToIndexXml } from "./builder/sitemap-index.js";
|
|
7
|
+
import { parseChunkInfo, getSitemapConfig } from "./utils/chunk.js";
|
|
8
|
+
export async function sitemapXmlEventHandler(e) {
|
|
9
|
+
const runtimeConfig = useSitemapRuntimeConfig();
|
|
10
|
+
const { sitemaps } = runtimeConfig;
|
|
11
|
+
if ("index" in sitemaps)
|
|
12
|
+
return sendRedirect(e, withBase("/sitemap_index.xml", useRuntimeConfig().app.baseURL), import.meta.dev ? 302 : 301);
|
|
13
|
+
return createSitemap(e, Object.values(sitemaps)[0], runtimeConfig);
|
|
14
|
+
}
|
|
15
|
+
export async function sitemapIndexXmlEventHandler(e) {
|
|
16
|
+
const runtimeConfig = useSitemapRuntimeConfig();
|
|
17
|
+
const nitro = useNitroApp();
|
|
18
|
+
const resolvers = useNitroUrlResolvers(e);
|
|
19
|
+
const { entries: sitemaps, failedSources } = await buildSitemapIndex(resolvers, runtimeConfig, nitro);
|
|
20
|
+
if (import.meta.prerender) {
|
|
21
|
+
appendHeader(
|
|
22
|
+
e,
|
|
23
|
+
"x-nitro-prerender",
|
|
24
|
+
sitemaps.filter((entry) => !!entry._sitemapName).map((entry) => encodeURIComponent(joinURL(runtimeConfig.sitemapsPathPrefix || "", `/${entry._sitemapName}.xml`))).join(", ")
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
const indexResolvedCtx = { sitemaps, event: e };
|
|
28
|
+
await nitro.hooks.callHook("sitemap:index-resolved", indexResolvedCtx);
|
|
29
|
+
const errorInfo = failedSources.length > 0 ? { messages: failedSources.map((f) => f.error), urls: failedSources.map((f) => f.url) } : void 0;
|
|
30
|
+
const output = urlsToIndexXml(indexResolvedCtx.sitemaps, resolvers, runtimeConfig, errorInfo);
|
|
31
|
+
const ctx = { sitemap: output, sitemapName: "sitemap", event: e };
|
|
32
|
+
await nitro.hooks.callHook("sitemap:output", ctx);
|
|
33
|
+
setHeader(e, "Content-Type", "text/xml; charset=UTF-8");
|
|
34
|
+
if (runtimeConfig.cacheMaxAgeSeconds) {
|
|
35
|
+
setHeader(e, "Cache-Control", `public, max-age=${runtimeConfig.cacheMaxAgeSeconds}, s-maxage=${runtimeConfig.cacheMaxAgeSeconds}, stale-while-revalidate=3600`);
|
|
36
|
+
const now = /* @__PURE__ */ new Date();
|
|
37
|
+
setHeader(e, "X-Sitemap-Generated", now.toISOString());
|
|
38
|
+
setHeader(e, "X-Sitemap-Cache-Duration", `${runtimeConfig.cacheMaxAgeSeconds}s`);
|
|
39
|
+
const expiryTime = new Date(now.getTime() + runtimeConfig.cacheMaxAgeSeconds * 1e3);
|
|
40
|
+
setHeader(e, "X-Sitemap-Cache-Expires", expiryTime.toISOString());
|
|
41
|
+
const remainingSeconds = Math.floor((expiryTime.getTime() - now.getTime()) / 1e3);
|
|
42
|
+
setHeader(e, "X-Sitemap-Cache-Remaining", `${remainingSeconds}s`);
|
|
43
|
+
} else {
|
|
44
|
+
setHeader(e, "Cache-Control", `no-cache, no-store`);
|
|
45
|
+
}
|
|
46
|
+
return ctx.sitemap;
|
|
47
|
+
}
|
|
48
|
+
export async function sitemapChildXmlEventHandler(e) {
|
|
49
|
+
if (!e.path.endsWith(".xml"))
|
|
50
|
+
return;
|
|
51
|
+
const runtimeConfig = useSitemapRuntimeConfig(e);
|
|
52
|
+
const { sitemaps } = runtimeConfig;
|
|
53
|
+
let sitemapName = getRouterParam(e, "sitemap");
|
|
54
|
+
if (!sitemapName) {
|
|
55
|
+
const path = e.path;
|
|
56
|
+
const match = path.match(/(?:\/__sitemap__\/)?([^/]+)\.xml$/);
|
|
57
|
+
if (match)
|
|
58
|
+
sitemapName = match[1];
|
|
59
|
+
}
|
|
60
|
+
if (!sitemapName)
|
|
61
|
+
throw createError({ statusCode: 400, message: "Invalid sitemap request" });
|
|
62
|
+
sitemapName = withoutLeadingSlash(withoutTrailingSlash(sitemapName.replace(".xml", "").replace("__sitemap__/", "").replace(runtimeConfig.sitemapsPathPrefix || "", "")));
|
|
63
|
+
const chunkInfo = parseChunkInfo(sitemapName, sitemaps, runtimeConfig.defaultSitemapsChunkSize);
|
|
64
|
+
const isAutoChunked = typeof sitemaps.chunks !== "undefined" && !Number.isNaN(Number(sitemapName));
|
|
65
|
+
const sitemapExists = sitemapName in sitemaps || chunkInfo.baseSitemapName in sitemaps || isAutoChunked;
|
|
66
|
+
if (!sitemapExists)
|
|
67
|
+
throw createError({ statusCode: 404, message: `Sitemap "${sitemapName}" not found.` });
|
|
68
|
+
if (chunkInfo.isChunked && chunkInfo.chunkIndex !== void 0) {
|
|
69
|
+
const baseSitemap = sitemaps[chunkInfo.baseSitemapName];
|
|
70
|
+
if (baseSitemap && !baseSitemap.chunks && !baseSitemap._isChunking)
|
|
71
|
+
throw createError({ statusCode: 404, message: `Sitemap "${chunkInfo.baseSitemapName}" does not support chunking.` });
|
|
72
|
+
if (baseSitemap?._chunkCount !== void 0 && chunkInfo.chunkIndex >= baseSitemap._chunkCount)
|
|
73
|
+
throw createError({ statusCode: 404, message: `Chunk ${chunkInfo.chunkIndex} does not exist for sitemap "${chunkInfo.baseSitemapName}".` });
|
|
74
|
+
}
|
|
75
|
+
const sitemapConfig = getSitemapConfig(sitemapName, sitemaps, runtimeConfig.defaultSitemapsChunkSize || void 0);
|
|
76
|
+
return createSitemap(e, sitemapConfig, runtimeConfig);
|
|
77
|
+
}
|
|
@@ -32,6 +32,7 @@ export function preNormalizeEntry(_e, resolvers) {
|
|
|
32
32
|
if (typeof input.loc !== "string") {
|
|
33
33
|
input.loc = "";
|
|
34
34
|
}
|
|
35
|
+
const skipEncoding = input._encoded === true;
|
|
35
36
|
const e = input;
|
|
36
37
|
e.loc = removeTrailingSlash(e.loc);
|
|
37
38
|
e._abs = hasProtocol(e.loc, { acceptRelative: false, strict: false });
|
|
@@ -43,13 +44,14 @@ export function preNormalizeEntry(_e, resolvers) {
|
|
|
43
44
|
if (e._path) {
|
|
44
45
|
const search = e._path.search;
|
|
45
46
|
const qs = search && search.length > 1 ? stringifyQuery(parseQuery(search)) : "";
|
|
46
|
-
e.
|
|
47
|
+
const pathname = skipEncoding ? e._path.pathname : encodePath(e._path.pathname);
|
|
48
|
+
e._relativeLoc = `${pathname}${qs.length ? `?${qs}` : ""}`;
|
|
47
49
|
if (e._path.host) {
|
|
48
50
|
e.loc = stringifyParsedURL(e._path);
|
|
49
51
|
} else {
|
|
50
52
|
e.loc = e._relativeLoc;
|
|
51
53
|
}
|
|
52
|
-
} else if (!isEncoded(e.loc)) {
|
|
54
|
+
} else if (!skipEncoding && !isEncoded(e.loc)) {
|
|
53
55
|
e.loc = encodeURI(e.loc);
|
|
54
56
|
}
|
|
55
57
|
if (e.loc === "")
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { H3Event } from 'h3';
|
|
2
|
-
import type { ModuleRuntimeConfig, SitemapSourceBase, SitemapSourceResolved } from '../../../types.js';
|
|
2
|
+
import type { ModuleRuntimeConfig, SitemapSourceBase, SitemapSourceInput, SitemapSourceResolved } from '../../../types.js';
|
|
3
|
+
export declare function normalizeSourceInput(source: SitemapSourceInput): SitemapSourceBase | SitemapSourceResolved;
|
|
3
4
|
export declare function fetchDataSource(input: SitemapSourceBase | SitemapSourceResolved, event?: H3Event): Promise<SitemapSourceResolved>;
|
|
4
5
|
export declare function globalSitemapSources(): Promise<any[]>;
|
|
5
6
|
export declare function childSitemapSources(definition: ModuleRuntimeConfig['sitemaps'][string]): Promise<any[]>;
|
|
6
|
-
export declare function resolveSitemapSources(sources:
|
|
7
|
+
export declare function resolveSitemapSources(sources: SitemapSourceInput[], event?: H3Event): Promise<SitemapSourceResolved[]>;
|
|
@@ -3,6 +3,15 @@ import { defu } from "defu";
|
|
|
3
3
|
import { parseURL } from "ufo";
|
|
4
4
|
import { logger } from "../../../utils-pure.js";
|
|
5
5
|
import { parseSitemapXml } from "@nuxtjs/sitemap/utils";
|
|
6
|
+
export function normalizeSourceInput(source) {
|
|
7
|
+
if (typeof source === "string") {
|
|
8
|
+
return { context: { name: "hook" }, fetch: source };
|
|
9
|
+
}
|
|
10
|
+
if (Array.isArray(source)) {
|
|
11
|
+
return { context: { name: "hook" }, fetch: source };
|
|
12
|
+
}
|
|
13
|
+
return source;
|
|
14
|
+
}
|
|
6
15
|
async function tryFetchWithFallback(url, options, event) {
|
|
7
16
|
const isExternalUrl = !url.startsWith("/");
|
|
8
17
|
if (isExternalUrl) {
|
|
@@ -143,17 +152,18 @@ export async function childSitemapSources(definition) {
|
|
|
143
152
|
export async function resolveSitemapSources(sources, event) {
|
|
144
153
|
return (await Promise.all(
|
|
145
154
|
sources.map((source) => {
|
|
146
|
-
|
|
155
|
+
const normalized = normalizeSourceInput(source);
|
|
156
|
+
if ("urls" in normalized) {
|
|
147
157
|
return {
|
|
148
158
|
timeTakenMs: 0,
|
|
149
|
-
...
|
|
150
|
-
urls:
|
|
159
|
+
...normalized,
|
|
160
|
+
urls: normalized.urls
|
|
151
161
|
};
|
|
152
162
|
}
|
|
153
|
-
if (
|
|
154
|
-
return fetchDataSource(
|
|
163
|
+
if (normalized.fetch)
|
|
164
|
+
return fetchDataSource(normalized, event);
|
|
155
165
|
return {
|
|
156
|
-
...
|
|
166
|
+
...normalized,
|
|
157
167
|
error: "Invalid source"
|
|
158
168
|
};
|
|
159
169
|
})
|
package/dist/runtime/types.d.ts
CHANGED
|
@@ -153,6 +153,15 @@ export interface ModuleOptions extends SitemapDefinition {
|
|
|
153
153
|
* @experimental Will be enabled by default in v5 (if stable)
|
|
154
154
|
*/
|
|
155
155
|
experimentalCompression?: boolean;
|
|
156
|
+
/**
|
|
157
|
+
* When enabled, sitemap generation only runs during prerendering.
|
|
158
|
+
* The sitemap building code is tree-shaken from the runtime bundle.
|
|
159
|
+
*
|
|
160
|
+
* Requires sitemaps to be prerendered (e.g., `nuxt generate` or `nitro.prerender.routes` includes sitemap).
|
|
161
|
+
*
|
|
162
|
+
* @default false
|
|
163
|
+
*/
|
|
164
|
+
zeroRuntime?: boolean;
|
|
156
165
|
}
|
|
157
166
|
export interface IndexSitemapRemotes {
|
|
158
167
|
index?: (string | SitemapIndexEntry)[];
|
|
@@ -357,7 +366,7 @@ export interface SitemapOutputHookCtx extends NitroBaseHook {
|
|
|
357
366
|
}
|
|
358
367
|
export interface SitemapSourcesHookCtx extends NitroBaseHook {
|
|
359
368
|
sitemapName: string;
|
|
360
|
-
sources:
|
|
369
|
+
sources: SitemapSourceInput[];
|
|
361
370
|
}
|
|
362
371
|
export type Changefreq = 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
|
|
363
372
|
export interface SitemapUrl {
|
|
@@ -375,6 +384,21 @@ export interface SitemapUrl {
|
|
|
375
384
|
videos?: Array<VideoEntry>;
|
|
376
385
|
_i18nTransform?: boolean;
|
|
377
386
|
_sitemap?: string | false;
|
|
387
|
+
/**
|
|
388
|
+
* Mark the URL as already encoded.
|
|
389
|
+
*
|
|
390
|
+
* When true, the loc will not be automatically encoded, preventing double-encoding
|
|
391
|
+
* when you've already applied encodeURIComponent() to path segments.
|
|
392
|
+
*
|
|
393
|
+
* @example
|
|
394
|
+
* ```ts
|
|
395
|
+
* {
|
|
396
|
+
* loc: `/${encodeURIComponent('$pecial-char')}`,
|
|
397
|
+
* _encoded: true
|
|
398
|
+
* }
|
|
399
|
+
* ```
|
|
400
|
+
*/
|
|
401
|
+
_encoded?: boolean;
|
|
378
402
|
}
|
|
379
403
|
export type SitemapStrict = Required<SitemapUrl>;
|
|
380
404
|
export interface AlternativeEntry {
|
|
@@ -11,4 +11,10 @@ export interface CreateFilterOptions {
|
|
|
11
11
|
exclude?: (FilterInput | string | RegExp)[];
|
|
12
12
|
}
|
|
13
13
|
export declare function createPathFilter(options?: CreateFilterOptions): (loc: string) => boolean;
|
|
14
|
+
export interface PageMatch {
|
|
15
|
+
mappings: Record<string, string | false>;
|
|
16
|
+
paramSegments: string[];
|
|
17
|
+
}
|
|
18
|
+
export declare function findPageMapping(pathWithoutPrefix: string, pages: Record<string, Record<string, string | false>>): PageMatch | null;
|
|
19
|
+
export declare function applyDynamicParams(customPath: string, paramSegments: string[]): string;
|
|
14
20
|
export declare function createFilter(options?: CreateFilterOptions): (path: string) => boolean;
|
|
@@ -58,6 +58,26 @@ export function createPathFilter(options = {}) {
|
|
|
58
58
|
return urlFilter(path);
|
|
59
59
|
};
|
|
60
60
|
}
|
|
61
|
+
export function findPageMapping(pathWithoutPrefix, pages) {
|
|
62
|
+
const stripped = pathWithoutPrefix[0] === "/" ? pathWithoutPrefix.slice(1) : pathWithoutPrefix;
|
|
63
|
+
const pageKey = stripped.endsWith("/index") ? stripped.slice(0, -6) || "index" : stripped || "index";
|
|
64
|
+
if (pages[pageKey])
|
|
65
|
+
return { mappings: pages[pageKey], paramSegments: [] };
|
|
66
|
+
const sortedKeys = Object.keys(pages).sort((a, b) => b.length - a.length);
|
|
67
|
+
for (const key of sortedKeys) {
|
|
68
|
+
if (pageKey.startsWith(key + "/")) {
|
|
69
|
+
const paramPath = pageKey.slice(key.length + 1);
|
|
70
|
+
return { mappings: pages[key], paramSegments: paramPath.split("/") };
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
export function applyDynamicParams(customPath, paramSegments) {
|
|
76
|
+
if (!paramSegments.length)
|
|
77
|
+
return customPath;
|
|
78
|
+
let i = 0;
|
|
79
|
+
return customPath.replace(/\[[^\]]+\]/g, () => paramSegments[i++] || "");
|
|
80
|
+
}
|
|
61
81
|
export function createFilter(options = {}) {
|
|
62
82
|
const include = options.include || [];
|
|
63
83
|
const exclude = options.exclude || [];
|
package/dist/types.d.mts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
|
+
import type { ModuleHooks } from './module.mjs'
|
|
2
|
+
|
|
3
|
+
declare module '@nuxt/schema' {
|
|
4
|
+
interface NuxtHooks extends ModuleHooks {}
|
|
5
|
+
}
|
|
6
|
+
|
|
1
7
|
export { default } from './module.mjs'
|
|
2
8
|
|
|
3
|
-
export { type ModuleOptions } from './module.mjs'
|
|
9
|
+
export { type ModuleHooks, type ModuleOptions } from './module.mjs'
|
|
4
10
|
|
|
5
11
|
export * from '../dist/runtime/types.js'
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nuxtjs/sitemap",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "7.
|
|
4
|
+
"version": "7.5.1",
|
|
5
5
|
"description": "Powerfully flexible XML Sitemaps that integrate seamlessly, for Nuxt.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Harlan Wilton",
|
|
@@ -75,13 +75,14 @@
|
|
|
75
75
|
},
|
|
76
76
|
"devDependencies": {
|
|
77
77
|
"@arethetypeswrong/cli": "^0.18.2",
|
|
78
|
-
"@nuxt/content": "^3.
|
|
78
|
+
"@nuxt/content": "^3.10.0",
|
|
79
79
|
"@nuxt/eslint-config": "^1.12.1",
|
|
80
80
|
"@nuxt/module-builder": "^1.0.2",
|
|
81
|
-
"@nuxt/test-utils": "^3.
|
|
82
|
-
"@nuxt/ui": "^4.
|
|
81
|
+
"@nuxt/test-utils": "^3.22.0",
|
|
82
|
+
"@nuxt/ui": "^4.3.0",
|
|
83
83
|
"@nuxtjs/i18n": "^10.2.1",
|
|
84
84
|
"@nuxtjs/robots": "^5.6.7",
|
|
85
|
+
"@vue/test-utils": "^2.4.6",
|
|
85
86
|
"better-sqlite3": "^12.5.0",
|
|
86
87
|
"bumpp": "^10.3.2",
|
|
87
88
|
"eslint": "^9.39.2",
|
|
@@ -89,11 +90,11 @@
|
|
|
89
90
|
"execa": "^9.6.1",
|
|
90
91
|
"happy-dom": "^20.0.11",
|
|
91
92
|
"nuxt": "^4.2.2",
|
|
92
|
-
"nuxt-i18n-micro": "^2.
|
|
93
|
+
"nuxt-i18n-micro": "^2.16.3",
|
|
93
94
|
"typescript": "^5.9.3",
|
|
94
95
|
"vitest": "3.2.4",
|
|
95
|
-
"vue-tsc": "^3.
|
|
96
|
-
"@nuxtjs/sitemap": "7.
|
|
96
|
+
"vue-tsc": "^3.2.2",
|
|
97
|
+
"@nuxtjs/sitemap": "7.5.1"
|
|
97
98
|
},
|
|
98
99
|
"scripts": {
|
|
99
100
|
"lint": "eslint .",
|