perf: apply Vercel Next.js best practices (caching, image optimization, metadata)
This commit is contained in:
@@ -1,8 +1,9 @@
|
|||||||
'use server'
|
'use server'
|
||||||
|
import { cache } from 'react';
|
||||||
import sql from '@/lib/db';
|
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 {
|
try {
|
||||||
const settings = await sql`SELECT * FROM settings WHERE id = 1 LIMIT 1`;
|
const settings = await sql`SELECT * FROM settings WHERE id = 1 LIMIT 1`;
|
||||||
return settings[0] || null;
|
return settings[0] || null;
|
||||||
@@ -10,7 +11,7 @@ export async function getSettings() {
|
|||||||
console.error('Error fetching settings:', error);
|
console.error('Error fetching settings:', error);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
export async function getFeaturedServices() {
|
export async function getFeaturedServices() {
|
||||||
try {
|
try {
|
||||||
@@ -69,7 +70,7 @@ export async function getPartners() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getProjectBySlug(slug: string) {
|
export const getProjectBySlug = cache(async function(slug: string) {
|
||||||
try {
|
try {
|
||||||
const projects = await sql`SELECT * FROM projects WHERE slug = ${slug} LIMIT 1`;
|
const projects = await sql`SELECT * FROM projects WHERE slug = ${slug} LIMIT 1`;
|
||||||
if (projects.length === 0) return null;
|
if (projects.length === 0) return null;
|
||||||
@@ -96,8 +97,9 @@ export async function getProjectBySlug(slug: string) {
|
|||||||
console.error('Error fetching project:', error);
|
console.error('Error fetching project:', error);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
export async function getServiceBySlug(slug: string) {
|
|
||||||
|
export const getServiceBySlug = cache(async function(slug: string) {
|
||||||
try {
|
try {
|
||||||
const services = await sql`SELECT * FROM services WHERE slug = ${slug} LIMIT 1`;
|
const services = await sql`SELECT * FROM services WHERE slug = ${slug} LIMIT 1`;
|
||||||
return services[0] || null;
|
return services[0] || null;
|
||||||
@@ -105,9 +107,9 @@ export async function getServiceBySlug(slug: string) {
|
|||||||
console.error('Error fetching service:', error);
|
console.error('Error fetching service:', error);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
export async function getLocationBySlug(slug: string) {
|
export const getLocationBySlug = cache(async function(slug: string) {
|
||||||
try {
|
try {
|
||||||
const locations = await sql`SELECT * FROM locations WHERE slug = ${slug} LIMIT 1`;
|
const locations = await sql`SELECT * FROM locations WHERE slug = ${slug} LIMIT 1`;
|
||||||
return locations[0] || null;
|
return locations[0] || null;
|
||||||
@@ -115,7 +117,7 @@ export async function getLocationBySlug(slug: string) {
|
|||||||
console.error('Error fetching location:', error);
|
console.error('Error fetching location:', error);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
|
|
||||||
export async function getProjectsByService(serviceName: string) {
|
export async function getProjectsByService(serviceName: string) {
|
||||||
@@ -137,7 +139,8 @@ export async function getProjectsByService(serviceName: string) {
|
|||||||
|
|
||||||
export async function getLocations() {
|
export async function getLocations() {
|
||||||
try {
|
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) {
|
} catch (error) {
|
||||||
console.error('Error fetching locations:', error);
|
console.error('Error fetching locations:', error);
|
||||||
return [];
|
return [];
|
||||||
@@ -146,7 +149,8 @@ export async function getLocations() {
|
|||||||
|
|
||||||
export async function getServices() {
|
export async function getServices() {
|
||||||
try {
|
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) {
|
} catch (error) {
|
||||||
console.error('Error fetching services:', error);
|
console.error('Error fetching services:', error);
|
||||||
return [];
|
return [];
|
||||||
|
|||||||
@@ -25,12 +25,27 @@ export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
|||||||
|
|
||||||
const title = `${location.name} ${service.title} | Muğla Dijital`;
|
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 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 {
|
return {
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
alternates: {
|
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 {};
|
if (!data) return {};
|
||||||
|
|
||||||
const { project } = data;
|
const { project } = data;
|
||||||
|
const url = `https://mugladijitalmedya.com/works/${slug}`;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: project.title,
|
|
||||||
description: project.subtitle,
|
|
||||||
openGraph: {
|
|
||||||
title: `${project.title} | Muğla Dijital`,
|
title: `${project.title} | Muğla Dijital`,
|
||||||
description: project.subtitle,
|
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"}
|
src={hero_image || "https://images.unsplash.com/photo-1550745165-9bc0b252726f"}
|
||||||
alt={title}
|
alt={title}
|
||||||
fill
|
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"
|
className="object-cover transition-all duration-700 grayscale group-hover:grayscale-0"
|
||||||
/>
|
/>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|||||||
Reference in New Issue
Block a user