Skip to content

Commit 4d51c2f

Browse files
author
mxvsh
committed
Fix sitemap
1 parent 98dac29 commit 4d51c2f

2 files changed

Lines changed: 125 additions & 2 deletions

File tree

apps/www/astro.config.mjs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
// @ts-check
22
import { defineConfig } from 'astro/config';
3-
import sitemap from "@astrojs/sitemap";
43
import tailwindcss from "@tailwindcss/vite";
54

65
// https://astro.build/config
76
export default defineConfig({
87
site: "https://livedot.dev",
9-
integrations: [sitemap()],
108
vite: {
119
plugins: [tailwindcss()],
1210
},

apps/www/src/pages/sitemap.xml.ts

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import { readdirSync, statSync } from "node:fs";
2+
import { posix, relative, resolve } from "node:path";
3+
4+
export const prerender = true;
5+
6+
const site = "https://livedot.dev";
7+
const pagesDir = resolve(process.cwd(), "src/pages");
8+
9+
type SitemapEntry = {
10+
pathname: string;
11+
source: string;
12+
changefreq: string;
13+
priority: string;
14+
};
15+
16+
const exactMetadata = new Map([
17+
["/", { changefreq: "daily", priority: "1.0" }],
18+
["/pricing", { changefreq: "daily", priority: "0.9" }],
19+
["/privacy", { changefreq: "daily", priority: "0.6" }],
20+
["/terms", { changefreq: "daily", priority: "0.6" }],
21+
]);
22+
23+
const prefixMetadata = [
24+
{ prefix: "/blog/", changefreq: "weekly", priority: "0.8" },
25+
{ prefix: "/docs/", changefreq: "weekly", priority: "0.7" },
26+
] as const;
27+
28+
const defaultMetadata = { changefreq: "monthly", priority: "0.7" };
29+
30+
const supportedPageExtensions = new Set([".astro", ".md", ".mdx"]);
31+
32+
const getPageFiles = (dir: string): string[] =>
33+
readdirSync(dir, { withFileTypes: true }).flatMap((entry) => {
34+
const fullPath = resolve(dir, entry.name);
35+
36+
if (entry.isDirectory()) {
37+
return getPageFiles(fullPath);
38+
}
39+
40+
const extension = posix.extname(entry.name);
41+
if (!supportedPageExtensions.has(extension)) {
42+
return [];
43+
}
44+
45+
if (entry.name.startsWith("[") || entry.name.includes("/[")) {
46+
return [];
47+
}
48+
49+
return [fullPath];
50+
});
51+
52+
const toPathname = (source: string) => {
53+
const relativePath = relative(pagesDir, source).replaceAll("\\", "/");
54+
const withoutExtension = relativePath.replace(/\.(astro|md|mdx)$/, "");
55+
56+
if (withoutExtension === "index") {
57+
return "/";
58+
}
59+
60+
if (withoutExtension.endsWith("/index")) {
61+
return `/${withoutExtension.slice(0, -"/index".length)}`;
62+
}
63+
64+
return `/${withoutExtension}`;
65+
};
66+
67+
const getMetadata = (pathname: string) => {
68+
const exact = exactMetadata.get(pathname);
69+
if (exact) {
70+
return exact;
71+
}
72+
73+
const prefixed = prefixMetadata.find((rule) => pathname.startsWith(rule.prefix));
74+
if (prefixed) {
75+
return prefixed;
76+
}
77+
78+
return defaultMetadata;
79+
};
80+
81+
const entries: SitemapEntry[] = getPageFiles(pagesDir)
82+
.filter((source) => !source.endsWith("/sitemap.xml.ts"))
83+
.map((source) => {
84+
const pathname = toPathname(source);
85+
const metadata = getMetadata(pathname);
86+
87+
return {
88+
pathname,
89+
source: relative(process.cwd(), source).replaceAll("\\", "/"),
90+
changefreq: metadata.changefreq,
91+
priority: metadata.priority,
92+
};
93+
})
94+
.sort((a, b) => a.pathname.localeCompare(b.pathname));
95+
96+
const toLastMod = (source: string) => statSync(resolve(process.cwd(), source)).mtime.toISOString();
97+
98+
const toUrlEntry = (entry: SitemapEntry) => {
99+
const loc = `${site}${entry.pathname}`;
100+
const lastmod = toLastMod(entry.source);
101+
102+
return [
103+
" <url>",
104+
` <loc>${loc}</loc>`,
105+
` <lastmod>${lastmod}</lastmod>`,
106+
` <changefreq>${entry.changefreq}</changefreq>`,
107+
` <priority>${entry.priority}</priority>`,
108+
" </url>",
109+
].join("\n");
110+
};
111+
112+
export function GET() {
113+
const xml = [
114+
'<?xml version="1.0" encoding="UTF-8"?>',
115+
'<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
116+
entries.map(toUrlEntry).join("\n"),
117+
"</urlset>",
118+
].join("\n");
119+
120+
return new Response(xml, {
121+
headers: {
122+
"Content-Type": "application/xml; charset=utf-8",
123+
},
124+
});
125+
}

0 commit comments

Comments
 (0)