Skip to content

Instantly share code, notes, and snippets.

@multipliedtwice
Created February 14, 2022 14:59
Show Gist options
  • Save multipliedtwice/fa90f7ab66d0088ea322d4362cd3a3d8 to your computer and use it in GitHub Desktop.
Save multipliedtwice/fa90f7ab66d0088ea322d4362cd3a3d8 to your computer and use it in GitHub Desktop.
Sveltekit sitemap xml
import dayjs from "dayjs"
import { supportedLanguages } from "../config"
import fs from "fs"
import path from "path"
const cwd = process.cwd()
import util from "util"
import glob from "glob"
const stat = util.promisify(fs.stat)
const asyncGlob = util.promisify(glob)
const BASE_URL = "localhost:3000" // Change this with ur domain
const i18nFolder = "[lang]"
const notPages = [`/${i18nFolder}`, "/p"]
const extraFilter = (file) => !notPages.includes(file)
const directory = path.join(cwd, "src/routes")
const unixStyleDirectory = directory.replace(/\\/gi, "/")
const getRoutes = async (files) => {
console.log('files :>> ', files);
// get all the routes in the directory and index files stats (last modified)
const mapped = await Promise.all(
files.map(async (file) => ({
last_modified: dayjs(await stat(file).mtime).format("YYYY-MM-DD"),
filepath: file.replace(unixStyleDirectory, "").replace(/\/index.svelte/gi, ""),
}))
)
// remove every route that has ID in it - those will be rendered after API call
const filtered = await Promise.all(
mapped.filter(
({ filepath }) => filepath.length && !filepath?.includes("id") && extraFilter(filepath)
)
)
// replace [lang] with available languages
const reduced = await Promise.all(
filtered.reduce((acc = [], current) => {
if (current.filepath.includes(i18nFolder)) {
const i18nRoutes = supportedLanguages.map((lang) =>
current.filepath.replace("[lang]", lang)
)
acc.push(
i18nRoutes.map((route) => ({
filepath: route,
last_modified: current.last_modified,
}))
)
} else {
acc.push(current)
}
return acc
}, [])
)
/*
Output will look something like this:
[
[
{ filepath: '/ru/shortcuts', last_modified: '2021-11-20' },
{ filepath: '/en/shortcuts', last_modified: '2021-11-20' },
{ filepath: '/th/shortcuts', last_modified: '2021-11-20' }
],
{ last_modified: '2021-11-20', filepath: '/changelog' },
{ last_modified: '2021-11-20', filepath: '/privacy' },
]
*/
return reduced
}
const render = (svelteRoutes) => `<?xml version="1.0" encoding="UTF-8" ?>
<urlset
xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:xhtml="http://www.w3.org/1999/xhtml"
>
${svelteRoutes
.map((route) => {
if (Array.isArray(route)) {
return `<url>
${route
.map((r, i) => {
if (i === 0) {
return `<loc>${BASE_URL}${r.filepath}</loc>`
} else {
return `<xhtml:link rel="alternate" hreflang="${
r.filepath.split("/")[1]
}" href="${BASE_URL}${r.filepath}"/>`
}
})
.join("\n")}
<lastmod>${route[0].last_modified}</lastmod>
</url>`
} else {
return `<url>
<loc>
${BASE_URL}${route.filepath}
</loc>
<lastmod>${route.last_modified}</lastmod>
</url>`
}
})
.join("\n")}
</urlset>
`
export async function get(req, res, next) {
const headers = {
'Cache-Control': 'max-age=0, s-max-age=3600',
"Content-Type": "application/xml",
}
const files = await asyncGlob(directory + "/**/!(_)*.svelte")
const svelteRoutes = await getRoutes(files)
const sitemap = await render(svelteRoutes)
const response = {
headers,
body: sitemap,
}
return response
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment