#!/usr/bin/env node /** * Post-build: generate sitemap.xml from prerendered pages in dist/. * Scans for index.html (root and under each path), excludes 410 paths. * Run after vite build and beasties, before copy-410-paths so 410 dirs don't exist yet. */ import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; import { PATHS as PATHS_410 } from './410-paths.mjs'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const DIST = path.join(__dirname, '..', 'dist'); /** Must match src/lib/seo.ts SEO_DEFAULTS.baseUrl */ const BASE_URL = 'https://mifi.ventures'; const EXCLUDE_FILES = new Set(['404.html', '410.html']); const excludeSet = new Set(PATHS_410); /** * adapter-static emits path.html or path/index.html. Walk dist and collect * every .html that represents a page (exclude 404/410 and 410-gone paths). */ function findPages(dir, basePath = '') { const entries = fs.readdirSync(dir, { withFileTypes: true }); const pages = []; for (const e of entries) { const rel = basePath ? `${basePath}/${e.name}` : e.name; if (e.isDirectory()) { const indexPath = path.join(dir, e.name, 'index.html'); if (fs.existsSync(indexPath)) { if (!excludeSet.has(rel)) { pages.push({ path: rel, indexPath }); } } else { pages.push(...findPages(path.join(dir, e.name), rel)); } } else if (e.name.endsWith('.html') && !EXCLUDE_FILES.has(e.name)) { const urlPath = e.name === 'index.html' ? basePath : (basePath ? `${basePath}/${e.name.slice(0, -5)}` : e.name.slice(0, -5)); if (!excludeSet.has(urlPath)) { pages.push({ path: urlPath, indexPath: path.join(dir, e.name) }); } } } return pages; } function escapeXml(s) { return s .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } function main() { const indexHtml = path.join(DIST, 'index.html'); if (!fs.existsSync(indexHtml)) { console.error('dist/index.html not found. Run build first.'); process.exit(1); } const pages = findPages(DIST).sort((a, b) => { if (a.path === '') return -1; if (b.path === '') return 1; return a.path.localeCompare(b.path); }); const urlElements = []; for (const { path: pagePath, indexPath } of pages) { const loc = pagePath ? `${BASE_URL}/${pagePath}` : BASE_URL; const stat = fs.statSync(indexPath); const lastmod = stat.mtime.toISOString().slice(0, 10); urlElements.push( ` \n ${escapeXml(loc)}\n ${lastmod}\n ` ); } const xml = ` ${urlElements.join('\n')} `; fs.writeFileSync(path.join(DIST, 'sitemap.xml'), xml, 'utf8'); console.log('✓ sitemap.xml generated with', pages.length, 'URLs.'); } main();