Skip to content

Commit 52f9840

Browse files
committed
Enhance sitemap generation with validation and error handling
Refactored sitemap.ts to add URL validation, improved error handling, and more robust date parsing for sitemap entries. Updated robots.txt comment to clarify sitemap generation by Next.js. These changes improve the reliability and accuracy of the generated sitemap.
1 parent b2c35ac commit 52f9840

2 files changed

Lines changed: 121 additions & 61 deletions

File tree

app/sitemap.ts

Lines changed: 120 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { statSync } from "fs";
2-
import { join } from "path";
1+
import { statSync } from "node:fs";
2+
import { join } from "node:path";
33
import type { MetadataRoute } from "next";
44

55
import { getRegistryBaseUrl, source } from "@/lib/source";
@@ -15,88 +15,148 @@ function getFileLastModified(filePath: string): Date {
1515
}
1616
}
1717

18-
const sitemap = (): MetadataRoute.Sitemap => {
18+
// feat: Validate URL format for sitemap
19+
function isValidUrl(url: string): boolean {
20+
try {
21+
new URL(url);
22+
return true;
23+
} catch {
24+
return false;
25+
}
26+
}
27+
28+
// feat: Generate sitemap data for Next.js App Router with enhanced error handling
29+
function generateSitemapData(): MetadataRoute.Sitemap {
1930
const baseUrl = getRegistryBaseUrl();
2031

32+
// feat: Validate base URL
33+
if (!isValidUrl(baseUrl)) {
34+
console.error("Invalid base URL for sitemap:", baseUrl);
35+
return [];
36+
}
37+
2138
const sitemap: MetadataRoute.Sitemap = [];
2239

23-
sitemap.push({
24-
url: `${baseUrl}/`,
25-
lastModified: new Date(),
26-
changeFrequency: "weekly",
27-
priority: 1,
28-
});
40+
// Add homepage with validation
41+
const homepageUrl = `${baseUrl}/`;
42+
if (isValidUrl(homepageUrl)) {
43+
sitemap.push({
44+
url: homepageUrl,
45+
lastModified: new Date(),
46+
changeFrequency: "weekly",
47+
priority: 1,
48+
});
49+
}
2950

51+
// Add documentation pages with enhanced error handling
3052
try {
3153
const pages = source.getPages();
32-
pages.forEach((page) => {
33-
// feat: Try to get actual file modification date
34-
let lastModified = new Date();
35-
if (page.data.lastModified) {
36-
lastModified = new Date(page.data.lastModified);
37-
} else {
38-
// Try to get file modification date from content directory
39-
try {
40-
const contentPath = join(
41-
process.cwd(),
42-
"content",
43-
"docs",
44-
`${page.url.replace("/docs/", "")}.mdx`,
45-
);
46-
lastModified = getFileLastModified(contentPath);
47-
} catch {
48-
// Fallback to current date
49-
lastModified = new Date();
54+
if (Array.isArray(pages)) {
55+
pages.forEach((page) => {
56+
if (!page?.url) return;
57+
58+
// feat: Try to get actual file modification date
59+
let lastModified = new Date();
60+
if (page.data?.lastModified) {
61+
try {
62+
lastModified = new Date(page.data.lastModified);
63+
// Validate date
64+
if (Number.isNaN(lastModified.getTime())) {
65+
lastModified = new Date();
66+
}
67+
} catch {
68+
lastModified = new Date();
69+
}
70+
} else {
71+
// Try to get file modification date from content directory
72+
try {
73+
const contentPath = join(
74+
process.cwd(),
75+
"content",
76+
"docs",
77+
`${page.url.replace("/docs/", "")}.mdx`,
78+
);
79+
lastModified = getFileLastModified(contentPath);
80+
} catch {
81+
// Fallback to current date
82+
lastModified = new Date();
83+
}
5084
}
51-
}
5285

53-
sitemap.push({
54-
url: `${baseUrl}${page.url}`,
55-
lastModified,
56-
changeFrequency: "monthly",
57-
priority: 0.9,
86+
const pageUrl = `${baseUrl}${page.url}`;
87+
if (isValidUrl(pageUrl)) {
88+
sitemap.push({
89+
url: pageUrl,
90+
lastModified,
91+
changeFrequency: "monthly",
92+
priority: 0.9,
93+
});
94+
}
5895
});
59-
});
96+
}
6097
} catch (error) {
61-
console.warn("Error generating sitemap", error);
98+
console.warn("Error generating sitemap for pages:", error);
6299
}
63100

64-
Object.keys(Index).forEach((componentName) => {
65-
if (componentName.endsWith("-demo")) return;
101+
// Add component registry JSON files with validation
102+
try {
103+
if (Index && typeof Index === "object") {
104+
Object.keys(Index).forEach((componentName) => {
105+
if (componentName.endsWith("-demo") || !componentName) return;
66106

67-
// feat: Component registry JSON file with proper modification date
68-
const componentPath = join(
69-
process.cwd(),
70-
"public",
71-
"r",
72-
`${componentName}.json`,
73-
);
74-
const lastModified = getFileLastModified(componentPath);
107+
// feat: Component registry JSON file with proper modification date
108+
const componentPath = join(
109+
process.cwd(),
110+
"public",
111+
"r",
112+
`${componentName}.json`,
113+
);
114+
const lastModified = getFileLastModified(componentPath);
75115

76-
sitemap.push({
77-
url: `${baseUrl}/r/${componentName}.json`,
78-
lastModified,
79-
changeFrequency: "monthly",
80-
priority: 0.6,
81-
});
82-
});
116+
const componentUrl = `${baseUrl}/r/${componentName}.json`;
117+
if (isValidUrl(componentUrl)) {
118+
sitemap.push({
119+
url: componentUrl,
120+
lastModified,
121+
changeFrequency: "monthly",
122+
priority: 0.6,
123+
});
124+
}
125+
});
126+
}
127+
} catch (error) {
128+
console.warn("Error generating sitemap for components:", error);
129+
}
83130

84-
sitemap.push(
131+
// Add API endpoints and other important pages with validation
132+
const additionalUrls = [
85133
{
86134
url: `${baseUrl}/api/search`,
87-
lastModified: new Date(),
88-
changeFrequency: "weekly",
135+
changeFrequency: "weekly" as const,
89136
priority: 0.7,
90137
},
91138
{
92139
url: `${baseUrl}/llms-full.txt`,
93-
lastModified: new Date(),
94-
changeFrequency: "weekly",
140+
changeFrequency: "weekly" as const,
95141
priority: 0.8,
96142
},
97-
);
143+
];
144+
145+
additionalUrls.forEach(({ url, changeFrequency, priority }) => {
146+
if (isValidUrl(url)) {
147+
sitemap.push({
148+
url,
149+
lastModified: new Date(),
150+
changeFrequency,
151+
priority,
152+
});
153+
}
154+
});
98155

99156
return sitemap;
100-
};
157+
}
101158

102-
export default sitemap;
159+
// feat: Export sitemap function for Next.js App Router
160+
export default function sitemap(): MetadataRoute.Sitemap {
161+
return generateSitemapData();
162+
}

public/robots.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,5 @@ Disallow: /llms.mdx/
1111
# Allow registry JSON files for component discovery
1212
Allow: /r/*.json
1313

14-
# Sitemap location
14+
# Sitemap location - Next.js automatically generates sitemap.xml
1515
Sitemap: https://shadix-ui.vercel.app/sitemap.xml

0 commit comments

Comments
 (0)