// This is a development script executed in the build step of pages const fs = require('fs'); const path = require('path'); const glob = require('glob'); const guides = require('../content/guides.json'); const roadmaps = require('../content/roadmaps.json'); const DOMAIN = 'https://roadmap.sh'; const PAGES_DIR = path.join(__dirname, '../pages'); const STORAGE_PATH = path.join(__dirname, '../content'); const SITEMAP_PATH = path.join(__dirname, '../public/sitemap.xml'); const PAGES_PATH = path.join(__dirname, '../pages'); const ROADMAPS_PATH = path.join(__dirname, '../content/roadmaps'); const GUIDES_PATH = path.join(__dirname, '../content/guides'); // Set the header const xmlHeader = ` `; // Wrap all pages in tags const xmlUrlWrapper = nodes => `${xmlHeader} ${nodes} `; function getSlugPriority(pageSlug) { if (pageSlug === '/') { return '1.0'; } const slugPriorities = [ [ '/roadmaps', '/guides', '/watch', '/podcasts' ], // 1.0 ['/signup'], // 0.9 ['/about'] // 0.8 ]; const foundIndex = slugPriorities.findIndex( routes => routes.some(route => pageSlug.startsWith(route)) ); if (foundIndex !== -1) { return parseFloat((10 - foundIndex) / 10) .toFixed(1); } return 0.5; } function getPageRoutes() { const files = glob.sync(`${PAGES_PATH}/**/*.tsx`, { ignore: [ '**/_*.tsx', // private non-page files e.g. _document.js '**/[[]*[]].tsx', // Ignore dynamic pages i.e. `page/[something].js` files '**/[[]*[]]/*.tsx', // Ignore files inside dynamic pages i.e. `[something]/abc.js` '**/components/*.tsx' // Ignore the component files ] }); const pageRoutes = {}; files.forEach(file => { const pageName = file.replace(PAGES_PATH, '').replace('.tsx', ''); const pagePath = pageName.replace('/index', '') || '/'; pageRoutes[pagePath] = { page: `${pageName}` }; }); return pageRoutes; } function generateNode(nodeProps) { const { slug, basePath, fileName, priority = null, date = null, frequency = 'monthly' } = nodeProps; const pagePath = path.join(basePath, fileName); let pageStats = {}; try { pageStats = fs.lstatSync(pagePath); } catch (e) { console.log(`File not found: ${pagePath}`); pageStats = { mtime: (new Date()) }; } return ` ${DOMAIN}${slug} ${frequency} ${date || pageStats.mtime.toISOString()} ${priority || getSlugPriority(slug)} `; } function generateSiteMap() { const pageRoutes = getPageRoutes(); const pageSlugs = Object.keys(pageRoutes) .filter(route => ![ '/privacy', '/terms' ].includes(route)); const pagesChunk = pageSlugs.map(pageSlug => { return generateNode({ basePath: PAGES_DIR, fileName: `${pageRoutes[pageSlug].page}.tsx`, slug: pageSlug }); }); const guidesChunk = guides.map(guide => { return generateNode({ basePath: GUIDES_PATH, fileName: `${guide.id}.md`, slug: `/guides/${guide.id}`, date: guide.updatedAt, priority: '1.0' }); }); const roadmapsChunk = roadmaps.map((roadmap, roadmapCounter) => { return generateNode({ basePath: ROADMAPS_PATH, fileName: roadmap.metaPath.replace('/roadmaps', ''), slug: `/${roadmap.id}`, date: roadmap.updatedAt, priority: '1.0' }); }); const nodes = [ ...roadmapsChunk, ...guidesChunk, ...pagesChunk ]; const sitemap = `${xmlUrlWrapper(nodes.join('\n'))}`; fs.writeFileSync(SITEMAP_PATH, sitemap); console.log(`sitemap.xml with ${nodes.length} entries was written to ${SITEMAP_PATH}`); } generateSiteMap();