perf: apply Vercel Next.js best practices (caching, image optimization, metadata)
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
'use server'
|
||||
|
||||
import { cache } from 'react';
|
||||
import sql from '@/lib/db';
|
||||
|
||||
export async function getSettings() {
|
||||
// Vercel Best Practice: server-cache-react - Deduplicate data fetching per request
|
||||
export const getSettings = cache(async function() {
|
||||
try {
|
||||
const settings = await sql`SELECT * FROM settings WHERE id = 1 LIMIT 1`;
|
||||
return settings[0] || null;
|
||||
@@ -10,7 +11,7 @@ export async function getSettings() {
|
||||
console.error('Error fetching settings:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export async function getFeaturedServices() {
|
||||
try {
|
||||
@@ -69,7 +70,7 @@ export async function getPartners() {
|
||||
}
|
||||
}
|
||||
|
||||
export async function getProjectBySlug(slug: string) {
|
||||
export const getProjectBySlug = cache(async function(slug: string) {
|
||||
try {
|
||||
const projects = await sql`SELECT * FROM projects WHERE slug = ${slug} LIMIT 1`;
|
||||
if (projects.length === 0) return null;
|
||||
@@ -96,8 +97,9 @@ export async function getProjectBySlug(slug: string) {
|
||||
console.error('Error fetching project:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
export async function getServiceBySlug(slug: string) {
|
||||
});
|
||||
|
||||
export const getServiceBySlug = cache(async function(slug: string) {
|
||||
try {
|
||||
const services = await sql`SELECT * FROM services WHERE slug = ${slug} LIMIT 1`;
|
||||
return services[0] || null;
|
||||
@@ -105,9 +107,9 @@ export async function getServiceBySlug(slug: string) {
|
||||
console.error('Error fetching service:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export async function getLocationBySlug(slug: string) {
|
||||
export const getLocationBySlug = cache(async function(slug: string) {
|
||||
try {
|
||||
const locations = await sql`SELECT * FROM locations WHERE slug = ${slug} LIMIT 1`;
|
||||
return locations[0] || null;
|
||||
@@ -115,7 +117,7 @@ export async function getLocationBySlug(slug: string) {
|
||||
console.error('Error fetching location:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
export async function getProjectsByService(serviceName: string) {
|
||||
@@ -137,7 +139,8 @@ export async function getProjectsByService(serviceName: string) {
|
||||
|
||||
export async function getLocations() {
|
||||
try {
|
||||
return await sql`SELECT * FROM locations ORDER BY name ASC`;
|
||||
const locations = await sql`SELECT * FROM locations ORDER BY name ASC`;
|
||||
return locations;
|
||||
} catch (error) {
|
||||
console.error('Error fetching locations:', error);
|
||||
return [];
|
||||
@@ -146,7 +149,8 @@ export async function getLocations() {
|
||||
|
||||
export async function getServices() {
|
||||
try {
|
||||
return await sql`SELECT * FROM services ORDER BY display_order ASC`;
|
||||
const services = await sql`SELECT * FROM services ORDER BY display_order ASC`;
|
||||
return services;
|
||||
} catch (error) {
|
||||
console.error('Error fetching services:', error);
|
||||
return [];
|
||||
|
||||
@@ -25,12 +25,27 @@ export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
||||
|
||||
const title = `${location.name} ${service.title} | Muğla Dijital`;
|
||||
const description = `${location.name} bölgesinde profesyonel ${service.title.toLowerCase()} hizmetleri. Muğla Dijital Medya Ajansı ile markanızı zirveye taşıyın.`;
|
||||
const url = `https://mugladijitalmedya.com/services/${slug}/${locationSlug}`;
|
||||
|
||||
return {
|
||||
title,
|
||||
description,
|
||||
alternates: {
|
||||
canonical: `/services/${slug}/${locationSlug}`,
|
||||
canonical: url,
|
||||
},
|
||||
openGraph: {
|
||||
title,
|
||||
description,
|
||||
url,
|
||||
images: [
|
||||
{
|
||||
url: "https://mugladijitalmedya.com/og-image.jpg", // Default OG image
|
||||
width: 1200,
|
||||
height: 630,
|
||||
alt: title,
|
||||
}
|
||||
],
|
||||
type: 'website',
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -9,14 +9,34 @@ export async function generateMetadata({ params }: { params: Promise<{ slug: str
|
||||
if (!data) return {};
|
||||
|
||||
const { project } = data;
|
||||
const url = `https://mugladijitalmedya.com/works/${slug}`;
|
||||
|
||||
return {
|
||||
title: project.title,
|
||||
description: project.subtitle,
|
||||
openGraph: {
|
||||
title: `${project.title} | Muğla Dijital`,
|
||||
description: project.subtitle,
|
||||
images: [project.hero_image],
|
||||
alternates: {
|
||||
canonical: url,
|
||||
},
|
||||
openGraph: {
|
||||
title: `${project.title} | Proje Detayı | Muğla Dijital`,
|
||||
description: project.subtitle,
|
||||
url: url,
|
||||
images: [
|
||||
{
|
||||
url: project.hero_image,
|
||||
width: 1200,
|
||||
height: 630,
|
||||
alt: project.title,
|
||||
}
|
||||
],
|
||||
type: 'article',
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
title: project.title,
|
||||
description: project.subtitle,
|
||||
images: [project.hero_image],
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,8 @@ function ProjectCard({ hero_image, category, title, year, subtitle, slug, index
|
||||
src={hero_image || "https://images.unsplash.com/photo-1550745165-9bc0b252726f"}
|
||||
alt={title}
|
||||
fill
|
||||
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
|
||||
priority={index < 3}
|
||||
className="object-cover transition-all duration-700 grayscale group-hover:grayscale-0"
|
||||
/>
|
||||
</motion.div>
|
||||
|
||||
Reference in New Issue
Block a user