All checks were successful
CI — Website / Website — typecheck, build (pull_request) Successful in 57s
70 lines
2.3 KiB
JavaScript
70 lines
2.3 KiB
JavaScript
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
import { dirname, join } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const root = dirname(fileURLToPath(import.meta.url));
|
|
const distHtml = join(root, 'dist', 'index.html');
|
|
const { origin, routes } = JSON.parse(
|
|
readFileSync(join(root, 'src', 'seo.routes.json'), 'utf8'),
|
|
);
|
|
|
|
function apply(html, { title, description, url, robots }) {
|
|
let out = html;
|
|
out = out.replace(/<title>[\s\S]*?<\/title>/, `<title>${title}</title>`);
|
|
out = out.replace(
|
|
/(<meta\s+name="description"\s+content=")[^"]*(")/,
|
|
`$1${description}$2`,
|
|
);
|
|
out = out.replace(/(<meta\s+name="robots"\s+content=")[^"]*(")/, `$1${robots}$2`);
|
|
out = out.replace(/(<meta\s+property="og:title"\s+content=")[^"]*(")/, `$1${title}$2`);
|
|
out = out.replace(
|
|
/(<meta\s+property="og:description"\s+content=")[^"]*(")/,
|
|
`$1${description}$2`,
|
|
);
|
|
out = out.replace(/(<meta\s+property="og:url"\s+content=")[^"]*(")/, `$1${url}$2`);
|
|
out = out.replace(/(<meta\s+name="twitter:title"\s+content=")[^"]*(")/, `$1${title}$2`);
|
|
out = out.replace(
|
|
/(<meta\s+name="twitter:description"\s+content=")[^"]*(")/,
|
|
`$1${description}$2`,
|
|
);
|
|
out = out.replace(/(<link\s+rel="canonical"\s+href=")[^"]*(")/, `$1${url}$2`);
|
|
return out;
|
|
}
|
|
|
|
const template = readFileSync(distHtml, 'utf8');
|
|
if (!template.includes('rel="canonical"') || !template.includes('og:title')) {
|
|
console.error('dist/index.html is missing SEO tags — check index.html');
|
|
process.exit(1);
|
|
}
|
|
|
|
const written = [];
|
|
for (const route of routes) {
|
|
const url = route.path === '/' ? `${origin}/` : `${origin}${route.path}`;
|
|
const file = route.path === '/' ? 'index.html' : `${route.path.replace(/^\//, '')}/index.html`;
|
|
const dest = join(root, 'dist', file);
|
|
mkdirSync(dirname(dest), { recursive: true });
|
|
writeFileSync(
|
|
dest,
|
|
apply(template, {
|
|
title: route.title,
|
|
description: route.description,
|
|
url,
|
|
robots: 'index, follow',
|
|
}),
|
|
);
|
|
written.push(file);
|
|
}
|
|
|
|
writeFileSync(
|
|
join(root, 'dist', '404.html'),
|
|
apply(template, {
|
|
title: 'Page not found — LexAI',
|
|
description: 'That address is not a LexAI page.',
|
|
url: `${origin}/`,
|
|
robots: 'noindex, follow',
|
|
}),
|
|
);
|
|
written.push('404.html');
|
|
|
|
console.log('SEO HTML written for', written.join(', '));
|