sitemap.xml generator for remix.run
December 16, 2021 ยท View on GitHub
import childProcess from 'child_process'; import fs from 'fs'; import dotenv from 'dotenv'; import prettier from 'prettier';
const rootDir = process.cwd();
dotenv.config({
path: ${rootDir}/.env.production,
});
interface Route { id: string; path?: string; file: string; children?: Route[]; }
const today = new Date().toISOString(); const domain = process.env.HOST;
console.log(Updating sitemap on ${today} for domain ${domain}...);
const consideredRoutes: string[] = [];
function addPathParts(path1 = '', path2 = ''): string {
return path1.endsWith('/') || path2.startsWith('/') ? ${path1}${path2} : ${path1}/${path2};
}
function pathToEntry(path: string): string {
return <url> <loc>${addPathParts(domain, path)}</loc> <lastmod>${today}</lastmod> <changefreq>daily</changefreq> <priority>0.7</priority> </url>;
}
async function depthFirstHelper(route: Route, currentPath = ''): Promise${rootDir}/app/${route.file};
const routeContent = fs.readFileSync(filePath, 'utf8');
// no default export means API route
if (routeContent.includes('export default')) {
const nextPath = addPathParts(currentPath, route.path);
const isConsidered = consideredRoutes.includes(nextPath);
if (!isConsidered) {
sitemapContent += pathToEntry(nextPath);
consideredRoutes.push(nextPath);
}
}
}
if (route.children) {
for (const childRoute of route.children) {
const nextPath = addPathParts(currentPath, route.path);
sitemapContent += await depthFirstHelper(childRoute, nextPath);
}
}
return sitemapContent; }
async function routesToSitemap(routes: Route[]): Promise
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"
${sitemapContent}
`;
}
const formatSitemap = (sitemap: string) => prettier.format(sitemap, { parser: 'html' });
async function main() { const output = childProcess.execSync('npx remix routes --json'); const routes: Route[] = JSON.parse(output.toString());
const root = routes.find((r) => r.id === 'root');
if (!root) { throw new Error('Root not found'); }
const childRoutes = root.children; if (!childRoutes) { throw new Error('Root has no children routes'); }
console.log(Found ${childRoutes.length} root children routes!);
const sitemap = await routesToSitemap(childRoutes);
const formattedSitemap = formatSitemap(sitemap);
fs.writeFileSync('./public/sitemap.xml', formattedSitemap, 'utf8');
console.log('sitemap.xml updated ๐');
return formattedSitemap; }
main();