development
ts 83 lines 3.77 KB
Raw
1 import { execSync } from "child_process";
2 import { MetadataRoute } from "next";
3 import { allKtis, allPages, allPosts } from "contentlayer/generated";
4 import { absoluteUrl } from "./seo";
5
6 export const dynamic = "force-static";
7
8 // Static routes have no frontmatter date, so pull the real last-edited date
9 // from git history instead of stamping every one with the build time —
10 // accurate lastmod values are a genuine freshness signal for crawlers.
11 function lastCommitDate(sourceFile: string): Date | undefined {
12 try {
13 const iso = execSync(`git log -1 --format=%cI -- "${sourceFile}"`, {
14 cwd: process.cwd(),
15 encoding: "utf8",
16 }).trim();
17 return iso ? new Date(iso) : undefined;
18 } catch {
19 return undefined;
20 }
21 }
22
23 interface StaticRoute {
24 path: string;
25 sourceFile: string;
26 changeFrequency: MetadataRoute.Sitemap[number]["changeFrequency"];
27 priority: number;
28 }
29
30 const STATIC_ROUTES: StaticRoute[] = [
31 { path: "/", sourceFile: "app/page.tsx", changeFrequency: "weekly", priority: 1 },
32 { path: "/services", sourceFile: "app/services/page.tsx", changeFrequency: "weekly", priority: 0.9 },
33 { path: "/mail", sourceFile: "app/mail/page.tsx", changeFrequency: "weekly", priority: 0.9 },
34 { path: "/auth", sourceFile: "app/auth/page.tsx", changeFrequency: "weekly", priority: 0.9 },
35 { path: "/posts", sourceFile: "app/posts/page.tsx", changeFrequency: "weekly", priority: 0.8 },
36 { path: "/kti", sourceFile: "app/kti/page.tsx", changeFrequency: "weekly", priority: 0.8 },
37 { path: "/heroku-alternative", sourceFile: "app/heroku-alternative/page.tsx", changeFrequency: "weekly", priority: 0.8 },
38 { path: "/railway-alternative", sourceFile: "app/railway-alternative/page.tsx", changeFrequency: "weekly", priority: 0.8 },
39 { path: "/resend-alternative", sourceFile: "app/resend-alternative/page.tsx", changeFrequency: "weekly", priority: 0.8 },
40 { path: "/usesend-alternative", sourceFile: "app/usesend-alternative/page.tsx", changeFrequency: "weekly", priority: 0.8 },
41 { path: "/sendgrid-alternative", sourceFile: "app/sendgrid-alternative/page.tsx", changeFrequency: "weekly", priority: 0.8 },
42 { path: "/auth0-alternative", sourceFile: "app/auth0-alternative/page.tsx", changeFrequency: "weekly", priority: 0.8 },
43 { path: "/clerk-alternative", sourceFile: "app/clerk-alternative/page.tsx", changeFrequency: "weekly", priority: 0.8 },
44 { path: "/supabase-alternative", sourceFile: "app/supabase-alternative/page.tsx", changeFrequency: "weekly", priority: 0.8 },
45 { path: "/neon-alternative", sourceFile: "app/neon-alternative/page.tsx", changeFrequency: "weekly", priority: 0.8 },
46 { path: "/planetscale-alternative", sourceFile: "app/planetscale-alternative/page.tsx", changeFrequency: "weekly", priority: 0.8 },
47 ];
48
49 export default function sitemap(): MetadataRoute.Sitemap {
50 const staticRoutes: MetadataRoute.Sitemap = STATIC_ROUTES.map((route) => ({
51 url: absoluteUrl(route.path),
52 lastModified: lastCommitDate(route.sourceFile),
53 changeFrequency: route.changeFrequency,
54 priority: route.priority,
55 }));
56
57 const postRoutes: MetadataRoute.Sitemap = allPosts
58 .filter((post) => post.published)
59 .map((post) => ({
60 url: absoluteUrl(post.slug),
61 lastModified: post.lastmod || post.date,
62 changeFrequency: "monthly",
63 priority: 0.7,
64 }));
65
66 const pageRoutes: MetadataRoute.Sitemap = allPages.map((page) => ({
67 url: absoluteUrl(`/${page.slugAsParams}`),
68 lastModified: page.lastmod,
69 changeFrequency: "yearly",
70 priority: 0.5,
71 }));
72
73 const ktiRoutes: MetadataRoute.Sitemap = allKtis
74 .filter((kti) => kti.published)
75 .map((kti) => ({
76 url: absoluteUrl(kti.slug),
77 lastModified: kti.lastmod,
78 changeFrequency: "monthly",
79 priority: 0.6,
80 }));
81
82 return [...staticRoutes, ...pageRoutes, ...postRoutes, ...ktiRoutes];
83 }