Skip to content

Commit 58a3f4f

Browse files
committed
2 parents 452def5 + d2b36c9 commit 58a3f4f

File tree

4 files changed

+93
-0
lines changed

4 files changed

+93
-0
lines changed

public/.htaccess

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,16 @@
2222
RewriteCond %{REQUEST_URI} !(\.[a-zA-Z0-9]{1,5}|/)$
2323
RewriteRule (.*)$ /$1/ [R=301,L]
2424
</IfModule>
25+
26+
# ✅ Optional: better headers for sitemap & robots
27+
<IfModule mod_headers.c>
28+
<Files "sitemap.xml">
29+
Header unset Set-Cookie
30+
Header set Cache-Control "public, max-age=86400"
31+
Header set Content-Type "application/xml; charset=UTF-8"
32+
</Files>
33+
<Files "robots.txt">
34+
Header set Content-Type "text/plain; charset=UTF-8"
35+
</Files>
36+
</IfModule>
37+

public/robots.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
User-agent: *
2+
Disallow:
3+
4+
Sitemap: https://ras.ece.utexas.edu/sitemap.xml
5+

src/app/sitemap.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import type { MetadataRoute } from 'next';
2+
// Ensure this route is statically exported when using `output: 'export'`.
3+
export const dynamic = 'force-static'
4+
// For static HTML export, ensure no ISR revalidation is requested.
5+
export const revalidate = false
6+
import { getPosts } from './components/posts';
7+
8+
const BASE_URL = process.env.NEXT_PUBLIC_SITE_URL ?? 'https://ras.ece.utexas.edu';
9+
10+
export default function sitemap(): MetadataRoute.Sitemap {
11+
const now = new Date();
12+
13+
const staticRoutes = [
14+
'', // /
15+
'/join',
16+
'/support',
17+
'/leaders',
18+
'/blog',
19+
'/embed',
20+
];
21+
22+
const staticEntries: MetadataRoute.Sitemap = staticRoutes.map(route => ({
23+
url: `${BASE_URL}${route === '' ? '/' : route}`,
24+
lastModified: now,
25+
changeFrequency: route === '' ? 'weekly' : 'monthly',
26+
priority: route === '' ? 1.0 : 0.7,
27+
}));
28+
29+
const posts = getPosts();
30+
const postEntries: MetadataRoute.Sitemap = posts.map(post => ({
31+
url: `${BASE_URL}/blog/${post.slug}`,
32+
lastModified: new Date(post.date || now),
33+
changeFrequency: 'monthly',
34+
priority: 0.6,
35+
}));
36+
return [...staticEntries, ...postEntries];
37+
}

src/app/sitemap.xml/route.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { getPosts } from '../components/posts'
2+
3+
// Ensure this route is statically exported for `output: 'export'` builds
4+
export const dynamic = 'force-static'
5+
export const revalidate = false
6+
7+
const BASE_URL = process.env.NEXT_PUBLIC_SITE_URL ?? 'https://utras.org'
8+
9+
function buildSitemapXml(): string {
10+
const now = new Date()
11+
12+
const staticRoutes = ['', '/join', '/support', '/leaders', '/blog', '/embed']
13+
14+
const urls = staticRoutes.map(route => ({
15+
loc: `${BASE_URL}${route === '' ? '/' : route}`,
16+
lastmod: now.toISOString(),
17+
}))
18+
19+
const posts = getPosts()
20+
const postUrls = posts.map(p => ({ loc: `${BASE_URL}/blog/${p.slug}`, lastmod: new Date(p.date || now).toISOString() }))
21+
22+
const allUrls = [...urls, ...postUrls]
23+
24+
const urlEntries = allUrls
25+
.map(u => ` <url>\n <loc>${u.loc}</loc>\n <lastmod>${u.lastmod}</lastmod>\n </url>`)
26+
.join('\n')
27+
28+
return `<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n${urlEntries}\n</urlset>`
29+
}
30+
31+
export async function GET() {
32+
const xml = buildSitemapXml()
33+
return new Response(xml, {
34+
headers: {
35+
'Content-Type': 'application/xml',
36+
},
37+
})
38+
}

0 commit comments

Comments
 (0)