Skip to content

Commit f9f1c4d

Browse files
authored
feat: add sitemap generation script and update prebuild script
1 parent de692ff commit f9f1c4d

File tree

3 files changed

+353
-1
lines changed

3 files changed

+353
-1
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"type": "module",
66
"scripts": {
77
"dev": "pnpm prebuild && vite",
8-
"prebuild": "tsx scripts/generate-rss.ts",
8+
"prebuild": "tsx scripts/generate-rss.ts && tsx scripts/generate-sitemap.ts",
99
"build": "tsc -b && vite build",
1010
"lint": "oxlint .",
1111
"fmt": "oxfmt .",

public/sitemap.xml

Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
3+
<url>
4+
<loc>https://blog.mahata.org</loc>
5+
<changefreq>weekly</changefreq>
6+
<priority>1.0</priority>
7+
</url>
8+
<url>
9+
<loc>https://blog.mahata.org/posts/2026-01-29-blog-in-2026</loc>
10+
<lastmod>2026-01-29</lastmod>
11+
<changefreq>monthly</changefreq>
12+
<priority>0.7</priority>
13+
</url>
14+
<url>
15+
<loc>https://blog.mahata.org/posts/2025-12-26-retrospective</loc>
16+
<lastmod>2025-12-26</lastmod>
17+
<changefreq>monthly</changefreq>
18+
<priority>0.7</priority>
19+
</url>
20+
<url>
21+
<loc>https://blog.mahata.org/posts/2025-02-08-tidy-first</loc>
22+
<lastmod>2025-02-08</lastmod>
23+
<changefreq>monthly</changefreq>
24+
<priority>0.7</priority>
25+
</url>
26+
<url>
27+
<loc>https://blog.mahata.org/posts/2025-02-07-mini-habits</loc>
28+
<lastmod>2025-02-07</lastmod>
29+
<changefreq>monthly</changefreq>
30+
<priority>0.7</priority>
31+
</url>
32+
<url>
33+
<loc>https://blog.mahata.org/posts/2025-01-29-take-notes</loc>
34+
<lastmod>2025-01-29</lastmod>
35+
<changefreq>monthly</changefreq>
36+
<priority>0.7</priority>
37+
</url>
38+
<url>
39+
<loc>https://blog.mahata.org/posts/2025-01-21-retrospective</loc>
40+
<lastmod>2025-01-21</lastmod>
41+
<changefreq>monthly</changefreq>
42+
<priority>0.7</priority>
43+
</url>
44+
<url>
45+
<loc>https://blog.mahata.org/posts/2024-10-30-hiroutohananika</loc>
46+
<lastmod>2024-10-30</lastmod>
47+
<changefreq>monthly</changefreq>
48+
<priority>0.7</priority>
49+
</url>
50+
<url>
51+
<loc>https://blog.mahata.org/posts/2024-01-05-giving-up-software-engineer-at-google</loc>
52+
<lastmod>2024-01-05</lastmod>
53+
<changefreq>monthly</changefreq>
54+
<priority>0.7</priority>
55+
</url>
56+
<url>
57+
<loc>https://blog.mahata.org/posts/2024-01-04-sad-new-year</loc>
58+
<lastmod>2024-01-04</lastmod>
59+
<changefreq>monthly</changefreq>
60+
<priority>0.7</priority>
61+
</url>
62+
<url>
63+
<loc>https://blog.mahata.org/posts/2023-12-22-retrospective</loc>
64+
<lastmod>2023-12-22</lastmod>
65+
<changefreq>monthly</changefreq>
66+
<priority>0.7</priority>
67+
</url>
68+
<url>
69+
<loc>https://blog.mahata.org/posts/2023-12-13-yet-another-blog-engine</loc>
70+
<lastmod>2023-12-13</lastmod>
71+
<changefreq>monthly</changefreq>
72+
<priority>0.7</priority>
73+
</url>
74+
<url>
75+
<loc>https://blog.mahata.org/posts/2023-06-09-chatgpt-again</loc>
76+
<lastmod>2023-06-09</lastmod>
77+
<changefreq>monthly</changefreq>
78+
<priority>0.7</priority>
79+
</url>
80+
<url>
81+
<loc>https://blog.mahata.org/posts/2023-05-12-kensui</loc>
82+
<lastmod>2023-05-12</lastmod>
83+
<changefreq>monthly</changefreq>
84+
<priority>0.7</priority>
85+
</url>
86+
<url>
87+
<loc>https://blog.mahata.org/posts/2023-04-25-japanese-style</loc>
88+
<lastmod>2023-04-25</lastmod>
89+
<changefreq>monthly</changefreq>
90+
<priority>0.7</priority>
91+
</url>
92+
<url>
93+
<loc>https://blog.mahata.org/posts/2023-04-20-better-programmer</loc>
94+
<lastmod>2023-04-20</lastmod>
95+
<changefreq>monthly</changefreq>
96+
<priority>0.7</priority>
97+
</url>
98+
<url>
99+
<loc>https://blog.mahata.org/posts/2023-04-10-react-hands-on-learning-2nd</loc>
100+
<lastmod>2023-04-10</lastmod>
101+
<changefreq>monthly</changefreq>
102+
<priority>0.7</priority>
103+
</url>
104+
<url>
105+
<loc>https://blog.mahata.org/posts/2023-04-08-bz-fan-history</loc>
106+
<lastmod>2023-04-08</lastmod>
107+
<changefreq>monthly</changefreq>
108+
<priority>0.7</priority>
109+
</url>
110+
<url>
111+
<loc>https://blog.mahata.org/posts/2023-03-14-company-blogs-where-i-contributed-articles</loc>
112+
<lastmod>2023-03-14</lastmod>
113+
<changefreq>monthly</changefreq>
114+
<priority>0.7</priority>
115+
</url>
116+
<url>
117+
<loc>https://blog.mahata.org/posts/2023-03-13-zenn</loc>
118+
<lastmod>2023-03-13</lastmod>
119+
<changefreq>monthly</changefreq>
120+
<priority>0.7</priority>
121+
</url>
122+
<url>
123+
<loc>https://blog.mahata.org/posts/2023-02-16-youthful-days</loc>
124+
<lastmod>2023-02-16</lastmod>
125+
<changefreq>monthly</changefreq>
126+
<priority>0.7</priority>
127+
</url>
128+
<url>
129+
<loc>https://blog.mahata.org/posts/2023-02-14-software-engineering-at-google-chapter3-knowledge-sharing</loc>
130+
<lastmod>2023-02-13</lastmod>
131+
<changefreq>monthly</changefreq>
132+
<priority>0.7</priority>
133+
</url>
134+
<url>
135+
<loc>https://blog.mahata.org/posts/2023-02-10-software-engineering-at-google-chapter2-how-to-work-well-on-teams</loc>
136+
<lastmod>2023-02-10</lastmod>
137+
<changefreq>monthly</changefreq>
138+
<priority>0.7</priority>
139+
</url>
140+
<url>
141+
<loc>https://blog.mahata.org/posts/2023-02-06-software-engineering-at-google-chapter1-what-is-software-engineering</loc>
142+
<lastmod>2023-02-06</lastmod>
143+
<changefreq>monthly</changefreq>
144+
<priority>0.7</priority>
145+
</url>
146+
<url>
147+
<loc>https://blog.mahata.org/posts/2023-01-27-dont-use-libraries-hosted-elsewhere</loc>
148+
<lastmod>2023-01-27</lastmod>
149+
<changefreq>monthly</changefreq>
150+
<priority>0.7</priority>
151+
</url>
152+
<url>
153+
<loc>https://blog.mahata.org/posts/2023-01-24-dont-lead-by-example</loc>
154+
<lastmod>2023-01-24</lastmod>
155+
<changefreq>monthly</changefreq>
156+
<priority>0.7</priority>
157+
</url>
158+
<url>
159+
<loc>https://blog.mahata.org/posts/2023-01-23-programming-typescript-chapter5-emulate-final</loc>
160+
<lastmod>2023-01-23</lastmod>
161+
<changefreq>monthly</changefreq>
162+
<priority>0.7</priority>
163+
</url>
164+
<url>
165+
<loc>https://blog.mahata.org/posts/2023-01-20-back-to-rss-reader</loc>
166+
<lastmod>2023-01-20</lastmod>
167+
<changefreq>monthly</changefreq>
168+
<priority>0.7</priority>
169+
</url>
170+
<url>
171+
<loc>https://blog.mahata.org/posts/2023-01-19-marktext-to-intellij</loc>
172+
<lastmod>2023-01-19</lastmod>
173+
<changefreq>monthly</changefreq>
174+
<priority>0.7</priority>
175+
</url>
176+
<url>
177+
<loc>https://blog.mahata.org/posts/2023-01-18-github-actions-for-github-stars-reminder</loc>
178+
<lastmod>2023-01-18</lastmod>
179+
<changefreq>monthly</changefreq>
180+
<priority>0.7</priority>
181+
</url>
182+
<url>
183+
<loc>https://blog.mahata.org/posts/2023-01-17-github-actions-as-a-cron-server</loc>
184+
<lastmod>2023-01-17</lastmod>
185+
<changefreq>monthly</changefreq>
186+
<priority>0.7</priority>
187+
</url>
188+
<url>
189+
<loc>https://blog.mahata.org/posts/2023-01-16-programming-typescript-chapter4-is-method</loc>
190+
<lastmod>2023-01-16</lastmod>
191+
<changefreq>monthly</changefreq>
192+
<priority>0.7</priority>
193+
</url>
194+
<url>
195+
<loc>https://blog.mahata.org/posts/2023-01-13-programming-typescript-chapter4-generator-iterator</loc>
196+
<lastmod>2023-01-13</lastmod>
197+
<changefreq>monthly</changefreq>
198+
<priority>0.7</priority>
199+
</url>
200+
<url>
201+
<loc>https://blog.mahata.org/posts/2023-01-11-sadservers2-saskatoon</loc>
202+
<lastmod>2023-01-11</lastmod>
203+
<changefreq>monthly</changefreq>
204+
<priority>0.7</priority>
205+
</url>
206+
<url>
207+
<loc>https://blog.mahata.org/posts/2023-01-10-sadservers1-saint-john</loc>
208+
<lastmod>2023-01-10</lastmod>
209+
<changefreq>monthly</changefreq>
210+
<priority>0.7</priority>
211+
</url>
212+
<url>
213+
<loc>https://blog.mahata.org/posts/2023-01-05-read-my-own-blog</loc>
214+
<lastmod>2023-01-05</lastmod>
215+
<changefreq>monthly</changefreq>
216+
<priority>0.7</priority>
217+
</url>
218+
<url>
219+
<loc>https://blog.mahata.org/posts/2023-01-04-no-alcohol-life</loc>
220+
<lastmod>2023-01-04</lastmod>
221+
<changefreq>monthly</changefreq>
222+
<priority>0.7</priority>
223+
</url>
224+
<url>
225+
<loc>https://blog.mahata.org/posts/2023-01-03-input-for-output</loc>
226+
<lastmod>2023-01-03</lastmod>
227+
<changefreq>monthly</changefreq>
228+
<priority>0.7</priority>
229+
</url>
230+
<url>
231+
<loc>https://blog.mahata.org/posts/2022-12-23-retrospective</loc>
232+
<lastmod>2022-12-23</lastmod>
233+
<changefreq>monthly</changefreq>
234+
<priority>0.7</priority>
235+
</url>
236+
<url>
237+
<loc>https://blog.mahata.org/posts/2022-12-01-startup-like-big-tech</loc>
238+
<lastmod>2022-12-01</lastmod>
239+
<changefreq>monthly</changefreq>
240+
<priority>0.7</priority>
241+
</url>
242+
<url>
243+
<loc>https://blog.mahata.org/posts/2022-11-30-yet-another-blog-migration</loc>
244+
<lastmod>2022-11-30</lastmod>
245+
<changefreq>monthly</changefreq>
246+
<priority>0.7</priority>
247+
</url>
248+
</urlset>

scripts/generate-sitemap.ts

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import { readdir, readFile, writeFile } from "fs/promises";
2+
import { join } from "path";
3+
import {
4+
extractFrontMatter,
5+
isValidFrontMatter,
6+
} from "../src/utils/frontMatter.js";
7+
8+
interface SitemapEntry {
9+
loc: string;
10+
lastmod?: string;
11+
changefreq: string;
12+
priority: number;
13+
}
14+
15+
const SITE_URL = process.env.SITE_URL || "https://blog.mahata.org";
16+
const POSTS_DIR = join(process.cwd(), "posts");
17+
const OUTPUT_DIR = join(process.cwd(), "public");
18+
const OUTPUT_FILE = join(OUTPUT_DIR, "sitemap.xml");
19+
20+
async function extractPostEntries(): Promise<SitemapEntry[]> {
21+
const files = await readdir(POSTS_DIR);
22+
const mdFiles = files.filter((f) => f.endsWith(".md"));
23+
const entries: SitemapEntry[] = [];
24+
25+
for (const filename of mdFiles) {
26+
try {
27+
const filePath = join(POSTS_DIR, filename);
28+
const content = await readFile(filePath, "utf-8");
29+
30+
// Extract and validate front matter
31+
const frontMatter = extractFrontMatter(content);
32+
if (!isValidFrontMatter(frontMatter)) continue;
33+
34+
// Extract slug from filename (e.g., 'my-post.md' -> 'my-post')
35+
const slug = filename.replace(".md", "");
36+
if (!slug) continue;
37+
38+
entries.push({
39+
loc: `${SITE_URL}/posts/${slug}`,
40+
lastmod: frontMatter.date,
41+
changefreq: "monthly",
42+
priority: 0.7,
43+
});
44+
} catch (error) {
45+
console.error(`Failed to parse post at ${filename}:`, error);
46+
}
47+
}
48+
49+
// Sort by date, newest first
50+
entries.sort((a, b) => {
51+
if (!a.lastmod || !b.lastmod) return 0;
52+
return new Date(b.lastmod).getTime() - new Date(a.lastmod).getTime();
53+
});
54+
55+
return entries;
56+
}
57+
58+
function escapeXml(str: string): string {
59+
return str
60+
.replace(/&/g, "&amp;")
61+
.replace(/</g, "&lt;")
62+
.replace(/>/g, "&gt;")
63+
.replace(/"/g, "&quot;")
64+
.replace(/'/g, "&apos;");
65+
}
66+
67+
function generateSitemapXml(entries: SitemapEntry[]): string {
68+
const urlElements = entries
69+
.map(
70+
(entry) => ` <url>
71+
<loc>${escapeXml(entry.loc)}</loc>${entry.lastmod ? `\n <lastmod>${entry.lastmod}</lastmod>` : ""}
72+
<changefreq>${entry.changefreq}</changefreq>
73+
<priority>${entry.priority}</priority>
74+
</url>`,
75+
)
76+
.join("\n");
77+
78+
return `<?xml version="1.0" encoding="UTF-8"?>
79+
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
80+
<url>
81+
<loc>${escapeXml(SITE_URL)}</loc>
82+
<changefreq>weekly</changefreq>
83+
<priority>1.0</priority>
84+
</url>
85+
${urlElements}
86+
</urlset>
87+
`;
88+
}
89+
90+
async function main(): Promise<void> {
91+
try {
92+
console.log(`Generating sitemap from ${POSTS_DIR}...`);
93+
const entries = await extractPostEntries();
94+
console.log(`Found ${entries.length} posts`);
95+
const xml = generateSitemapXml(entries);
96+
await writeFile(OUTPUT_FILE, xml);
97+
console.log(`✓ Sitemap generated: ${OUTPUT_FILE}`);
98+
} catch (error) {
99+
console.error("Failed to generate sitemap:", error);
100+
process.exit(1);
101+
}
102+
}
103+
104+
main();

0 commit comments

Comments
 (0)