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:
@@ -13,15 +13,9 @@ RUN npm install
|
|||||||
# Copy the application code
|
# Copy the application code
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# Set IS_BUILD environment variable for build process
|
|
||||||
ENV IS_BUILD=true
|
|
||||||
|
|
||||||
# Build the Next.js application
|
# Build the Next.js application
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
# Unset IS_BUILD environment variable for runtime
|
|
||||||
ENV IS_BUILD=false
|
|
||||||
|
|
||||||
# Set environmental variable for production mode
|
# Set environmental variable for production mode
|
||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
// portfolio/app/api/sitemap/route.tsx
|
|
||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
|
|
||||||
interface Project {
|
interface Project {
|
||||||
slug: string;
|
slug: string;
|
||||||
|
updated_at?: string; // Optional timestamp for last modification
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ProjectsData {
|
interface ProjectsData {
|
||||||
@@ -14,7 +14,7 @@ interface SitemapRoute {
|
|||||||
lastModified: string;
|
lastModified: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const baseUrl = "https://dki.one";
|
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || "https://dki.one";
|
||||||
|
|
||||||
const generateSitemap = async (): Promise<SitemapRoute[]> => {
|
const generateSitemap = async (): Promise<SitemapRoute[]> => {
|
||||||
try {
|
try {
|
||||||
@@ -33,7 +33,7 @@ const generateSitemap = async (): Promise<SitemapRoute[]> => {
|
|||||||
|
|
||||||
// Check if running in build environment
|
// Check if running in build environment
|
||||||
if (process.env.IS_BUILD) {
|
if (process.env.IS_BUILD) {
|
||||||
// Use mock data during build
|
console.log("Running in build mode - using mock data");
|
||||||
const mockProjectsData: ProjectsData = {
|
const mockProjectsData: ProjectsData = {
|
||||||
posts: [
|
posts: [
|
||||||
{ slug: "project-1" },
|
{ slug: "project-1" },
|
||||||
@@ -50,36 +50,42 @@ const generateSitemap = async (): Promise<SitemapRoute[]> => {
|
|||||||
return [...staticRoutes, ...projectRoutes];
|
return [...staticRoutes, ...projectRoutes];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch project data from your API
|
// Fetch project data from API
|
||||||
console.log("Fetching 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) {
|
if (!response.ok) {
|
||||||
throw new Error(
|
console.error(`Failed to fetch projects: ${response.statusText}`);
|
||||||
`Failed to fetch projects from Ghost: ${response.statusText}`,
|
return staticRoutes; // Return static pages instead of throwing an error
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const projectsData = (await response.json()) as ProjectsData;
|
const projectsData = (await response.json()) as ProjectsData;
|
||||||
console.log("Fetched project data:", projectsData);
|
console.log("Fetched project data:", projectsData);
|
||||||
|
|
||||||
// Generate dynamic routes for projects
|
// Generate dynamic routes for projects
|
||||||
const projectRoutes: SitemapRoute[] = projectsData.posts.map((project) => ({
|
const projectRoutes: SitemapRoute[] = projectsData.posts.map((project) => ({
|
||||||
url: `${baseUrl}/projects/${project.slug}`,
|
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];
|
return [...staticRoutes, ...projectRoutes];
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error generating sitemap:", error);
|
console.error("Error generating sitemap:", error);
|
||||||
throw error;
|
return staticRoutes; // Return static pages in case of failure
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function GET() {
|
export async function GET() {
|
||||||
try {
|
try {
|
||||||
const sitemap = await generateSitemap();
|
const sitemap = await generateSitemap();
|
||||||
return NextResponse.json(sitemap);
|
return NextResponse.json(sitemap, {
|
||||||
|
headers: { "Cache-Control": "no-cache" },
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to generate sitemap:", error);
|
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ error: "Failed to generate sitemap" },
|
{ error: "Failed to generate sitemap" },
|
||||||
{ status: 500 },
|
{ status: 500 },
|
||||||
|
|||||||
@@ -17,36 +17,58 @@ interface SitemapRoute {
|
|||||||
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
|
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
|
||||||
const baseUrl = "https://dki.one";
|
const baseUrl = "https://dki.one";
|
||||||
|
|
||||||
// Fetch the sitemap data from the dynamic API routes
|
try {
|
||||||
const response = await fetch(`${baseUrl}/api/sitemap`);
|
const response = await fetch(`${baseUrl}/api/sitemap`);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`Failed to fetch sitemap: ${response.statusText}`);
|
throw new Error(`Failed to fetch sitemap: ${response.statusText}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const sitemapData = (await response.json()) as SitemapRoute[];
|
const sitemapData = (await response.json()) as SitemapRoute[];
|
||||||
|
|
||||||
return sitemapData.map((route) => {
|
return sitemapData.map((route) => {
|
||||||
let changeFrequency: SitemapRoute["changeFrequency"];
|
const config: Record<
|
||||||
let priority: number;
|
string,
|
||||||
|
{ changeFrequency: SitemapRoute["changeFrequency"]; priority: number }
|
||||||
|
> = {
|
||||||
|
[`${baseUrl}/`]: { changeFrequency: "weekly", priority: 1.0 },
|
||||||
|
};
|
||||||
|
|
||||||
if (route.url === `${baseUrl}/`) {
|
if (route.url.startsWith(`${baseUrl}/projects`)) {
|
||||||
changeFrequency = "weekly";
|
config[route.url] = { changeFrequency: "monthly", priority: 0.8 };
|
||||||
priority = 1.0;
|
} else if (route.url.startsWith(`${baseUrl}/blog`)) {
|
||||||
} else if (route.url.startsWith(`${baseUrl}/projects`)) {
|
config[route.url] = { changeFrequency: "weekly", priority: 0.6 };
|
||||||
changeFrequency = "monthly";
|
|
||||||
priority = 0.8;
|
|
||||||
} else if (route.url.startsWith(`${baseUrl}/Blog`)) {
|
|
||||||
changeFrequency = "weekly";
|
|
||||||
priority = 0.6;
|
|
||||||
} else {
|
} else {
|
||||||
changeFrequency = "monthly";
|
config[route.url] = { changeFrequency: "monthly", priority: 0.5 };
|
||||||
priority = 0.5;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
url: route.url,
|
url: route.url,
|
||||||
lastModified: route.lastModified,
|
lastModified: route.lastModified,
|
||||||
changeFrequency,
|
...config[route.url],
|
||||||
priority,
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
} 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,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user