Add static SEO and FAQ foundations

This commit is contained in:
Kevin
2026-09-02 01:56:51 -04:00
parent 19bba4282e
commit 245f0e8a7e
10 changed files with 53 additions and 4 deletions
+3
View File
@@ -11,3 +11,6 @@ const result = spawnSync('npm', ['run', 'build', '--', '--outDir', `dist/${key}`
stdio: 'inherit'
});
if (result.status !== 0) process.exit(result.status ?? 1);
const seo = spawnSync('node', ['scripts/generate-seo.mjs'], { env: { ...process.env, SITE_KEY: key }, stdio: 'inherit' });
if (seo.status !== 0) process.exit(seo.status ?? 1);
+28
View File
@@ -0,0 +1,28 @@
import { readdir, readFile, writeFile } from 'node:fs/promises';
import { join, relative, sep } from 'node:path';
const key = process.env.SITE_KEY;
if (!key) throw new Error('SITE_KEY is required.');
const manifest = JSON.parse(await readFile('sites.json', 'utf8'));
const deployment = manifest.sites[key];
if (!deployment) throw new Error(`Unknown site key: ${key}`);
const outputDir = `dist/${key}`;
async function htmlFiles(dir) {
const entries = await readdir(dir, { withFileTypes: true });
const nested = await Promise.all(entries.map(async (entry) => entry.isDirectory() ? htmlFiles(join(dir, entry.name)) : entry.name.endsWith('.html') ? [join(dir, entry.name)] : []));
return nested.flat();
}
const urls = (await Promise.all((await htmlFiles(outputDir)).map(async (file) => {
const html = await readFile(file, 'utf8');
if (/<title>Redirecting to:/i.test(html)) return null;
const path = relative(outputDir, file).split(sep).join('/');
if (path === '404.html') return null;
return path === 'index.html' ? '/' : `/${path.replace(/index\.html$/, '')}`;
}))).filter(Boolean).sort();
const origin = `https://${deployment.hostname}`;
const sitemap = `<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n${urls.map((path) => ` <url><loc>${origin}${path}</loc></url>`).join('\n')}\n</urlset>\n`;
const robots = process.env.DEPLOY_ENV === 'production' ? `User-agent: *\nAllow: /\nSitemap: ${origin}/sitemap.xml\n` : 'User-agent: *\nDisallow: /\n';
await Promise.all([writeFile(join(outputDir, 'sitemap.xml'), sitemap), writeFile(join(outputDir, 'robots.txt'), robots)]);
console.log(`Generated ${urls.length} sitemap URLs and ${process.env.DEPLOY_ENV === 'production' ? 'production' : 'preview'} robots rules for ${key}.`);
+1 -1
View File
@@ -4,7 +4,7 @@ import { resolve } from 'node:path';
const key = process.env.SITE_KEY;
if (!key) throw new Error('SITE_KEY is required.');
const root = resolve(`dist/${key}`);
const required = ['index.html', '404.html'];
const required = ['index.html', '404.html', 'robots.txt', 'sitemap.xml'];
if (key === 'www') required.push('about/index.html', 'services/index.html', 'contact/index.html');
for (const file of required) await access(resolve(root, file));