feat(sitemap): enhance sitemap generation and error handling

Add optional `updated_at` field to the Project interface for 
tracking last modification. Update base URL to use an 
environment variable for better configurability. Improve 
error handling during sitemap data fetching by logging 
errors and returning static routes as a fallback. 
Refactor change frequency and priority logic for clarity 
and maintainability.
This commit is contained in:
2025-02-12 18:31:13 +01:00
parent 66efa25ba8
commit 588dfb912b
3 changed files with 70 additions and 48 deletions

View File

@@ -13,15 +13,9 @@ RUN npm install
# Copy the application code
COPY . .
# Set IS_BUILD environment variable for build process
ENV IS_BUILD=true
# Build the Next.js application
RUN npm run build
# Unset IS_BUILD environment variable for runtime
ENV IS_BUILD=false
# Set environmental variable for production mode
ENV NODE_ENV=production

View File

@@ -1,8 +1,8 @@
// portfolio/app/api/sitemap/route.tsx
import { NextResponse } from "next/server";
interface Project {
slug: string;
updated_at?: string; // Optional timestamp for last modification
}
interface ProjectsData {
@@ -14,7 +14,7 @@ interface SitemapRoute {
lastModified: string;
}
const baseUrl = "https://dki.one";
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || "https://dki.one";
const generateSitemap = async (): Promise<SitemapRoute[]> => {
try {
@@ -33,7 +33,7 @@ const generateSitemap = async (): Promise<SitemapRoute[]> => {
// Check if running in build environment
if (process.env.IS_BUILD) {
// Use mock data during build
console.log("Running in build mode - using mock data");
const mockProjectsData: ProjectsData = {
posts: [
{ slug: "project-1" },
@@ -50,36 +50,42 @@ const generateSitemap = async (): Promise<SitemapRoute[]> => {
return [...staticRoutes, ...projectRoutes];
}
// Fetch project data from your API
// Fetch project data from API
console.log("Fetching project data from API...");
const response = await fetch(`${baseUrl}/api/fetchAllProjects`);
const response = await fetch(`${baseUrl}/api/fetchAllProjects`, {
headers: { "Cache-Control": "no-cache" },
});
if (!response.ok) {
throw new Error(
`Failed to fetch projects from Ghost: ${response.statusText}`,
);
console.error(`Failed to fetch projects: ${response.statusText}`);
return staticRoutes; // Return static pages instead of throwing an error
}
const projectsData = (await response.json()) as ProjectsData;
console.log("Fetched project data:", projectsData);
// Generate dynamic routes for projects
const projectRoutes: SitemapRoute[] = projectsData.posts.map((project) => ({
url: `${baseUrl}/projects/${project.slug}`,
lastModified: new Date().toISOString(),
lastModified: project.updated_at
? new Date(project.updated_at).toISOString()
: new Date().toISOString(),
}));
return [...staticRoutes, ...projectRoutes];
} catch (error) {
console.error("Error generating sitemap:", error);
throw error;
return staticRoutes; // Return static pages in case of failure
}
};
export async function GET() {
try {
const sitemap = await generateSitemap();
return NextResponse.json(sitemap);
return NextResponse.json(sitemap, {
headers: { "Cache-Control": "no-cache" },
});
} catch (error) {
console.error("Failed to generate sitemap:", error);
return NextResponse.json(
{ error: "Failed to generate sitemap" },
{ status: 500 },

View File

@@ -17,36 +17,58 @@ interface SitemapRoute {
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const baseUrl = "https://dki.one";
// Fetch the sitemap data from the dynamic API routes
try {
const response = await fetch(`${baseUrl}/api/sitemap`);
if (!response.ok) {
throw new Error(`Failed to fetch sitemap: ${response.statusText}`);
}
const sitemapData = (await response.json()) as SitemapRoute[];
return sitemapData.map((route) => {
let changeFrequency: SitemapRoute["changeFrequency"];
let priority: number;
const config: Record<
string,
{ changeFrequency: SitemapRoute["changeFrequency"]; priority: number }
> = {
[`${baseUrl}/`]: { changeFrequency: "weekly", priority: 1.0 },
};
if (route.url === `${baseUrl}/`) {
changeFrequency = "weekly";
priority = 1.0;
} else if (route.url.startsWith(`${baseUrl}/projects`)) {
changeFrequency = "monthly";
priority = 0.8;
} else if (route.url.startsWith(`${baseUrl}/Blog`)) {
changeFrequency = "weekly";
priority = 0.6;
if (route.url.startsWith(`${baseUrl}/projects`)) {
config[route.url] = { changeFrequency: "monthly", priority: 0.8 };
} else if (route.url.startsWith(`${baseUrl}/blog`)) {
config[route.url] = { changeFrequency: "weekly", priority: 0.6 };
} else {
changeFrequency = "monthly";
priority = 0.5;
config[route.url] = { changeFrequency: "monthly", priority: 0.5 };
}
return {
url: route.url,
lastModified: route.lastModified,
changeFrequency,
priority,
...config[route.url],
};
});
} catch (error) {
console.error("Failed to fetch dynamic sitemap, using fallback:", error);
return [
{
url: `${baseUrl}/`,
lastModified: new Date().toISOString(),
changeFrequency: "weekly",
priority: 1.0,
},
{
url: `${baseUrl}/privacy-policy`,
lastModified: new Date().toISOString(),
changeFrequency: "yearly",
priority: 0.3,
},
{
url: `${baseUrl}/legal-notice`,
lastModified: new Date().toISOString(),
changeFrequency: "yearly",
priority: 0.3,
},
];
}
}