diff options
Diffstat (limited to 'packages/integrations/sitemap/src/index.ts')
-rw-r--r-- | packages/integrations/sitemap/src/index.ts | 38 |
1 files changed, 38 insertions, 0 deletions
diff --git a/packages/integrations/sitemap/src/index.ts b/packages/integrations/sitemap/src/index.ts new file mode 100644 index 000000000..28bc61396 --- /dev/null +++ b/packages/integrations/sitemap/src/index.ts @@ -0,0 +1,38 @@ +import fs from 'node:fs'; +import type { AstroConfig, AstroIntegration } from 'astro'; +const STATUS_CODE_PAGE_REGEXP = /\/[0-9]{3}\/?$/; + +/** Construct sitemap.xml given a set of URLs */ +function generateSitemap(pages: string[]) { + // TODO: find way to respect <link rel="canonical"> URLs here + // TODO: find way to exclude pages from sitemap + const urls = [...pages].filter((url) => !STATUS_CODE_PAGE_REGEXP.test(url)); + urls.sort((a, b) => a.localeCompare(b, 'en', { numeric: true })); // sort alphabetically so sitemap is same each time + let sitemap = `<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">`; + for (const url of urls) { + sitemap += `<url><loc>${url}</loc></url>`; + } + sitemap += `</urlset>\n`; + return sitemap; +} + +export default function createPlugin(): AstroIntegration { + let config: AstroConfig; + return { + name: '@astrojs/sitemap', + hooks: { + 'astro:config:done': async ({ config: _config }) => { + config = _config; + }, + 'astro:build:done': async ({ pages, dir }) => { + const finalSiteUrl = config.buildOptions.site; + if (!finalSiteUrl) { + return; + } + const pageUrls = pages.map((p) => new URL(p.pathname, finalSiteUrl).href); + const sitemapContent = generateSitemap(pageUrls); + fs.writeFileSync(new URL('sitemap.xml', dir), sitemapContent); + }, + }, + }; +} |