@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/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) {
|
|
@@ -106,17 +265,16 @@ ${allEntries}
|
|
|
106
265
|
}
|
|
107
266
|
|
|
108
267
|
// src/app/index.ts
|
|
109
|
-
var joinPath = (...segments) => path.join(...segments);
|
|
110
268
|
function findPageFiles(dir, baseDir = dir) {
|
|
111
269
|
const files = [];
|
|
112
270
|
try {
|
|
113
|
-
const entries =
|
|
271
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
114
272
|
for (const entry of entries) {
|
|
115
|
-
const fullPath =
|
|
273
|
+
const fullPath = join(dir, entry.name);
|
|
116
274
|
if (entry.isDirectory()) {
|
|
117
275
|
files.push(...findPageFiles(fullPath, baseDir));
|
|
118
276
|
} else if (/^page\.(tsx?|jsx?)$/.test(entry.name)) {
|
|
119
|
-
const relativePath = "./" +
|
|
277
|
+
const relativePath = "./" + relative(baseDir, fullPath).replace(/\\/g, "/");
|
|
120
278
|
files.push(relativePath);
|
|
121
279
|
}
|
|
122
280
|
}
|
|
@@ -124,83 +282,12 @@ function findPageFiles(dir, baseDir = dir) {
|
|
|
124
282
|
}
|
|
125
283
|
return files;
|
|
126
284
|
}
|
|
127
|
-
function
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
return srcApp;
|
|
131
|
-
}
|
|
132
|
-
return path.join(process.cwd(), "app");
|
|
133
|
-
}
|
|
134
|
-
function resolveAppDirectory(options) {
|
|
135
|
-
if (options.appDirectory) {
|
|
136
|
-
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);
|
|
137
288
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
function getPageKeys(options) {
|
|
141
|
-
return findPageFiles(resolveAppDirectory(options));
|
|
142
|
-
}
|
|
143
|
-
var jitiCache = /* @__PURE__ */ new Map();
|
|
144
|
-
function getTsconfigPaths(projectRoot, debug = false) {
|
|
145
|
-
const alias = {};
|
|
146
|
-
try {
|
|
147
|
-
const tsconfigPath = path.join(projectRoot, "tsconfig.json");
|
|
148
|
-
if (debug) {
|
|
149
|
-
console.log("[next-sitemap] Looking for tsconfig at:", tsconfigPath);
|
|
150
|
-
console.log("[next-sitemap] tsconfig exists:", fs.existsSync(tsconfigPath));
|
|
151
|
-
}
|
|
152
|
-
if (fs.existsSync(tsconfigPath)) {
|
|
153
|
-
const content = fs.readFileSync(tsconfigPath, "utf-8");
|
|
154
|
-
const withoutComments = stripJsonComments(content);
|
|
155
|
-
const cleaned = withoutComments.replace(/,(\s*[}\]])/g, "$1");
|
|
156
|
-
if (debug) {
|
|
157
|
-
console.log("[next-sitemap] Cleaned tsconfig (first 500 chars):", cleaned.slice(0, 500));
|
|
158
|
-
}
|
|
159
|
-
const tsconfig = JSON.parse(cleaned);
|
|
160
|
-
if (debug) {
|
|
161
|
-
console.log("[next-sitemap] Parsed tsconfig paths:", tsconfig.compilerOptions?.paths);
|
|
162
|
-
}
|
|
163
|
-
const baseUrl = tsconfig.compilerOptions?.baseUrl || ".";
|
|
164
|
-
const paths = tsconfig.compilerOptions?.paths || {};
|
|
165
|
-
for (const [key, values] of Object.entries(paths)) {
|
|
166
|
-
if (values.length > 0) {
|
|
167
|
-
const aliasKey = key.replace(/\*$/, "");
|
|
168
|
-
const aliasValue = joinPath(projectRoot, baseUrl, values[0].replace(/\*$/, ""));
|
|
169
|
-
alias[aliasKey] = aliasValue;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
} catch (error) {
|
|
174
|
-
if (debug) {
|
|
175
|
-
console.error("[next-sitemap] Error parsing tsconfig:", error);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
return alias;
|
|
179
|
-
}
|
|
180
|
-
function getJiti(projectRoot, debug = false) {
|
|
181
|
-
if (jitiCache.has(projectRoot)) {
|
|
182
|
-
return jitiCache.get(projectRoot);
|
|
183
|
-
}
|
|
184
|
-
const alias = getTsconfigPaths(projectRoot, debug);
|
|
185
|
-
if (debug) {
|
|
186
|
-
console.log("[next-sitemap] Final alias config:", JSON.stringify(alias));
|
|
187
|
-
}
|
|
188
|
-
const jiti = createJiti(import.meta.url, {
|
|
189
|
-
moduleCache: false,
|
|
190
|
-
interopDefault: true,
|
|
191
|
-
jsx: true,
|
|
192
|
-
alias
|
|
193
|
-
});
|
|
194
|
-
jitiCache.set(projectRoot, jiti);
|
|
195
|
-
return jiti;
|
|
196
|
-
}
|
|
197
|
-
async function importPage(appDirectory, key, debug = false) {
|
|
198
|
-
const relativePath = key.replace("./", "");
|
|
199
|
-
const absolutePath = path.join(appDirectory, relativePath);
|
|
200
|
-
const projectRoot = process.cwd();
|
|
201
|
-
const jiti = getJiti(projectRoot, debug);
|
|
202
|
-
const module = await jiti.import(absolutePath);
|
|
203
|
-
return module.default || module;
|
|
289
|
+
const srcApp = join(process.cwd(), "src/app");
|
|
290
|
+
return existsSync(srcApp) ? srcApp : join(process.cwd(), "app");
|
|
204
291
|
}
|
|
205
292
|
function extractRoutes(pageKeys, localeSegment) {
|
|
206
293
|
const routes = [];
|
|
@@ -208,163 +295,64 @@ function extractRoutes(pageKeys, localeSegment) {
|
|
|
208
295
|
if (key.includes("[...")) continue;
|
|
209
296
|
let pathname = key.replace("./", "/").replace(/\/page\.(tsx?|jsx?)$/, "");
|
|
210
297
|
if (localeSegment) {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
""
|
|
214
|
-
);
|
|
298
|
+
const escapedSegment = localeSegment.replace(/[[\]]/g, "\\$&");
|
|
299
|
+
pathname = pathname.replace(new RegExp(`^/${escapedSegment}`), "");
|
|
215
300
|
}
|
|
216
301
|
pathname = pathname.replace(/\/\([^)]+\)/g, "");
|
|
217
302
|
if (/(?:^|\/)(src|app)(?:\/|$)/.test(pathname)) continue;
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
} else if (!pathname.startsWith("/")) {
|
|
303
|
+
pathname = pathname || "/";
|
|
304
|
+
if (pathname !== "/" && !pathname.startsWith("/")) {
|
|
221
305
|
pathname = "/" + pathname;
|
|
222
306
|
}
|
|
223
|
-
const dynamicSegments = pathname.match(/\[([^\]]+)\]/g)?.map((s) => s.slice(1, -1))
|
|
224
|
-
routes.push({
|
|
225
|
-
pathname,
|
|
226
|
-
dynamicSegments,
|
|
227
|
-
key
|
|
228
|
-
});
|
|
307
|
+
const dynamicSegments = pathname.match(/\[([^\]]+)\]/g)?.map((s) => s.slice(1, -1)) ?? [];
|
|
308
|
+
routes.push({ pathname, dynamicSegments, fileKey: key });
|
|
229
309
|
}
|
|
230
310
|
return routes;
|
|
231
311
|
}
|
|
232
|
-
async function getAllPaths(routes, appDirectory, debug = false) {
|
|
233
|
-
const allPaths = ["/"];
|
|
234
|
-
const seenPaths = /* @__PURE__ */ new Set(["/"]);
|
|
235
|
-
for (const route of routes) {
|
|
236
|
-
if (route.dynamicSegments.length === 0) {
|
|
237
|
-
if (route.pathname !== "/" && !seenPaths.has(route.pathname)) {
|
|
238
|
-
allPaths.push(route.pathname);
|
|
239
|
-
seenPaths.add(route.pathname);
|
|
240
|
-
}
|
|
241
|
-
} else {
|
|
242
|
-
let getParams = null;
|
|
243
|
-
try {
|
|
244
|
-
if (debug) {
|
|
245
|
-
console.log(`[next-sitemap] ${route.pathname}: importing ${route.key}`);
|
|
246
|
-
}
|
|
247
|
-
const module = await importPage(appDirectory, route.key, debug);
|
|
248
|
-
getParams = module.generateStaticParams || null;
|
|
249
|
-
} catch (error) {
|
|
250
|
-
if (debug) {
|
|
251
|
-
console.warn(`[next-sitemap] ${route.pathname}: import failed:`, error);
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
if (getParams) {
|
|
255
|
-
try {
|
|
256
|
-
const params = await getParams();
|
|
257
|
-
if (debug) {
|
|
258
|
-
console.log(`[next-sitemap] ${route.pathname}: generateStaticParams returned ${params.length} params`);
|
|
259
|
-
}
|
|
260
|
-
for (const param of params) {
|
|
261
|
-
let dynamicPath = route.pathname;
|
|
262
|
-
for (const segment of route.dynamicSegments) {
|
|
263
|
-
const value = param[segment];
|
|
264
|
-
if (value === void 0) {
|
|
265
|
-
if (debug) {
|
|
266
|
-
console.warn(`[next-sitemap] ${route.pathname}: missing param "${segment}" in`, param);
|
|
267
|
-
}
|
|
268
|
-
continue;
|
|
269
|
-
}
|
|
270
|
-
dynamicPath = dynamicPath.replace(`[${segment}]`, value);
|
|
271
|
-
}
|
|
272
|
-
if (!seenPaths.has(dynamicPath)) {
|
|
273
|
-
allPaths.push(dynamicPath);
|
|
274
|
-
seenPaths.add(dynamicPath);
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
} catch (error) {
|
|
278
|
-
console.error(`[next-sitemap] Error calling generateStaticParams for ${route.pathname}:`, error);
|
|
279
|
-
}
|
|
280
|
-
} else {
|
|
281
|
-
if (debug) {
|
|
282
|
-
console.warn(
|
|
283
|
-
`[next-sitemap] Skipping dynamic route ${route.pathname}: no generateStaticParams exported. Use additionalSitemaps for routes that fetch data at runtime.`
|
|
284
|
-
);
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
return allPaths;
|
|
290
|
-
}
|
|
291
|
-
function pathsToEntries(paths, config) {
|
|
292
|
-
const { baseUrl, locales = [], defaultLocale, exclude, priority, changeFreq } = config;
|
|
293
|
-
const filteredPaths = paths.filter((pathname) => !shouldExclude(pathname, exclude));
|
|
294
|
-
return filteredPaths.map((pathname) => {
|
|
295
|
-
const entry = {
|
|
296
|
-
url: buildUrl(baseUrl, pathname, defaultLocale, defaultLocale),
|
|
297
|
-
lastModified: /* @__PURE__ */ new Date(),
|
|
298
|
-
changeFrequency: getChangeFreq(pathname, changeFreq),
|
|
299
|
-
priority: getPriority(pathname, priority)
|
|
300
|
-
};
|
|
301
|
-
if (locales.length > 0) {
|
|
302
|
-
entry.alternates = {
|
|
303
|
-
languages: Object.fromEntries(
|
|
304
|
-
locales.map((locale) => [
|
|
305
|
-
locale,
|
|
306
|
-
buildUrl(baseUrl, pathname, locale, defaultLocale)
|
|
307
|
-
])
|
|
308
|
-
)
|
|
309
|
-
};
|
|
310
|
-
}
|
|
311
|
-
return entry;
|
|
312
|
-
});
|
|
313
|
-
}
|
|
314
312
|
function createSitemapIndexHandler(options) {
|
|
315
313
|
const { urlsPerSitemap = 5e3, locales = [], defaultLocale, additionalSitemaps, exclude, debug = false } = options;
|
|
316
314
|
const localeSegment = options.localeSegment ?? (locales.length > 0 || defaultLocale ? "[locale]" : "");
|
|
317
|
-
const appDir = resolveAppDirectory(options);
|
|
318
|
-
const pageKeys =
|
|
315
|
+
const appDir = resolveAppDirectory(options.appDirectory);
|
|
316
|
+
const pageKeys = findPageFiles(appDir);
|
|
319
317
|
const routes = extractRoutes(pageKeys, localeSegment);
|
|
320
318
|
return {
|
|
321
319
|
GET: async () => {
|
|
322
320
|
if (debug) {
|
|
323
|
-
console.log(`[next-sitemap] Found ${routes.length} routes
|
|
324
|
-
routes.forEach((r) => {
|
|
325
|
-
const isDynamic = r.dynamicSegments.length > 0;
|
|
326
|
-
const segments = isDynamic ? ` [${r.dynamicSegments.join(", ")}]` : "";
|
|
327
|
-
console.log(` ${r.pathname}${segments}${isDynamic ? " (dynamic)" : ""}`);
|
|
328
|
-
});
|
|
321
|
+
console.log(`[next-sitemap] Found ${routes.length} routes`);
|
|
329
322
|
}
|
|
330
|
-
const allPaths = await
|
|
331
|
-
const filteredPaths = allPaths.filter((
|
|
323
|
+
const allPaths = await generateAllPaths(routes, appDir, debug);
|
|
324
|
+
const filteredPaths = allPaths.filter((p) => !shouldExclude(p, exclude));
|
|
332
325
|
const sitemapCount = Math.max(1, Math.ceil(filteredPaths.length / urlsPerSitemap));
|
|
333
|
-
|
|
334
|
-
additionalSitemaps
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
headers: { "Content-Type": "application/xml" }
|
|
338
|
-
});
|
|
326
|
+
return new Response(
|
|
327
|
+
generateSitemapIndexXml(options.baseUrl, sitemapCount, { additionalSitemaps }),
|
|
328
|
+
{ headers: { "Content-Type": "application/xml" } }
|
|
329
|
+
);
|
|
339
330
|
}
|
|
340
331
|
};
|
|
341
332
|
}
|
|
342
333
|
function createSitemapHandler(options) {
|
|
343
334
|
const { urlsPerSitemap = 5e3, locales = [], defaultLocale, exclude, debug = false } = options;
|
|
344
335
|
const localeSegment = options.localeSegment ?? (locales.length > 0 || defaultLocale ? "[locale]" : "");
|
|
345
|
-
const appDir = resolveAppDirectory(options);
|
|
346
|
-
const pageKeys =
|
|
336
|
+
const appDir = resolveAppDirectory(options.appDirectory);
|
|
337
|
+
const pageKeys = findPageFiles(appDir);
|
|
347
338
|
const routes = extractRoutes(pageKeys, localeSegment);
|
|
348
339
|
const getFilteredPaths = async () => {
|
|
349
|
-
const allPaths = await
|
|
350
|
-
return allPaths.filter((
|
|
340
|
+
const allPaths = await generateAllPaths(routes, appDir, debug);
|
|
341
|
+
return allPaths.filter((p) => !shouldExclude(p, exclude));
|
|
351
342
|
};
|
|
352
343
|
return {
|
|
353
344
|
generateStaticParams: async () => {
|
|
354
345
|
const filteredPaths = await getFilteredPaths();
|
|
355
|
-
const
|
|
356
|
-
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) }));
|
|
357
348
|
},
|
|
358
349
|
GET: async (_request, { params }) => {
|
|
359
350
|
const { id } = await params;
|
|
360
351
|
const sitemapId = parseInt(id, 10);
|
|
361
352
|
const filteredPaths = await getFilteredPaths();
|
|
362
|
-
const
|
|
363
|
-
const end = start + urlsPerSitemap;
|
|
364
|
-
const paths = filteredPaths.slice(start, end);
|
|
353
|
+
const paths = filteredPaths.slice(sitemapId * urlsPerSitemap, (sitemapId + 1) * urlsPerSitemap);
|
|
365
354
|
const entries = pathsToEntries(paths, { ...options, exclude: void 0 });
|
|
366
|
-
|
|
367
|
-
return new Response(xml, {
|
|
355
|
+
return new Response(generateSitemapXml(entries), {
|
|
368
356
|
headers: { "Content-Type": "application/xml" }
|
|
369
357
|
});
|
|
370
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;
|