1- // Build-time generator for the blog sitemap.
1+ // Build-time generator for blog sitemap artifacts .
22//
3- // Reads frontend/src/content/blogPosts.ts and writes public/blog-sitemap.xml so
4- // that adding a post only requires editing blogPosts.ts — no backend change.
3+ // Reads frontend/src/content/blogPosts.ts and writes:
4+ // 1. public/blog-sitemap.xml — served at bloghub.app/blog-sitemap.xml
5+ // 2. backend/app/data/manual_blog_posts.json — consumed by api.bloghub.app/sitemap.xml
6+ //
7+ // Adding a post only requires editing blogPosts.ts, then running `npm run blog-sitemap`
8+ // (also runs automatically on `npm run build`).
59//
610// We parse the slug/publishedAt pairs out of the .ts source with a regex rather
711// than importing it, so the script stays dependency-free (no tsx/ts-node).
812
9- import { readFileSync , writeFileSync } from "node:fs" ;
13+ import { mkdirSync , readFileSync , writeFileSync } from "node:fs" ;
1014import { fileURLToPath } from "node:url" ;
1115import { dirname , resolve } from "node:path" ;
1216
1317const SITE_URL = "https://bloghub.app" ;
1418
15- // Static, crawlable frontend routes that aren't blog posts. The backend sitemap at
16- // api.bloghub.app/sitemap.xml covers publication pages; anything hand-built in
17- // src/pages that we want indexed belongs here.
19+ // Static, crawlable frontend routes that aren't blog posts. Also mirrored into the
20+ // backend sitemap so api.bloghub.app/sitemap.xml is the single discovery source.
1821const STATIC_PAGES = [
1922 { path : "/submit-your-newsletter" , changefreq : "monthly" , priority : "0.9" } ,
23+ { path : "/blogs" , changefreq : "weekly" , priority : "0.6" } ,
2024] ;
2125
2226const __dirname = dirname ( fileURLToPath ( import . meta. url ) ) ;
2327const dataFile = resolve ( __dirname , "../src/content/blogPosts.ts" ) ;
24- const outFile = resolve ( __dirname , "../public/blog-sitemap.xml" ) ;
28+ const outXml = resolve ( __dirname , "../public/blog-sitemap.xml" ) ;
29+ const outJson = resolve ( __dirname , "../../backend/app/data/manual_blog_posts.json" ) ;
2530
2631const source = readFileSync ( dataFile , "utf8" ) ;
2732
@@ -35,18 +40,18 @@ while ((match = slugRe.exec(source)) !== null) {
3540 // Find the publishedAt that follows this slug within the same object.
3641 const rest = source . slice ( match . index ) ;
3742 const dateMatch = rest . match ( / p u b l i s h e d A t : \s * [ " ' ` ] ( \d { 4 } - \d { 2 } - \d { 2 } ) [ " ' ` ] / ) ;
38- posts . push ( { slug, lastmod : dateMatch ? dateMatch [ 1 ] : null } ) ;
43+ posts . push ( { slug, publishedAt : dateMatch ? dateMatch [ 1 ] : null } ) ;
3944}
4045
4146if ( posts . length === 0 ) {
4247 console . warn ( "[gen-blog-sitemap] No posts found in blogPosts.ts" ) ;
4348}
4449
45- const urlEntry = ( { slug, lastmod } ) => {
50+ const urlEntry = ( { slug, publishedAt } ) => {
4651 const lines = [
4752 " <url>" ,
4853 ` <loc>${ SITE_URL } /blogs/${ slug } </loc>` ,
49- ...( lastmod ? [ ` <lastmod>${ lastmod } </lastmod>` ] : [ ] ) ,
54+ ...( publishedAt ? [ ` <lastmod>${ publishedAt } </lastmod>` ] : [ ] ) ,
5055 " <changefreq>monthly</changefreq>" ,
5156 " <priority>0.6</priority>" ,
5257 " </url>" ,
@@ -67,18 +72,17 @@ const xml = [
6772 '<?xml version="1.0" encoding="UTF-8"?>' ,
6873 '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' ,
6974 ...STATIC_PAGES . map ( staticEntry ) ,
70- // The blog index page itself.
71- " <url>" ,
72- ` <loc>${ SITE_URL } /blogs</loc>` ,
73- " <changefreq>weekly</changefreq>" ,
74- " <priority>0.6</priority>" ,
75- " </url>" ,
7675 ...posts . map ( urlEntry ) ,
7776 "</urlset>" ,
7877 "" ,
7978] . join ( "\n" ) ;
8079
81- writeFileSync ( outFile , xml , "utf8" ) ;
80+ writeFileSync ( outXml , xml , "utf8" ) ;
81+
82+ mkdirSync ( dirname ( outJson ) , { recursive : true } ) ;
83+ writeFileSync ( outJson , `${ JSON . stringify ( { staticPages : STATIC_PAGES , posts } , null , 2 ) } \n` , "utf8" ) ;
84+
8285console . log (
8386 `[gen-blog-sitemap] Wrote ${ STATIC_PAGES . length } static page(s) and ${ posts . length } post(s) to public/blog-sitemap.xml` ,
8487) ;
88+ console . log ( `[gen-blog-sitemap] Wrote ${ posts . length } post(s) to backend/app/data/manual_blog_posts.json` ) ;
0 commit comments