Add static SEO and FAQ foundations
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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}.`);
|
||||
@@ -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));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user