UNPKG

@qalisa/vike-plugin-sitemap

Version:

An unofficial Vike plugin to automagically generate sitemap and robots.txt files

100 lines (99 loc) 3.59 kB
import { generateSitemapContent, writeSitemapToDisk } from './generators/sitemap.js'; import { generateRobotsTxtContent, robotsFileName, writeRobotsTxtToDisk } from './generators/robots.js'; // const defaultOptions = { pagesDir: 'pages', baseUrl: 'http://localhost:3000', filename: 'sitemap.xml', outputDir: '.', defaultChangefreq: 'weekly', defaultPriority: 0.5, customEntries: [], formatDate: (date) => date.toISOString(), robots: { userAgent: '*', disallow: { cloudflare: true, }, }, clashingPathsResolution: 'ignore', debug: { printRoutes: false, printIgnored: false, }, }; /** inplace removes first-order undefined properties from an object */ function removeUndefinedProps(objToRemoveFrom) { for (const key in objToRemoveFrom) { if (objToRemoveFrom[key] === undefined) { delete objToRemoveFrom[key]; } } return objToRemoveFrom; // optional, for chaining } // Vite Plugin export default function VikeSitemapPlugin(options) { // remove undefined props, so that merging keeps default options removeUndefinedProps(options); // const mergedOptions = { ...defaultOptions, ...options, robots: options.robots === false ? false : { ...defaultOptions.robots, ...options.robots }, debug: { ...defaultOptions.debug, ...options.debug }, }; // let sitemapContent = ''; let robotsContent = ''; // Function to update in-memory content const updateContent = async () => { sitemapContent = await generateSitemapContent(mergedOptions); robotsContent = generateRobotsTxtContent(mergedOptions); }; return { name: '@qalisa/vike-plugin-sitemap', async configureServer(server) { // Initialize content when server starts await updateContent(); // Middleware to serve sitemap.xml and robots.txt server.middlewares.use((req, res, next) => { if (req.url === `/${mergedOptions.filename}`) { res.setHeader('Content-Type', 'application/xml'); res.end(sitemapContent); return; } if (mergedOptions.robots !== false && req.url === `/${robotsFileName}`) { res.setHeader('Content-Type', 'text/plain'); res.end(robotsContent); return; } next(); }); }, async handleHotUpdate({ file, server }) { if (file.includes('pages')) { await updateContent(); server.config.logger.info(`✅ Sitemap and ${robotsFileName} updated in memory`); } }, async closeBundle() { // Only write into bundle for the "client" if (this.environment.config.consumer !== 'client') { return; } // if (process.env.NODE_ENV === "production" && options.baseUrl === undefined) { const message = `⚠️ Sitemap - "baseUrl" must be defined in production.`; console.error(message); throw new Error(message); } // await writeSitemapToDisk(mergedOptions, this.environment.config.build.outDir); if (mergedOptions.robots !== false) { await writeRobotsTxtToDisk(mergedOptions, this.environment.config.build.outDir); } }, }; }