@onruntime/next-sitemap 0.6.2 → 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 -209
- package/dist/app/index.d.cts +6 -11
- package/dist/app/index.d.ts +6 -11
- package/dist/app/index.js +194 -206
- 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 -201
- package/dist/pages/index.d.cts +9 -27
- package/dist/pages/index.d.ts +9 -27
- package/dist/pages/index.js +195 -198
- package/dist/worker.cjs +207 -0
- package/package.json +2 -2
package/dist/pages/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/pages/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) {
|
|
@@ -144,18 +303,17 @@ function generateRobotsTxt(config) {
|
|
|
144
303
|
}
|
|
145
304
|
|
|
146
305
|
// src/pages/index.ts
|
|
147
|
-
var joinPath = (...segments) => path.join(...segments);
|
|
148
306
|
function findPageFiles(dir, baseDir = dir) {
|
|
149
307
|
const files = [];
|
|
150
308
|
try {
|
|
151
|
-
const entries =
|
|
309
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
152
310
|
for (const entry of entries) {
|
|
153
|
-
const fullPath =
|
|
311
|
+
const fullPath = join(dir, entry.name);
|
|
154
312
|
if (entry.isDirectory()) {
|
|
155
313
|
if (entry.name === "api") continue;
|
|
156
314
|
files.push(...findPageFiles(fullPath, baseDir));
|
|
157
315
|
} else if (/\.(tsx?|jsx?)$/.test(entry.name) && !entry.name.startsWith("_")) {
|
|
158
|
-
const relativePath = "./" +
|
|
316
|
+
const relativePath = "./" + relative(baseDir, fullPath).replace(/\\/g, "/");
|
|
159
317
|
files.push(relativePath);
|
|
160
318
|
}
|
|
161
319
|
}
|
|
@@ -163,67 +321,12 @@ function findPageFiles(dir, baseDir = dir) {
|
|
|
163
321
|
}
|
|
164
322
|
return files;
|
|
165
323
|
}
|
|
166
|
-
function
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
return srcPages;
|
|
170
|
-
}
|
|
171
|
-
return path.join(process.cwd(), "pages");
|
|
172
|
-
}
|
|
173
|
-
function resolvePagesDirectory(options) {
|
|
174
|
-
if (options.pagesDirectory) {
|
|
175
|
-
return path.isAbsolute(options.pagesDirectory) ? options.pagesDirectory : path.join(process.cwd(), options.pagesDirectory);
|
|
324
|
+
function resolvePagesDirectory(pagesDirectory) {
|
|
325
|
+
if (pagesDirectory) {
|
|
326
|
+
return isAbsolute(pagesDirectory) ? pagesDirectory : join(process.cwd(), pagesDirectory);
|
|
176
327
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
function getPageKeys(options) {
|
|
180
|
-
return findPageFiles(resolvePagesDirectory(options));
|
|
181
|
-
}
|
|
182
|
-
var jitiCache = /* @__PURE__ */ new Map();
|
|
183
|
-
function getTsconfigPaths(projectRoot) {
|
|
184
|
-
const alias = {};
|
|
185
|
-
try {
|
|
186
|
-
const tsconfigPath = path.join(projectRoot, "tsconfig.json");
|
|
187
|
-
if (fs.existsSync(tsconfigPath)) {
|
|
188
|
-
const content = fs.readFileSync(tsconfigPath, "utf-8");
|
|
189
|
-
const withoutComments = stripJsonComments(content);
|
|
190
|
-
const cleaned = withoutComments.replace(/,(\s*[}\]])/g, "$1");
|
|
191
|
-
const tsconfig = JSON.parse(cleaned);
|
|
192
|
-
const baseUrl = tsconfig.compilerOptions?.baseUrl || ".";
|
|
193
|
-
const paths = tsconfig.compilerOptions?.paths || {};
|
|
194
|
-
for (const [key, values] of Object.entries(paths)) {
|
|
195
|
-
if (values.length > 0) {
|
|
196
|
-
const aliasKey = key.replace(/\*$/, "");
|
|
197
|
-
const aliasValue = joinPath(projectRoot, baseUrl, values[0].replace(/\*$/, ""));
|
|
198
|
-
alias[aliasKey] = aliasValue;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
} catch {
|
|
203
|
-
}
|
|
204
|
-
return alias;
|
|
205
|
-
}
|
|
206
|
-
function getJiti(projectRoot) {
|
|
207
|
-
if (jitiCache.has(projectRoot)) {
|
|
208
|
-
return jitiCache.get(projectRoot);
|
|
209
|
-
}
|
|
210
|
-
const alias = getTsconfigPaths(projectRoot);
|
|
211
|
-
const jiti = createJiti(import.meta.url, {
|
|
212
|
-
moduleCache: false,
|
|
213
|
-
interopDefault: true,
|
|
214
|
-
jsx: true,
|
|
215
|
-
alias
|
|
216
|
-
});
|
|
217
|
-
jitiCache.set(projectRoot, jiti);
|
|
218
|
-
return jiti;
|
|
219
|
-
}
|
|
220
|
-
async function importPage(pagesDirectory, key) {
|
|
221
|
-
const relativePath = key.replace("./", "");
|
|
222
|
-
const absolutePath = path.join(pagesDirectory, relativePath);
|
|
223
|
-
const projectRoot = process.cwd();
|
|
224
|
-
const jiti = getJiti(projectRoot);
|
|
225
|
-
const module = await jiti.import(absolutePath);
|
|
226
|
-
return module.default || module;
|
|
328
|
+
const srcPages = join(process.cwd(), "src/pages");
|
|
329
|
+
return existsSync(srcPages) ? srcPages : join(process.cwd(), "pages");
|
|
227
330
|
}
|
|
228
331
|
function extractRoutes(pageKeys, localeSegment) {
|
|
229
332
|
const routes = [];
|
|
@@ -232,10 +335,8 @@ function extractRoutes(pageKeys, localeSegment) {
|
|
|
232
335
|
let pathname = key.replace(/^\.\//, "/").replace(/\.(tsx?|jsx?)$/, "").replace(/\/index$/, "/");
|
|
233
336
|
if (pathname === "") pathname = "/";
|
|
234
337
|
if (localeSegment) {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
""
|
|
238
|
-
);
|
|
338
|
+
const escapedSegment = localeSegment.replace(/[[\]]/g, "\\$&");
|
|
339
|
+
pathname = pathname.replace(new RegExp(`^/${escapedSegment}`), "");
|
|
239
340
|
}
|
|
240
341
|
if (/(?:^|\/)(src|pages)(?:\/|$)/.test(pathname)) continue;
|
|
241
342
|
if (!pathname || pathname === "") {
|
|
@@ -243,160 +344,57 @@ function extractRoutes(pageKeys, localeSegment) {
|
|
|
243
344
|
} else if (!pathname.startsWith("/")) {
|
|
244
345
|
pathname = "/" + pathname;
|
|
245
346
|
}
|
|
246
|
-
const dynamicSegments = pathname.match(/\[([^\]]+)\]/g)?.map((s) => s.slice(1, -1))
|
|
247
|
-
routes.push({
|
|
248
|
-
pathname,
|
|
249
|
-
dynamicSegments,
|
|
250
|
-
key
|
|
251
|
-
});
|
|
347
|
+
const dynamicSegments = pathname.match(/\[([^\]]+)\]/g)?.map((s) => s.slice(1, -1)) ?? [];
|
|
348
|
+
routes.push({ pathname, dynamicSegments, fileKey: key });
|
|
252
349
|
}
|
|
253
350
|
return routes;
|
|
254
351
|
}
|
|
255
|
-
async function getAllPaths(routes, pagesDirectory, debug = false) {
|
|
256
|
-
const allPaths = ["/"];
|
|
257
|
-
const seenPaths = /* @__PURE__ */ new Set(["/"]);
|
|
258
|
-
for (const route of routes) {
|
|
259
|
-
if (route.dynamicSegments.length === 0) {
|
|
260
|
-
if (route.pathname !== "/" && !seenPaths.has(route.pathname)) {
|
|
261
|
-
allPaths.push(route.pathname);
|
|
262
|
-
seenPaths.add(route.pathname);
|
|
263
|
-
}
|
|
264
|
-
} else {
|
|
265
|
-
let getParams = null;
|
|
266
|
-
try {
|
|
267
|
-
if (debug) {
|
|
268
|
-
console.log(`[next-sitemap] ${route.pathname}: importing ${route.key}`);
|
|
269
|
-
}
|
|
270
|
-
const module = await importPage(pagesDirectory, route.key);
|
|
271
|
-
const getStaticPaths = module.getStaticPaths;
|
|
272
|
-
if (getStaticPaths) {
|
|
273
|
-
getParams = async () => {
|
|
274
|
-
const result = await getStaticPaths();
|
|
275
|
-
return result.paths.map((p) => p.params);
|
|
276
|
-
};
|
|
277
|
-
} else if (module.generateStaticParams) {
|
|
278
|
-
getParams = module.generateStaticParams;
|
|
279
|
-
}
|
|
280
|
-
} catch (error) {
|
|
281
|
-
if (debug) {
|
|
282
|
-
console.warn(`[next-sitemap] ${route.pathname}: import failed:`, error);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
if (getParams) {
|
|
286
|
-
try {
|
|
287
|
-
const params = await getParams();
|
|
288
|
-
if (debug) {
|
|
289
|
-
console.log(`[next-sitemap] ${route.pathname}: getStaticPaths returned ${params.length} params`);
|
|
290
|
-
}
|
|
291
|
-
for (const param of params) {
|
|
292
|
-
let dynamicPath = route.pathname;
|
|
293
|
-
for (const segment of route.dynamicSegments) {
|
|
294
|
-
const value = param[segment];
|
|
295
|
-
if (value === void 0) {
|
|
296
|
-
if (debug) {
|
|
297
|
-
console.warn(`[next-sitemap] ${route.pathname}: missing param "${segment}" in`, param);
|
|
298
|
-
}
|
|
299
|
-
continue;
|
|
300
|
-
}
|
|
301
|
-
dynamicPath = dynamicPath.replace(`[${segment}]`, value);
|
|
302
|
-
}
|
|
303
|
-
if (!seenPaths.has(dynamicPath)) {
|
|
304
|
-
allPaths.push(dynamicPath);
|
|
305
|
-
seenPaths.add(dynamicPath);
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
} catch (error) {
|
|
309
|
-
console.error(`[next-sitemap] Error calling getStaticPaths for ${route.pathname}:`, error);
|
|
310
|
-
}
|
|
311
|
-
} else {
|
|
312
|
-
if (debug) {
|
|
313
|
-
console.warn(
|
|
314
|
-
`[next-sitemap] Skipping dynamic route ${route.pathname}: no getStaticPaths exported. Use additionalSitemaps for routes that fetch data at runtime.`
|
|
315
|
-
);
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
return allPaths;
|
|
321
|
-
}
|
|
322
|
-
function pathsToEntries(paths, config) {
|
|
323
|
-
const { baseUrl, locales = [], defaultLocale, exclude, priority, changeFreq } = config;
|
|
324
|
-
const filteredPaths = paths.filter((pathname) => !shouldExclude(pathname, exclude));
|
|
325
|
-
return filteredPaths.map((pathname) => {
|
|
326
|
-
const entry = {
|
|
327
|
-
url: buildUrl(baseUrl, pathname, defaultLocale, defaultLocale),
|
|
328
|
-
lastModified: /* @__PURE__ */ new Date(),
|
|
329
|
-
changeFrequency: getChangeFreq(pathname, changeFreq),
|
|
330
|
-
priority: getPriority(pathname, priority)
|
|
331
|
-
};
|
|
332
|
-
if (locales.length > 0) {
|
|
333
|
-
entry.alternates = {
|
|
334
|
-
languages: Object.fromEntries(
|
|
335
|
-
locales.map((locale) => [
|
|
336
|
-
locale,
|
|
337
|
-
buildUrl(baseUrl, pathname, locale, defaultLocale)
|
|
338
|
-
])
|
|
339
|
-
)
|
|
340
|
-
};
|
|
341
|
-
}
|
|
342
|
-
return entry;
|
|
343
|
-
});
|
|
344
|
-
}
|
|
345
352
|
function createSitemapIndexApiHandler(options) {
|
|
346
353
|
const { urlsPerSitemap = 5e3, additionalSitemaps, exclude, debug = false } = options;
|
|
347
354
|
const localeSegment = options.localeSegment ?? "";
|
|
348
|
-
const pagesDir = resolvePagesDirectory(options);
|
|
349
|
-
const pageKeys =
|
|
355
|
+
const pagesDir = resolvePagesDirectory(options.pagesDirectory);
|
|
356
|
+
const pageKeys = findPageFiles(pagesDir);
|
|
350
357
|
const routes = extractRoutes(pageKeys, localeSegment);
|
|
351
|
-
if (debug) {
|
|
352
|
-
console.log(`[next-sitemap] Found ${routes.length} routes:`);
|
|
353
|
-
routes.forEach((r) => {
|
|
354
|
-
const isDynamic = r.dynamicSegments.length > 0;
|
|
355
|
-
const segments = isDynamic ? ` [${r.dynamicSegments.join(", ")}]` : "";
|
|
356
|
-
console.log(` ${r.pathname}${segments}${isDynamic ? " (dynamic)" : ""}`);
|
|
357
|
-
});
|
|
358
|
-
}
|
|
359
358
|
return async function handler(_req, res) {
|
|
360
|
-
|
|
361
|
-
|
|
359
|
+
if (debug) {
|
|
360
|
+
console.log(`[next-sitemap] Found ${routes.length} routes`);
|
|
361
|
+
}
|
|
362
|
+
const allPaths = await generateAllPaths(routes, pagesDir, debug);
|
|
363
|
+
const filteredPaths = allPaths.filter((p) => !shouldExclude(p, exclude));
|
|
362
364
|
const sitemapCount = Math.max(1, Math.ceil(filteredPaths.length / urlsPerSitemap));
|
|
363
|
-
const xml = generateSitemapIndexXml(options.baseUrl, sitemapCount, {
|
|
364
|
-
additionalSitemaps
|
|
365
|
-
});
|
|
366
365
|
res.setHeader("Content-Type", "application/xml");
|
|
367
|
-
res.status(200).send(
|
|
366
|
+
res.status(200).send(
|
|
367
|
+
generateSitemapIndexXml(options.baseUrl, sitemapCount, { additionalSitemaps })
|
|
368
|
+
);
|
|
368
369
|
};
|
|
369
370
|
}
|
|
370
371
|
function createSitemapApiHandler(options) {
|
|
371
372
|
const { urlsPerSitemap = 5e3, exclude, debug = false } = options;
|
|
372
373
|
const localeSegment = options.localeSegment ?? "";
|
|
373
|
-
const pagesDir = resolvePagesDirectory(options);
|
|
374
|
-
const pageKeys =
|
|
374
|
+
const pagesDir = resolvePagesDirectory(options.pagesDirectory);
|
|
375
|
+
const pageKeys = findPageFiles(pagesDir);
|
|
375
376
|
const routes = extractRoutes(pageKeys, localeSegment);
|
|
376
377
|
const getFilteredPaths = async () => {
|
|
377
|
-
const allPaths = await
|
|
378
|
-
return allPaths.filter((
|
|
378
|
+
const allPaths = await generateAllPaths(routes, pagesDir, debug);
|
|
379
|
+
return allPaths.filter((p) => !shouldExclude(p, exclude));
|
|
379
380
|
};
|
|
380
381
|
return async function handler(req, res) {
|
|
381
382
|
const { id } = req.query;
|
|
382
383
|
const sitemapId = parseInt(Array.isArray(id) ? id[0] : id || "0", 10);
|
|
383
384
|
const filteredPaths = await getFilteredPaths();
|
|
384
|
-
const
|
|
385
|
-
const end = start + urlsPerSitemap;
|
|
386
|
-
const paths = filteredPaths.slice(start, end);
|
|
385
|
+
const paths = filteredPaths.slice(sitemapId * urlsPerSitemap, (sitemapId + 1) * urlsPerSitemap);
|
|
387
386
|
const entries = pathsToEntries(paths, { ...options, exclude: void 0 });
|
|
388
|
-
const xml = generateSitemapXml(entries);
|
|
389
387
|
res.setHeader("Content-Type", "application/xml");
|
|
390
|
-
res.status(200).send(
|
|
388
|
+
res.status(200).send(generateSitemapXml(entries));
|
|
391
389
|
};
|
|
392
390
|
}
|
|
393
391
|
async function getSitemapStaticPaths(options) {
|
|
394
392
|
const { urlsPerSitemap = 5e3, exclude, debug = false } = options;
|
|
395
393
|
const localeSegment = options.localeSegment ?? "";
|
|
396
|
-
const pagesDir = resolvePagesDirectory(options);
|
|
397
|
-
const pageKeys =
|
|
394
|
+
const pagesDir = resolvePagesDirectory(options.pagesDirectory);
|
|
395
|
+
const pageKeys = findPageFiles(pagesDir);
|
|
398
396
|
const routes = extractRoutes(pageKeys, localeSegment);
|
|
399
|
-
const allPaths = await
|
|
397
|
+
const allPaths = await generateAllPaths(routes, pagesDir, debug);
|
|
400
398
|
const filteredPaths = allPaths.filter((pathname) => !shouldExclude(pathname, exclude));
|
|
401
399
|
const sitemapCount = Math.max(1, Math.ceil(filteredPaths.length / urlsPerSitemap));
|
|
402
400
|
return {
|
|
@@ -408,9 +406,8 @@ async function getSitemapStaticPaths(options) {
|
|
|
408
406
|
}
|
|
409
407
|
function createRobotsApiHandler(config) {
|
|
410
408
|
return function handler(_req, res) {
|
|
411
|
-
const robotsTxt = generateRobotsTxt(config);
|
|
412
409
|
res.setHeader("Content-Type", "text/plain");
|
|
413
|
-
res.status(200).send(
|
|
410
|
+
res.status(200).send(generateRobotsTxt(config));
|
|
414
411
|
};
|
|
415
412
|
}
|
|
416
413
|
|
package/dist/worker.cjs
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var fs = require('fs');
|
|
4
|
+
var module$1 = require('module');
|
|
5
|
+
var path = require('path');
|
|
6
|
+
var jiti = require('jiti');
|
|
7
|
+
require('child_process');
|
|
8
|
+
var url = require('url');
|
|
9
|
+
|
|
10
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
11
|
+
// src/worker.ts
|
|
12
|
+
|
|
13
|
+
// ../../node_modules/.pnpm/strip-json-comments@5.0.3/node_modules/strip-json-comments/index.js
|
|
14
|
+
var singleComment = /* @__PURE__ */ Symbol("singleComment");
|
|
15
|
+
var multiComment = /* @__PURE__ */ Symbol("multiComment");
|
|
16
|
+
var stripWithoutWhitespace = () => "";
|
|
17
|
+
var stripWithWhitespace = (string, start, end) => string.slice(start, end).replace(/[^ \t\r\n]/g, " ");
|
|
18
|
+
var isEscaped = (jsonString, quotePosition) => {
|
|
19
|
+
let index = quotePosition - 1;
|
|
20
|
+
let backslashCount = 0;
|
|
21
|
+
while (jsonString[index] === "\\") {
|
|
22
|
+
index -= 1;
|
|
23
|
+
backslashCount += 1;
|
|
24
|
+
}
|
|
25
|
+
return Boolean(backslashCount % 2);
|
|
26
|
+
};
|
|
27
|
+
function stripJsonComments(jsonString, { whitespace = true, trailingCommas = false } = {}) {
|
|
28
|
+
if (typeof jsonString !== "string") {
|
|
29
|
+
throw new TypeError(`Expected argument \`jsonString\` to be a \`string\`, got \`${typeof jsonString}\``);
|
|
30
|
+
}
|
|
31
|
+
const strip = whitespace ? stripWithWhitespace : stripWithoutWhitespace;
|
|
32
|
+
let isInsideString = false;
|
|
33
|
+
let isInsideComment = false;
|
|
34
|
+
let offset = 0;
|
|
35
|
+
let buffer = "";
|
|
36
|
+
let result = "";
|
|
37
|
+
let commaIndex = -1;
|
|
38
|
+
for (let index = 0; index < jsonString.length; index++) {
|
|
39
|
+
const currentCharacter = jsonString[index];
|
|
40
|
+
const nextCharacter = jsonString[index + 1];
|
|
41
|
+
if (!isInsideComment && currentCharacter === '"') {
|
|
42
|
+
const escaped = isEscaped(jsonString, index);
|
|
43
|
+
if (!escaped) {
|
|
44
|
+
isInsideString = !isInsideString;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (isInsideString) {
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
if (!isInsideComment && currentCharacter + nextCharacter === "//") {
|
|
51
|
+
buffer += jsonString.slice(offset, index);
|
|
52
|
+
offset = index;
|
|
53
|
+
isInsideComment = singleComment;
|
|
54
|
+
index++;
|
|
55
|
+
} else if (isInsideComment === singleComment && currentCharacter + nextCharacter === "\r\n") {
|
|
56
|
+
index++;
|
|
57
|
+
isInsideComment = false;
|
|
58
|
+
buffer += strip(jsonString, offset, index);
|
|
59
|
+
offset = index;
|
|
60
|
+
continue;
|
|
61
|
+
} else if (isInsideComment === singleComment && currentCharacter === "\n") {
|
|
62
|
+
isInsideComment = false;
|
|
63
|
+
buffer += strip(jsonString, offset, index);
|
|
64
|
+
offset = index;
|
|
65
|
+
} else if (!isInsideComment && currentCharacter + nextCharacter === "/*") {
|
|
66
|
+
buffer += jsonString.slice(offset, index);
|
|
67
|
+
offset = index;
|
|
68
|
+
isInsideComment = multiComment;
|
|
69
|
+
index++;
|
|
70
|
+
continue;
|
|
71
|
+
} else if (isInsideComment === multiComment && currentCharacter + nextCharacter === "*/") {
|
|
72
|
+
index++;
|
|
73
|
+
isInsideComment = false;
|
|
74
|
+
buffer += strip(jsonString, offset, index + 1);
|
|
75
|
+
offset = index + 1;
|
|
76
|
+
continue;
|
|
77
|
+
} else if (trailingCommas && !isInsideComment) {
|
|
78
|
+
if (commaIndex !== -1) {
|
|
79
|
+
if (currentCharacter === "}" || currentCharacter === "]") {
|
|
80
|
+
buffer += jsonString.slice(offset, index);
|
|
81
|
+
result += strip(buffer, 0, 1) + buffer.slice(1);
|
|
82
|
+
buffer = "";
|
|
83
|
+
offset = index;
|
|
84
|
+
commaIndex = -1;
|
|
85
|
+
} else if (currentCharacter !== " " && currentCharacter !== " " && currentCharacter !== "\r" && currentCharacter !== "\n") {
|
|
86
|
+
buffer += jsonString.slice(offset, index);
|
|
87
|
+
offset = index;
|
|
88
|
+
commaIndex = -1;
|
|
89
|
+
}
|
|
90
|
+
} else if (currentCharacter === ",") {
|
|
91
|
+
result += buffer + jsonString.slice(offset, index);
|
|
92
|
+
buffer = "";
|
|
93
|
+
offset = index;
|
|
94
|
+
commaIndex = index;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const remaining = isInsideComment === singleComment ? strip(jsonString, offset) : jsonString.slice(offset);
|
|
99
|
+
return result + buffer + remaining;
|
|
100
|
+
}
|
|
101
|
+
var JS_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
102
|
+
".js",
|
|
103
|
+
".cjs",
|
|
104
|
+
".mjs",
|
|
105
|
+
".jsx",
|
|
106
|
+
".ts",
|
|
107
|
+
".cts",
|
|
108
|
+
".mts",
|
|
109
|
+
".tsx",
|
|
110
|
+
".json",
|
|
111
|
+
".node"
|
|
112
|
+
]);
|
|
113
|
+
var NO_STATIC_PARAMS = "NO_STATIC_PARAMS";
|
|
114
|
+
path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('worker.cjs', document.baseURI).href))));
|
|
115
|
+
process.env.NODE_ENV === "development";
|
|
116
|
+
|
|
117
|
+
// src/worker.ts
|
|
118
|
+
var joinPath = (...segments) => path.join(...segments);
|
|
119
|
+
installMockLoader();
|
|
120
|
+
main();
|
|
121
|
+
function installMockLoader() {
|
|
122
|
+
const ModuleInternal = module$1.Module;
|
|
123
|
+
const originalLoad = ModuleInternal._load;
|
|
124
|
+
ModuleInternal._load = function(request, parent, isMain) {
|
|
125
|
+
let resolvedPath;
|
|
126
|
+
try {
|
|
127
|
+
resolvedPath = ModuleInternal._resolveFilename(request, parent, isMain);
|
|
128
|
+
} catch {
|
|
129
|
+
return originalLoad(request, parent, isMain);
|
|
130
|
+
}
|
|
131
|
+
const ext = path.extname(resolvedPath).toLowerCase();
|
|
132
|
+
if (ext && !JS_EXTENSIONS.has(ext)) {
|
|
133
|
+
return {};
|
|
134
|
+
}
|
|
135
|
+
return originalLoad(request, parent, isMain);
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
function parseTsconfigAliases(projectRoot) {
|
|
139
|
+
const aliases = {};
|
|
140
|
+
try {
|
|
141
|
+
const tsconfigPath = path.join(projectRoot, "tsconfig.json");
|
|
142
|
+
if (!fs.existsSync(tsconfigPath)) return aliases;
|
|
143
|
+
const content = fs.readFileSync(tsconfigPath, "utf-8");
|
|
144
|
+
const withoutComments = stripJsonComments(content);
|
|
145
|
+
const cleaned = withoutComments.replace(/,(\s*[}\]])/g, "$1");
|
|
146
|
+
const tsconfig = JSON.parse(cleaned);
|
|
147
|
+
const baseUrl = tsconfig.compilerOptions?.baseUrl ?? ".";
|
|
148
|
+
const paths = tsconfig.compilerOptions?.paths ?? {};
|
|
149
|
+
if (baseUrl === ".") {
|
|
150
|
+
const srcPath = joinPath(projectRoot, "src");
|
|
151
|
+
if (fs.existsSync(srcPath)) {
|
|
152
|
+
aliases["src/"] = `${srcPath}/`;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
for (const [pattern, targets] of Object.entries(paths)) {
|
|
156
|
+
const target = targets[0];
|
|
157
|
+
if (!target) continue;
|
|
158
|
+
if (target.includes("@types") || target.includes("node_modules/@types")) {
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
if (!pattern.includes("*") && !pattern.startsWith("@") && !pattern.includes("/")) {
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
const aliasKey = pattern.replace(/\*$/, "");
|
|
165
|
+
const aliasValue = joinPath(projectRoot, baseUrl, target.replace(/\*$/, ""));
|
|
166
|
+
aliases[aliasKey] = aliasValue;
|
|
167
|
+
}
|
|
168
|
+
} catch {
|
|
169
|
+
}
|
|
170
|
+
return aliases;
|
|
171
|
+
}
|
|
172
|
+
function output(result, exitCode = 0) {
|
|
173
|
+
console.log(JSON.stringify(result));
|
|
174
|
+
process.exit(exitCode);
|
|
175
|
+
}
|
|
176
|
+
async function main() {
|
|
177
|
+
const [absolutePath, projectRoot] = process.argv.slice(2);
|
|
178
|
+
if (!absolutePath || !projectRoot) {
|
|
179
|
+
output({ success: false, error: "Usage: worker.cjs <absolutePath> <projectRoot>" }, 1);
|
|
180
|
+
}
|
|
181
|
+
try {
|
|
182
|
+
process.chdir(projectRoot);
|
|
183
|
+
const jiti$1 = jiti.createJiti((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('worker.cjs', document.baseURI).href)), {
|
|
184
|
+
moduleCache: false,
|
|
185
|
+
interopDefault: true,
|
|
186
|
+
jsx: true,
|
|
187
|
+
alias: parseTsconfigAliases(projectRoot),
|
|
188
|
+
tryNative: false
|
|
189
|
+
});
|
|
190
|
+
const module = jiti$1(absolutePath);
|
|
191
|
+
const generateStaticParams = module.generateStaticParams;
|
|
192
|
+
if (generateStaticParams) {
|
|
193
|
+
const params = await generateStaticParams();
|
|
194
|
+
output({ success: true, params: params ?? [] });
|
|
195
|
+
}
|
|
196
|
+
const getStaticPaths = module.getStaticPaths;
|
|
197
|
+
if (getStaticPaths) {
|
|
198
|
+
const result = await getStaticPaths();
|
|
199
|
+
const params = result.paths.map((p) => p.params);
|
|
200
|
+
output({ success: true, params });
|
|
201
|
+
}
|
|
202
|
+
output({ success: false, error: NO_STATIC_PARAMS });
|
|
203
|
+
} catch (err) {
|
|
204
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
205
|
+
output({ success: false, error: message }, 1);
|
|
206
|
+
}
|
|
207
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onruntime/next-sitemap",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Dynamic sitemap generation for Next.js with automatic route discovery",
|
|
5
5
|
"author": "onRuntime Studio <contact@onruntime.com>",
|
|
6
6
|
"repository": {
|
|
@@ -67,6 +67,6 @@
|
|
|
67
67
|
"build": "tsup",
|
|
68
68
|
"dev": "tsup --watch",
|
|
69
69
|
"type-check": "tsc --noEmit",
|
|
70
|
-
"test": "tsx --test tests/index.ts"
|
|
70
|
+
"test": "tsup && tsx --test tests/index.ts"
|
|
71
71
|
}
|
|
72
72
|
}
|