@onruntime/next-sitemap 0.6.1 → 0.7.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/app/index.cjs +193 -208
- package/dist/app/index.d.cts +6 -11
- package/dist/app/index.d.ts +6 -11
- package/dist/app/index.js +194 -205
- package/dist/index.cjs +207 -0
- package/dist/index.d.cts +56 -1
- package/dist/index.d.ts +56 -1
- package/dist/index.js +179 -1
- package/dist/loader.js +38 -0
- package/dist/pages/index.cjs +194 -200
- package/dist/pages/index.d.cts +9 -27
- package/dist/pages/index.d.ts +9 -27
- package/dist/pages/index.js +195 -197
- package/dist/worker.cjs +207 -0
- package/package.json +2 -2
package/dist/app/index.js
CHANGED
|
@@ -1,9 +1,168 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
1
|
+
import { existsSync, readdirSync } from 'fs';
|
|
2
|
+
import { dirname, join, isAbsolute, relative, delimiter } from 'path';
|
|
3
|
+
import * as childProcess from 'child_process';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
5
|
|
|
6
6
|
// src/app/index.ts
|
|
7
|
+
var NO_STATIC_PARAMS = "NO_STATIC_PARAMS";
|
|
8
|
+
var spawnProcess = childProcess.spawn;
|
|
9
|
+
var __dirname$1 = dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
var paramsCache = /* @__PURE__ */ new Map();
|
|
11
|
+
var isDev = process.env.NODE_ENV === "development";
|
|
12
|
+
async function executeWorker(directory, fileKey, debug) {
|
|
13
|
+
const absolutePath = join(directory, fileKey.replace("./", ""));
|
|
14
|
+
const projectRoot = process.cwd();
|
|
15
|
+
const distRoot = join(__dirname$1, "..");
|
|
16
|
+
const workerPath = join(distRoot, "worker.cjs");
|
|
17
|
+
const loaderPath = join(distRoot, "loader.js");
|
|
18
|
+
if (debug) {
|
|
19
|
+
console.log(`[next-sitemap] Worker path: ${workerPath}`);
|
|
20
|
+
console.log(`[next-sitemap] Worker exists: ${existsSync(workerPath)}`);
|
|
21
|
+
console.log(`[next-sitemap] Loader path: ${loaderPath}`);
|
|
22
|
+
console.log(`[next-sitemap] Loader exists: ${existsSync(loaderPath)}`);
|
|
23
|
+
}
|
|
24
|
+
return new Promise((resolve) => {
|
|
25
|
+
const nodePath = [
|
|
26
|
+
join(projectRoot, "node_modules"),
|
|
27
|
+
join(__dirname$1, "..", "node_modules")
|
|
28
|
+
].join(delimiter);
|
|
29
|
+
const importFlag = ["--import", loaderPath];
|
|
30
|
+
const args = [...importFlag, workerPath, absolutePath, projectRoot];
|
|
31
|
+
const child = spawnProcess("node", args, {
|
|
32
|
+
cwd: projectRoot,
|
|
33
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
34
|
+
env: { ...process.env, NODE_PATH: nodePath }
|
|
35
|
+
});
|
|
36
|
+
let stdout = "";
|
|
37
|
+
let stderr = "";
|
|
38
|
+
child.stdout.on("data", (data) => {
|
|
39
|
+
stdout += data.toString();
|
|
40
|
+
});
|
|
41
|
+
child.stderr.on("data", (data) => {
|
|
42
|
+
stderr += data.toString();
|
|
43
|
+
});
|
|
44
|
+
child.on("close", (code) => {
|
|
45
|
+
if (debug && stderr) {
|
|
46
|
+
console.warn(`[next-sitemap] Worker stderr: ${stderr}`);
|
|
47
|
+
}
|
|
48
|
+
if (code !== 0 && code !== null) {
|
|
49
|
+
if (debug) console.warn(`[next-sitemap] Worker exited with code ${code}`);
|
|
50
|
+
resolve(null);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
const lines = stdout.trim().split("\n");
|
|
55
|
+
const result = JSON.parse(lines[lines.length - 1]);
|
|
56
|
+
if (result.success) {
|
|
57
|
+
resolve(result.params);
|
|
58
|
+
} else {
|
|
59
|
+
if (result.error !== NO_STATIC_PARAMS && debug) {
|
|
60
|
+
console.warn(`[next-sitemap] Worker error: ${result.error}`);
|
|
61
|
+
}
|
|
62
|
+
resolve(null);
|
|
63
|
+
}
|
|
64
|
+
} catch {
|
|
65
|
+
if (debug) console.warn(`[next-sitemap] Failed to parse worker output: ${stdout}`);
|
|
66
|
+
resolve(null);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
child.on("error", (err) => {
|
|
70
|
+
if (debug) console.warn(`[next-sitemap] Failed to spawn worker: ${err.message}`);
|
|
71
|
+
resolve(null);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
async function getRouteParams(route, directory, debug) {
|
|
76
|
+
const cacheKey = route.fileKey;
|
|
77
|
+
if (paramsCache.has(cacheKey)) {
|
|
78
|
+
return paramsCache.get(cacheKey);
|
|
79
|
+
}
|
|
80
|
+
if (debug) {
|
|
81
|
+
console.log(`[next-sitemap] ${route.pathname}: executing static params via worker`);
|
|
82
|
+
}
|
|
83
|
+
const params = await executeWorker(directory, route.fileKey, debug);
|
|
84
|
+
paramsCache.set(cacheKey, params);
|
|
85
|
+
if (debug && params) {
|
|
86
|
+
console.log(`[next-sitemap] ${route.pathname}: got ${params.length} params`);
|
|
87
|
+
}
|
|
88
|
+
return params;
|
|
89
|
+
}
|
|
90
|
+
async function generateAllPaths(routes, directory, debug) {
|
|
91
|
+
const staticPaths = ["/"];
|
|
92
|
+
const dynamicRoutes = [];
|
|
93
|
+
for (const route of routes) {
|
|
94
|
+
if (route.dynamicSegments.length === 0) {
|
|
95
|
+
if (route.pathname !== "/") {
|
|
96
|
+
staticPaths.push(route.pathname);
|
|
97
|
+
}
|
|
98
|
+
} else {
|
|
99
|
+
dynamicRoutes.push(route);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
const startTime = isDev ? Date.now() : 0;
|
|
103
|
+
if (isDev && dynamicRoutes.length > 0) {
|
|
104
|
+
console.log(`[next-sitemap] Generating sitemap for ${dynamicRoutes.length} dynamic routes (dev only, instant in production)...`);
|
|
105
|
+
}
|
|
106
|
+
const dynamicResults = await Promise.all(
|
|
107
|
+
dynamicRoutes.map(async (route) => {
|
|
108
|
+
const params = await getRouteParams(route, directory, debug);
|
|
109
|
+
if (!params || params.length === 0) {
|
|
110
|
+
if (debug) {
|
|
111
|
+
console.warn(`[next-sitemap] Skipping dynamic route ${route.pathname}: no static params or empty result.`);
|
|
112
|
+
}
|
|
113
|
+
return [];
|
|
114
|
+
}
|
|
115
|
+
const paths = [];
|
|
116
|
+
for (const param of params) {
|
|
117
|
+
let path = route.pathname;
|
|
118
|
+
let valid = true;
|
|
119
|
+
for (const segment of route.dynamicSegments) {
|
|
120
|
+
const value = param[segment];
|
|
121
|
+
if (value === void 0) {
|
|
122
|
+
if (debug) {
|
|
123
|
+
console.warn(`[next-sitemap] ${route.pathname}: missing param "${segment}" in`, param);
|
|
124
|
+
}
|
|
125
|
+
valid = false;
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
path = path.replace(`[${segment}]`, value);
|
|
129
|
+
}
|
|
130
|
+
if (valid) paths.push(path);
|
|
131
|
+
}
|
|
132
|
+
return paths;
|
|
133
|
+
})
|
|
134
|
+
);
|
|
135
|
+
const allPaths = new Set(staticPaths);
|
|
136
|
+
for (const paths of dynamicResults) {
|
|
137
|
+
for (const path of paths) {
|
|
138
|
+
allPaths.add(path);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (isDev && dynamicRoutes.length > 0) {
|
|
142
|
+
const elapsed = Date.now() - startTime;
|
|
143
|
+
console.log(`[next-sitemap] Done! Found ${allPaths.size} total URLs in ${elapsed}ms.`);
|
|
144
|
+
}
|
|
145
|
+
return Array.from(allPaths);
|
|
146
|
+
}
|
|
147
|
+
function pathsToEntries(paths, config) {
|
|
148
|
+
const { baseUrl, locales = [], defaultLocale, exclude, priority, changeFreq } = config;
|
|
149
|
+
return paths.filter((pathname) => !shouldExclude(pathname, exclude)).map((pathname) => {
|
|
150
|
+
const entry = {
|
|
151
|
+
url: buildUrl(baseUrl, pathname, defaultLocale, defaultLocale),
|
|
152
|
+
lastModified: /* @__PURE__ */ new Date(),
|
|
153
|
+
changeFrequency: getChangeFreq(pathname, changeFreq),
|
|
154
|
+
priority: getPriority(pathname, priority)
|
|
155
|
+
};
|
|
156
|
+
if (locales.length > 0) {
|
|
157
|
+
entry.alternates = {
|
|
158
|
+
languages: Object.fromEntries(
|
|
159
|
+
locales.map((locale) => [locale, buildUrl(baseUrl, pathname, locale, defaultLocale)])
|
|
160
|
+
)
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
return entry;
|
|
164
|
+
});
|
|
165
|
+
}
|
|
7
166
|
|
|
8
167
|
// src/index.ts
|
|
9
168
|
function calculateDepthPriority(pathname) {
|
|
@@ -109,13 +268,13 @@ ${allEntries}
|
|
|
109
268
|
function findPageFiles(dir, baseDir = dir) {
|
|
110
269
|
const files = [];
|
|
111
270
|
try {
|
|
112
|
-
const entries =
|
|
271
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
113
272
|
for (const entry of entries) {
|
|
114
|
-
const fullPath =
|
|
273
|
+
const fullPath = join(dir, entry.name);
|
|
115
274
|
if (entry.isDirectory()) {
|
|
116
275
|
files.push(...findPageFiles(fullPath, baseDir));
|
|
117
276
|
} else if (/^page\.(tsx?|jsx?)$/.test(entry.name)) {
|
|
118
|
-
const relativePath = "./" +
|
|
277
|
+
const relativePath = "./" + relative(baseDir, fullPath).replace(/\\/g, "/");
|
|
119
278
|
files.push(relativePath);
|
|
120
279
|
}
|
|
121
280
|
}
|
|
@@ -123,83 +282,12 @@ function findPageFiles(dir, baseDir = dir) {
|
|
|
123
282
|
}
|
|
124
283
|
return files;
|
|
125
284
|
}
|
|
126
|
-
function
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
return srcApp;
|
|
130
|
-
}
|
|
131
|
-
return path.join(process.cwd(), "app");
|
|
132
|
-
}
|
|
133
|
-
function resolveAppDirectory(options) {
|
|
134
|
-
if (options.appDirectory) {
|
|
135
|
-
return path.isAbsolute(options.appDirectory) ? options.appDirectory : path.join(process.cwd(), options.appDirectory);
|
|
285
|
+
function resolveAppDirectory(appDirectory) {
|
|
286
|
+
if (appDirectory) {
|
|
287
|
+
return isAbsolute(appDirectory) ? appDirectory : join(process.cwd(), appDirectory);
|
|
136
288
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
function getPageKeys(options) {
|
|
140
|
-
return findPageFiles(resolveAppDirectory(options));
|
|
141
|
-
}
|
|
142
|
-
var jitiCache = /* @__PURE__ */ new Map();
|
|
143
|
-
function getTsconfigPaths(projectRoot, debug = false) {
|
|
144
|
-
const alias = {};
|
|
145
|
-
try {
|
|
146
|
-
const tsconfigPath = path.join(projectRoot, "tsconfig.json");
|
|
147
|
-
if (debug) {
|
|
148
|
-
console.log("[next-sitemap] Looking for tsconfig at:", tsconfigPath);
|
|
149
|
-
console.log("[next-sitemap] tsconfig exists:", fs.existsSync(tsconfigPath));
|
|
150
|
-
}
|
|
151
|
-
if (fs.existsSync(tsconfigPath)) {
|
|
152
|
-
const content = fs.readFileSync(tsconfigPath, "utf-8");
|
|
153
|
-
const withoutComments = stripJsonComments(content);
|
|
154
|
-
const cleaned = withoutComments.replace(/,(\s*[}\]])/g, "$1");
|
|
155
|
-
if (debug) {
|
|
156
|
-
console.log("[next-sitemap] Cleaned tsconfig (first 500 chars):", cleaned.slice(0, 500));
|
|
157
|
-
}
|
|
158
|
-
const tsconfig = JSON.parse(cleaned);
|
|
159
|
-
if (debug) {
|
|
160
|
-
console.log("[next-sitemap] Parsed tsconfig paths:", tsconfig.compilerOptions?.paths);
|
|
161
|
-
}
|
|
162
|
-
const baseUrl = tsconfig.compilerOptions?.baseUrl || ".";
|
|
163
|
-
const paths = tsconfig.compilerOptions?.paths || {};
|
|
164
|
-
for (const [key, values] of Object.entries(paths)) {
|
|
165
|
-
if (values.length > 0) {
|
|
166
|
-
const aliasKey = key.replace(/\*$/, "");
|
|
167
|
-
const aliasValue = path.join(projectRoot, baseUrl, values[0].replace(/\*$/, ""));
|
|
168
|
-
alias[aliasKey] = aliasValue;
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
} catch (error) {
|
|
173
|
-
if (debug) {
|
|
174
|
-
console.error("[next-sitemap] Error parsing tsconfig:", error);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
return alias;
|
|
178
|
-
}
|
|
179
|
-
function getJiti(projectRoot, debug = false) {
|
|
180
|
-
if (jitiCache.has(projectRoot)) {
|
|
181
|
-
return jitiCache.get(projectRoot);
|
|
182
|
-
}
|
|
183
|
-
const alias = getTsconfigPaths(projectRoot, debug);
|
|
184
|
-
if (debug) {
|
|
185
|
-
console.log("[next-sitemap] Final alias config:", JSON.stringify(alias));
|
|
186
|
-
}
|
|
187
|
-
const jiti = createJiti(import.meta.url, {
|
|
188
|
-
moduleCache: false,
|
|
189
|
-
interopDefault: true,
|
|
190
|
-
jsx: true,
|
|
191
|
-
alias
|
|
192
|
-
});
|
|
193
|
-
jitiCache.set(projectRoot, jiti);
|
|
194
|
-
return jiti;
|
|
195
|
-
}
|
|
196
|
-
async function importPage(appDirectory, key, debug = false) {
|
|
197
|
-
const relativePath = key.replace("./", "");
|
|
198
|
-
const absolutePath = path.join(appDirectory, relativePath);
|
|
199
|
-
const projectRoot = process.cwd();
|
|
200
|
-
const jiti = getJiti(projectRoot, debug);
|
|
201
|
-
const module = await jiti.import(absolutePath);
|
|
202
|
-
return module.default || module;
|
|
289
|
+
const srcApp = join(process.cwd(), "src/app");
|
|
290
|
+
return existsSync(srcApp) ? srcApp : join(process.cwd(), "app");
|
|
203
291
|
}
|
|
204
292
|
function extractRoutes(pageKeys, localeSegment) {
|
|
205
293
|
const routes = [];
|
|
@@ -207,163 +295,64 @@ function extractRoutes(pageKeys, localeSegment) {
|
|
|
207
295
|
if (key.includes("[...")) continue;
|
|
208
296
|
let pathname = key.replace("./", "/").replace(/\/page\.(tsx?|jsx?)$/, "");
|
|
209
297
|
if (localeSegment) {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
""
|
|
213
|
-
);
|
|
298
|
+
const escapedSegment = localeSegment.replace(/[[\]]/g, "\\$&");
|
|
299
|
+
pathname = pathname.replace(new RegExp(`^/${escapedSegment}`), "");
|
|
214
300
|
}
|
|
215
301
|
pathname = pathname.replace(/\/\([^)]+\)/g, "");
|
|
216
302
|
if (/(?:^|\/)(src|app)(?:\/|$)/.test(pathname)) continue;
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
} else if (!pathname.startsWith("/")) {
|
|
303
|
+
pathname = pathname || "/";
|
|
304
|
+
if (pathname !== "/" && !pathname.startsWith("/")) {
|
|
220
305
|
pathname = "/" + pathname;
|
|
221
306
|
}
|
|
222
|
-
const dynamicSegments = pathname.match(/\[([^\]]+)\]/g)?.map((s) => s.slice(1, -1))
|
|
223
|
-
routes.push({
|
|
224
|
-
pathname,
|
|
225
|
-
dynamicSegments,
|
|
226
|
-
key
|
|
227
|
-
});
|
|
307
|
+
const dynamicSegments = pathname.match(/\[([^\]]+)\]/g)?.map((s) => s.slice(1, -1)) ?? [];
|
|
308
|
+
routes.push({ pathname, dynamicSegments, fileKey: key });
|
|
228
309
|
}
|
|
229
310
|
return routes;
|
|
230
311
|
}
|
|
231
|
-
async function getAllPaths(routes, appDirectory, debug = false) {
|
|
232
|
-
const allPaths = ["/"];
|
|
233
|
-
const seenPaths = /* @__PURE__ */ new Set(["/"]);
|
|
234
|
-
for (const route of routes) {
|
|
235
|
-
if (route.dynamicSegments.length === 0) {
|
|
236
|
-
if (route.pathname !== "/" && !seenPaths.has(route.pathname)) {
|
|
237
|
-
allPaths.push(route.pathname);
|
|
238
|
-
seenPaths.add(route.pathname);
|
|
239
|
-
}
|
|
240
|
-
} else {
|
|
241
|
-
let getParams = null;
|
|
242
|
-
try {
|
|
243
|
-
if (debug) {
|
|
244
|
-
console.log(`[next-sitemap] ${route.pathname}: importing ${route.key}`);
|
|
245
|
-
}
|
|
246
|
-
const module = await importPage(appDirectory, route.key, debug);
|
|
247
|
-
getParams = module.generateStaticParams || null;
|
|
248
|
-
} catch (error) {
|
|
249
|
-
if (debug) {
|
|
250
|
-
console.warn(`[next-sitemap] ${route.pathname}: import failed:`, error);
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
if (getParams) {
|
|
254
|
-
try {
|
|
255
|
-
const params = await getParams();
|
|
256
|
-
if (debug) {
|
|
257
|
-
console.log(`[next-sitemap] ${route.pathname}: generateStaticParams returned ${params.length} params`);
|
|
258
|
-
}
|
|
259
|
-
for (const param of params) {
|
|
260
|
-
let dynamicPath = route.pathname;
|
|
261
|
-
for (const segment of route.dynamicSegments) {
|
|
262
|
-
const value = param[segment];
|
|
263
|
-
if (value === void 0) {
|
|
264
|
-
if (debug) {
|
|
265
|
-
console.warn(`[next-sitemap] ${route.pathname}: missing param "${segment}" in`, param);
|
|
266
|
-
}
|
|
267
|
-
continue;
|
|
268
|
-
}
|
|
269
|
-
dynamicPath = dynamicPath.replace(`[${segment}]`, value);
|
|
270
|
-
}
|
|
271
|
-
if (!seenPaths.has(dynamicPath)) {
|
|
272
|
-
allPaths.push(dynamicPath);
|
|
273
|
-
seenPaths.add(dynamicPath);
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
} catch (error) {
|
|
277
|
-
console.error(`[next-sitemap] Error calling generateStaticParams for ${route.pathname}:`, error);
|
|
278
|
-
}
|
|
279
|
-
} else {
|
|
280
|
-
if (debug) {
|
|
281
|
-
console.warn(
|
|
282
|
-
`[next-sitemap] Skipping dynamic route ${route.pathname}: no generateStaticParams exported. Use additionalSitemaps for routes that fetch data at runtime.`
|
|
283
|
-
);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
return allPaths;
|
|
289
|
-
}
|
|
290
|
-
function pathsToEntries(paths, config) {
|
|
291
|
-
const { baseUrl, locales = [], defaultLocale, exclude, priority, changeFreq } = config;
|
|
292
|
-
const filteredPaths = paths.filter((pathname) => !shouldExclude(pathname, exclude));
|
|
293
|
-
return filteredPaths.map((pathname) => {
|
|
294
|
-
const entry = {
|
|
295
|
-
url: buildUrl(baseUrl, pathname, defaultLocale, defaultLocale),
|
|
296
|
-
lastModified: /* @__PURE__ */ new Date(),
|
|
297
|
-
changeFrequency: getChangeFreq(pathname, changeFreq),
|
|
298
|
-
priority: getPriority(pathname, priority)
|
|
299
|
-
};
|
|
300
|
-
if (locales.length > 0) {
|
|
301
|
-
entry.alternates = {
|
|
302
|
-
languages: Object.fromEntries(
|
|
303
|
-
locales.map((locale) => [
|
|
304
|
-
locale,
|
|
305
|
-
buildUrl(baseUrl, pathname, locale, defaultLocale)
|
|
306
|
-
])
|
|
307
|
-
)
|
|
308
|
-
};
|
|
309
|
-
}
|
|
310
|
-
return entry;
|
|
311
|
-
});
|
|
312
|
-
}
|
|
313
312
|
function createSitemapIndexHandler(options) {
|
|
314
313
|
const { urlsPerSitemap = 5e3, locales = [], defaultLocale, additionalSitemaps, exclude, debug = false } = options;
|
|
315
314
|
const localeSegment = options.localeSegment ?? (locales.length > 0 || defaultLocale ? "[locale]" : "");
|
|
316
|
-
const appDir = resolveAppDirectory(options);
|
|
317
|
-
const pageKeys =
|
|
315
|
+
const appDir = resolveAppDirectory(options.appDirectory);
|
|
316
|
+
const pageKeys = findPageFiles(appDir);
|
|
318
317
|
const routes = extractRoutes(pageKeys, localeSegment);
|
|
319
318
|
return {
|
|
320
319
|
GET: async () => {
|
|
321
320
|
if (debug) {
|
|
322
|
-
console.log(`[next-sitemap] Found ${routes.length} routes
|
|
323
|
-
routes.forEach((r) => {
|
|
324
|
-
const isDynamic = r.dynamicSegments.length > 0;
|
|
325
|
-
const segments = isDynamic ? ` [${r.dynamicSegments.join(", ")}]` : "";
|
|
326
|
-
console.log(` ${r.pathname}${segments}${isDynamic ? " (dynamic)" : ""}`);
|
|
327
|
-
});
|
|
321
|
+
console.log(`[next-sitemap] Found ${routes.length} routes`);
|
|
328
322
|
}
|
|
329
|
-
const allPaths = await
|
|
330
|
-
const filteredPaths = allPaths.filter((
|
|
323
|
+
const allPaths = await generateAllPaths(routes, appDir, debug);
|
|
324
|
+
const filteredPaths = allPaths.filter((p) => !shouldExclude(p, exclude));
|
|
331
325
|
const sitemapCount = Math.max(1, Math.ceil(filteredPaths.length / urlsPerSitemap));
|
|
332
|
-
|
|
333
|
-
additionalSitemaps
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
headers: { "Content-Type": "application/xml" }
|
|
337
|
-
});
|
|
326
|
+
return new Response(
|
|
327
|
+
generateSitemapIndexXml(options.baseUrl, sitemapCount, { additionalSitemaps }),
|
|
328
|
+
{ headers: { "Content-Type": "application/xml" } }
|
|
329
|
+
);
|
|
338
330
|
}
|
|
339
331
|
};
|
|
340
332
|
}
|
|
341
333
|
function createSitemapHandler(options) {
|
|
342
334
|
const { urlsPerSitemap = 5e3, locales = [], defaultLocale, exclude, debug = false } = options;
|
|
343
335
|
const localeSegment = options.localeSegment ?? (locales.length > 0 || defaultLocale ? "[locale]" : "");
|
|
344
|
-
const appDir = resolveAppDirectory(options);
|
|
345
|
-
const pageKeys =
|
|
336
|
+
const appDir = resolveAppDirectory(options.appDirectory);
|
|
337
|
+
const pageKeys = findPageFiles(appDir);
|
|
346
338
|
const routes = extractRoutes(pageKeys, localeSegment);
|
|
347
339
|
const getFilteredPaths = async () => {
|
|
348
|
-
const allPaths = await
|
|
349
|
-
return allPaths.filter((
|
|
340
|
+
const allPaths = await generateAllPaths(routes, appDir, debug);
|
|
341
|
+
return allPaths.filter((p) => !shouldExclude(p, exclude));
|
|
350
342
|
};
|
|
351
343
|
return {
|
|
352
344
|
generateStaticParams: async () => {
|
|
353
345
|
const filteredPaths = await getFilteredPaths();
|
|
354
|
-
const
|
|
355
|
-
return Array.from({ length:
|
|
346
|
+
const count = Math.max(1, Math.ceil(filteredPaths.length / urlsPerSitemap));
|
|
347
|
+
return Array.from({ length: count }, (_, i) => ({ id: String(i) }));
|
|
356
348
|
},
|
|
357
349
|
GET: async (_request, { params }) => {
|
|
358
350
|
const { id } = await params;
|
|
359
351
|
const sitemapId = parseInt(id, 10);
|
|
360
352
|
const filteredPaths = await getFilteredPaths();
|
|
361
|
-
const
|
|
362
|
-
const end = start + urlsPerSitemap;
|
|
363
|
-
const paths = filteredPaths.slice(start, end);
|
|
353
|
+
const paths = filteredPaths.slice(sitemapId * urlsPerSitemap, (sitemapId + 1) * urlsPerSitemap);
|
|
364
354
|
const entries = pathsToEntries(paths, { ...options, exclude: void 0 });
|
|
365
|
-
|
|
366
|
-
return new Response(xml, {
|
|
355
|
+
return new Response(generateSitemapXml(entries), {
|
|
367
356
|
headers: { "Content-Type": "application/xml" }
|
|
368
357
|
});
|
|
369
358
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,204 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var fs = require('fs');
|
|
4
|
+
var path = require('path');
|
|
5
|
+
var childProcess = require('child_process');
|
|
6
|
+
var url = require('url');
|
|
7
|
+
|
|
8
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
9
|
+
function _interopNamespace(e) {
|
|
10
|
+
if (e && e.__esModule) return e;
|
|
11
|
+
var n = Object.create(null);
|
|
12
|
+
if (e) {
|
|
13
|
+
Object.keys(e).forEach(function (k) {
|
|
14
|
+
if (k !== 'default') {
|
|
15
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
16
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
17
|
+
enumerable: true,
|
|
18
|
+
get: function () { return e[k]; }
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
n.default = e;
|
|
24
|
+
return Object.freeze(n);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
var childProcess__namespace = /*#__PURE__*/_interopNamespace(childProcess);
|
|
28
|
+
|
|
29
|
+
// src/shared.ts
|
|
30
|
+
var JS_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
31
|
+
".js",
|
|
32
|
+
".cjs",
|
|
33
|
+
".mjs",
|
|
34
|
+
".jsx",
|
|
35
|
+
".ts",
|
|
36
|
+
".cts",
|
|
37
|
+
".mts",
|
|
38
|
+
".tsx",
|
|
39
|
+
".json",
|
|
40
|
+
".node"
|
|
41
|
+
]);
|
|
42
|
+
var NO_STATIC_PARAMS = "NO_STATIC_PARAMS";
|
|
43
|
+
var spawnProcess = childProcess__namespace.spawn;
|
|
44
|
+
var __dirname$1 = path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))));
|
|
45
|
+
var paramsCache = /* @__PURE__ */ new Map();
|
|
46
|
+
var isDev = process.env.NODE_ENV === "development";
|
|
47
|
+
async function executeWorker(directory, fileKey, debug) {
|
|
48
|
+
const absolutePath = path.join(directory, fileKey.replace("./", ""));
|
|
49
|
+
const projectRoot = process.cwd();
|
|
50
|
+
const distRoot = path.join(__dirname$1, "..");
|
|
51
|
+
const workerPath = path.join(distRoot, "worker.cjs");
|
|
52
|
+
const loaderPath = path.join(distRoot, "loader.js");
|
|
53
|
+
if (debug) {
|
|
54
|
+
console.log(`[next-sitemap] Worker path: ${workerPath}`);
|
|
55
|
+
console.log(`[next-sitemap] Worker exists: ${fs.existsSync(workerPath)}`);
|
|
56
|
+
console.log(`[next-sitemap] Loader path: ${loaderPath}`);
|
|
57
|
+
console.log(`[next-sitemap] Loader exists: ${fs.existsSync(loaderPath)}`);
|
|
58
|
+
}
|
|
59
|
+
return new Promise((resolve) => {
|
|
60
|
+
const nodePath = [
|
|
61
|
+
path.join(projectRoot, "node_modules"),
|
|
62
|
+
path.join(__dirname$1, "..", "node_modules")
|
|
63
|
+
].join(path.delimiter);
|
|
64
|
+
const importFlag = ["--import", loaderPath];
|
|
65
|
+
const args = [...importFlag, workerPath, absolutePath, projectRoot];
|
|
66
|
+
const child = spawnProcess("node", args, {
|
|
67
|
+
cwd: projectRoot,
|
|
68
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
69
|
+
env: { ...process.env, NODE_PATH: nodePath }
|
|
70
|
+
});
|
|
71
|
+
let stdout = "";
|
|
72
|
+
let stderr = "";
|
|
73
|
+
child.stdout.on("data", (data) => {
|
|
74
|
+
stdout += data.toString();
|
|
75
|
+
});
|
|
76
|
+
child.stderr.on("data", (data) => {
|
|
77
|
+
stderr += data.toString();
|
|
78
|
+
});
|
|
79
|
+
child.on("close", (code) => {
|
|
80
|
+
if (debug && stderr) {
|
|
81
|
+
console.warn(`[next-sitemap] Worker stderr: ${stderr}`);
|
|
82
|
+
}
|
|
83
|
+
if (code !== 0 && code !== null) {
|
|
84
|
+
if (debug) console.warn(`[next-sitemap] Worker exited with code ${code}`);
|
|
85
|
+
resolve(null);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
const lines = stdout.trim().split("\n");
|
|
90
|
+
const result = JSON.parse(lines[lines.length - 1]);
|
|
91
|
+
if (result.success) {
|
|
92
|
+
resolve(result.params);
|
|
93
|
+
} else {
|
|
94
|
+
if (result.error !== NO_STATIC_PARAMS && debug) {
|
|
95
|
+
console.warn(`[next-sitemap] Worker error: ${result.error}`);
|
|
96
|
+
}
|
|
97
|
+
resolve(null);
|
|
98
|
+
}
|
|
99
|
+
} catch {
|
|
100
|
+
if (debug) console.warn(`[next-sitemap] Failed to parse worker output: ${stdout}`);
|
|
101
|
+
resolve(null);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
child.on("error", (err) => {
|
|
105
|
+
if (debug) console.warn(`[next-sitemap] Failed to spawn worker: ${err.message}`);
|
|
106
|
+
resolve(null);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
async function getRouteParams(route, directory, debug) {
|
|
111
|
+
const cacheKey = route.fileKey;
|
|
112
|
+
if (paramsCache.has(cacheKey)) {
|
|
113
|
+
return paramsCache.get(cacheKey);
|
|
114
|
+
}
|
|
115
|
+
if (debug) {
|
|
116
|
+
console.log(`[next-sitemap] ${route.pathname}: executing static params via worker`);
|
|
117
|
+
}
|
|
118
|
+
const params = await executeWorker(directory, route.fileKey, debug);
|
|
119
|
+
paramsCache.set(cacheKey, params);
|
|
120
|
+
if (debug && params) {
|
|
121
|
+
console.log(`[next-sitemap] ${route.pathname}: got ${params.length} params`);
|
|
122
|
+
}
|
|
123
|
+
return params;
|
|
124
|
+
}
|
|
125
|
+
async function generateAllPaths(routes, directory, debug) {
|
|
126
|
+
const staticPaths = ["/"];
|
|
127
|
+
const dynamicRoutes = [];
|
|
128
|
+
for (const route of routes) {
|
|
129
|
+
if (route.dynamicSegments.length === 0) {
|
|
130
|
+
if (route.pathname !== "/") {
|
|
131
|
+
staticPaths.push(route.pathname);
|
|
132
|
+
}
|
|
133
|
+
} else {
|
|
134
|
+
dynamicRoutes.push(route);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
const startTime = isDev ? Date.now() : 0;
|
|
138
|
+
if (isDev && dynamicRoutes.length > 0) {
|
|
139
|
+
console.log(`[next-sitemap] Generating sitemap for ${dynamicRoutes.length} dynamic routes (dev only, instant in production)...`);
|
|
140
|
+
}
|
|
141
|
+
const dynamicResults = await Promise.all(
|
|
142
|
+
dynamicRoutes.map(async (route) => {
|
|
143
|
+
const params = await getRouteParams(route, directory, debug);
|
|
144
|
+
if (!params || params.length === 0) {
|
|
145
|
+
if (debug) {
|
|
146
|
+
console.warn(`[next-sitemap] Skipping dynamic route ${route.pathname}: no static params or empty result.`);
|
|
147
|
+
}
|
|
148
|
+
return [];
|
|
149
|
+
}
|
|
150
|
+
const paths = [];
|
|
151
|
+
for (const param of params) {
|
|
152
|
+
let path = route.pathname;
|
|
153
|
+
let valid = true;
|
|
154
|
+
for (const segment of route.dynamicSegments) {
|
|
155
|
+
const value = param[segment];
|
|
156
|
+
if (value === void 0) {
|
|
157
|
+
if (debug) {
|
|
158
|
+
console.warn(`[next-sitemap] ${route.pathname}: missing param "${segment}" in`, param);
|
|
159
|
+
}
|
|
160
|
+
valid = false;
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
path = path.replace(`[${segment}]`, value);
|
|
164
|
+
}
|
|
165
|
+
if (valid) paths.push(path);
|
|
166
|
+
}
|
|
167
|
+
return paths;
|
|
168
|
+
})
|
|
169
|
+
);
|
|
170
|
+
const allPaths = new Set(staticPaths);
|
|
171
|
+
for (const paths of dynamicResults) {
|
|
172
|
+
for (const path of paths) {
|
|
173
|
+
allPaths.add(path);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (isDev && dynamicRoutes.length > 0) {
|
|
177
|
+
const elapsed = Date.now() - startTime;
|
|
178
|
+
console.log(`[next-sitemap] Done! Found ${allPaths.size} total URLs in ${elapsed}ms.`);
|
|
179
|
+
}
|
|
180
|
+
return Array.from(allPaths);
|
|
181
|
+
}
|
|
182
|
+
function pathsToEntries(paths, config) {
|
|
183
|
+
const { baseUrl, locales = [], defaultLocale, exclude, priority, changeFreq } = config;
|
|
184
|
+
return paths.filter((pathname) => !shouldExclude(pathname, exclude)).map((pathname) => {
|
|
185
|
+
const entry = {
|
|
186
|
+
url: buildUrl(baseUrl, pathname, defaultLocale, defaultLocale),
|
|
187
|
+
lastModified: /* @__PURE__ */ new Date(),
|
|
188
|
+
changeFrequency: getChangeFreq(pathname, changeFreq),
|
|
189
|
+
priority: getPriority(pathname, priority)
|
|
190
|
+
};
|
|
191
|
+
if (locales.length > 0) {
|
|
192
|
+
entry.alternates = {
|
|
193
|
+
languages: Object.fromEntries(
|
|
194
|
+
locales.map((locale) => [locale, buildUrl(baseUrl, pathname, locale, defaultLocale)])
|
|
195
|
+
)
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
return entry;
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
|
|
3
202
|
// src/index.ts
|
|
4
203
|
function calculateDepthPriority(pathname) {
|
|
5
204
|
if (pathname === "/") return 1;
|
|
@@ -100,11 +299,19 @@ ${allEntries}
|
|
|
100
299
|
</sitemapindex>`;
|
|
101
300
|
}
|
|
102
301
|
|
|
302
|
+
exports.JS_EXTENSIONS = JS_EXTENSIONS;
|
|
303
|
+
exports.NO_STATIC_PARAMS = NO_STATIC_PARAMS;
|
|
103
304
|
exports.buildUrl = buildUrl;
|
|
104
305
|
exports.calculateDepthPriority = calculateDepthPriority;
|
|
306
|
+
exports.executeWorker = executeWorker;
|
|
307
|
+
exports.generateAllPaths = generateAllPaths;
|
|
105
308
|
exports.generateSitemapIndexXml = generateSitemapIndexXml;
|
|
106
309
|
exports.generateSitemapXml = generateSitemapXml;
|
|
107
310
|
exports.getChangeFreq = getChangeFreq;
|
|
108
311
|
exports.getPriority = getPriority;
|
|
312
|
+
exports.getRouteParams = getRouteParams;
|
|
313
|
+
exports.isDev = isDev;
|
|
109
314
|
exports.normalizePath = normalizePath;
|
|
315
|
+
exports.paramsCache = paramsCache;
|
|
316
|
+
exports.pathsToEntries = pathsToEntries;
|
|
110
317
|
exports.shouldExclude = shouldExclude;
|