feat: update sitemap generation script to use Node.js and mark subprojects as dirty
parent
1c1775c327
commit
b95230f53e
|
|
@ -8,7 +8,7 @@
|
||||||
"generate:metadata": "cd .. && npx tsx scripts/generate-component-metadata.ts",
|
"generate:metadata": "cd .. && npx tsx scripts/generate-component-metadata.ts",
|
||||||
"generate:favicons": "node ../scripts/generate-favicons.mjs",
|
"generate:favicons": "node ../scripts/generate-favicons.mjs",
|
||||||
"generate:og-image": "node ../scripts/generate-og-image.mjs",
|
"generate:og-image": "node ../scripts/generate-og-image.mjs",
|
||||||
"generate:sitemap": "npx tsx scripts/generate-sitemap.ts",
|
"generate:sitemap": "node scripts/generate-sitemap.mjs",
|
||||||
"dev": "npm run generate:metadata && vite",
|
"dev": "npm run generate:metadata && vite",
|
||||||
"build": "npm run generate:metadata && npm run generate:sitemap && tsc -b && vite build",
|
"build": "npm run generate:metadata && npm run generate:sitemap && tsc -b && vite build",
|
||||||
"build:docker": "npm run generate:sitemap && vite build",
|
"build:docker": "npm run generate:sitemap && vite build",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
/**
|
||||||
|
* Auto-generates public/sitemap.xml by parsing seoRoutes.ts
|
||||||
|
* Pure Node.js — no tsx/ts-node needed.
|
||||||
|
* Run: node scripts/generate-sitemap.mjs [--ping]
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { readFileSync, writeFileSync } from 'fs';
|
||||||
|
import { resolve, dirname } from 'path';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
|
||||||
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||||
|
const DOMAIN = 'https://velxio.dev';
|
||||||
|
const TODAY = new Date().toISOString().slice(0, 10);
|
||||||
|
|
||||||
|
// Parse seoRoutes.ts to extract the route objects
|
||||||
|
const seoRoutesPath = resolve(__dirname, '../src/seoRoutes.ts');
|
||||||
|
const source = readFileSync(seoRoutesPath, 'utf-8');
|
||||||
|
|
||||||
|
// Extract the array content between SEO_ROUTES = [ ... ];
|
||||||
|
const match = source.match(/SEO_ROUTES[^=]*=\s*\[([\s\S]*?)\];/);
|
||||||
|
if (!match) {
|
||||||
|
console.error('Could not parse SEO_ROUTES from seoRoutes.ts');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Evaluate the array (safe: only contains string/number/boolean literals)
|
||||||
|
// Convert TS-style comments and trailing commas to valid JSON-ish
|
||||||
|
const arrayStr = match[1]
|
||||||
|
.replace(/\/\/.*$/gm, '') // remove line comments
|
||||||
|
.replace(/\/\*[\s\S]*?\*\//g, ''); // remove block comments
|
||||||
|
|
||||||
|
// Use Function constructor to evaluate the JS array literal
|
||||||
|
const routes = new Function(`return [${arrayStr}]`)();
|
||||||
|
|
||||||
|
const indexable = routes.filter((r) => !r.noindex);
|
||||||
|
|
||||||
|
const xml = `<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
|
||||||
|
xmlns:xhtml="http://www.w3.org/1999/xhtml">
|
||||||
|
${indexable
|
||||||
|
.map(
|
||||||
|
(r) => `
|
||||||
|
<url>
|
||||||
|
<loc>${DOMAIN}${r.path}</loc>
|
||||||
|
<lastmod>${TODAY}</lastmod>
|
||||||
|
<changefreq>${r.changefreq ?? 'monthly'}</changefreq>
|
||||||
|
<priority>${r.priority ?? 0.5}</priority>
|
||||||
|
</url>`
|
||||||
|
)
|
||||||
|
.join('')}
|
||||||
|
|
||||||
|
</urlset>
|
||||||
|
`;
|
||||||
|
|
||||||
|
const outPath = resolve(__dirname, '../public/sitemap.xml');
|
||||||
|
writeFileSync(outPath, xml.trimStart(), 'utf-8');
|
||||||
|
console.log(`sitemap.xml generated → ${indexable.length} URLs (${TODAY})`);
|
||||||
|
|
||||||
|
// Ping search engines (optional)
|
||||||
|
if (process.argv.includes('--ping')) {
|
||||||
|
const sitemapUrl = `${DOMAIN}/sitemap.xml`;
|
||||||
|
const pings = [
|
||||||
|
`https://www.google.com/ping?sitemap=${encodeURIComponent(sitemapUrl)}`,
|
||||||
|
`https://www.bing.com/ping?sitemap=${encodeURIComponent(sitemapUrl)}`,
|
||||||
|
];
|
||||||
|
console.log('Pinging search engines...');
|
||||||
|
await Promise.allSettled(
|
||||||
|
pings.map(async (url) => {
|
||||||
|
try {
|
||||||
|
const res = await fetch(url);
|
||||||
|
console.log(` ${res.ok ? 'OK' : 'FAIL'} ${url.split('?')[0]}`);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(` FAIL ${url.split('?')[0]}: ${e.message}`);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue