From 312ee2032014d2e0ba235d54be2a88a9bec4d87f Mon Sep 17 00:00:00 2001 From: AyrisAI Date: Sat, 16 May 2026 01:19:29 +0300 Subject: [PATCH] perf: apply Vercel Next.js best practices (caching, image optimization, metadata) --- app/actions.ts | 26 ++++++++++++++----------- app/services/[slug]/[location]/page.tsx | 17 +++++++++++++++- app/works/[slug]/page.tsx | 26 ++++++++++++++++++++++--- components/SelectedWorks.tsx | 2 ++ 4 files changed, 56 insertions(+), 15 deletions(-) diff --git a/app/actions.ts b/app/actions.ts index a075689..4a5e6cc 100644 --- a/app/actions.ts +++ b/app/actions.ts @@ -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 []; diff --git a/app/services/[slug]/[location]/page.tsx b/app/services/[slug]/[location]/page.tsx index 9604447..d2fbe31 100644 --- a/app/services/[slug]/[location]/page.tsx +++ b/app/services/[slug]/[location]/page.tsx @@ -25,12 +25,27 @@ export async function generateMetadata({ params }: Props): Promise { 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', } }; } diff --git a/app/works/[slug]/page.tsx b/app/works/[slug]/page.tsx index a203384..83e8afe 100644 --- a/app/works/[slug]/page.tsx +++ b/app/works/[slug]/page.tsx @@ -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, + title: `${project.title} | Muğla Dijital`, description: project.subtitle, + alternates: { + canonical: url, + }, openGraph: { - title: `${project.title} | Muğla Dijital`, + 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], - }, + } }; } diff --git a/components/SelectedWorks.tsx b/components/SelectedWorks.tsx index 98cbdcc..6dbf1f6 100644 --- a/components/SelectedWorks.tsx +++ b/components/SelectedWorks.tsx @@ -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" />