feat: dynamic sitemap and robots.txt
This commit is contained in:
@@ -0,0 +1,10 @@
|
|||||||
|
import type { MetadataRoute } from 'next'
|
||||||
|
|
||||||
|
const BASE_URL = process.env.NEXT_PUBLIC_BASE_URL ?? 'https://kotobane.achmad.dev'
|
||||||
|
|
||||||
|
export default function robots(): MetadataRoute.Robots {
|
||||||
|
return {
|
||||||
|
rules: { userAgent: '*', allow: '/' },
|
||||||
|
sitemap: `${BASE_URL}/sitemap.xml`,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import type { MetadataRoute } from 'next'
|
||||||
|
import { getAllCategories, getArticles } from '@/lib/directus'
|
||||||
|
|
||||||
|
const BASE_URL = process.env.NEXT_PUBLIC_BASE_URL ?? 'https://kotobane.achmad.dev'
|
||||||
|
|
||||||
|
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
|
||||||
|
let categories: import('@/lib/types').Category[] = []
|
||||||
|
let articles: import('@/lib/types').Article[] = []
|
||||||
|
|
||||||
|
try {
|
||||||
|
const [cats, arts] = await Promise.all([
|
||||||
|
getAllCategories(),
|
||||||
|
getArticles({ limit: 1000 }),
|
||||||
|
])
|
||||||
|
categories = cats
|
||||||
|
articles = arts
|
||||||
|
} catch {
|
||||||
|
// Directus not available — return homepage only
|
||||||
|
}
|
||||||
|
|
||||||
|
const categoryUrls: MetadataRoute.Sitemap = categories.map((cat) => ({
|
||||||
|
url: `${BASE_URL}/${cat.slug}`,
|
||||||
|
changeFrequency: 'daily',
|
||||||
|
priority: 0.8,
|
||||||
|
}))
|
||||||
|
|
||||||
|
const articleUrls: MetadataRoute.Sitemap = articles.map((article) => ({
|
||||||
|
url: `${BASE_URL}/${article.category.slug}/${article.slug}`,
|
||||||
|
lastModified: article.published_at ? new Date(article.published_at) : new Date(),
|
||||||
|
changeFrequency: 'weekly',
|
||||||
|
priority: 0.6,
|
||||||
|
}))
|
||||||
|
|
||||||
|
return [
|
||||||
|
{ url: BASE_URL, changeFrequency: 'hourly', priority: 1.0 },
|
||||||
|
...categoryUrls,
|
||||||
|
...articleUrls,
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user