Πώς να Βελτιστοποιήσετε την Απόδοση του Next.js
Η απόδοση είναι κρίσιμη για την επιτυχία μιας web εφαρμογής. Το Next.js προσφέρει πολλά built-in εργαλεία για optimization, αλλά χρειάζεται να τα χρησιμοποιήσετε σωστά.
Image Optimization
Next.js Image Component
import Image from 'next/image'
function ProfilePicture() {
return (
<Image
src="/profile.jpg"
alt="Profile Picture"
width={500}
height={300}
priority // Για above-the-fold images
placeholder="blur" // Για καλύτερο UX
/>
)
}
Responsive Images
function ResponsiveImage() {
return (
<Image
src="/hero-image.jpg"
alt="Hero Image"
fill
style={{
objectFit: 'cover',
}}
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
/>
)
}
Code Splitting & Lazy Loading
Dynamic Imports
import dynamic from 'next/dynamic'
// Lazy load ένα component
const DynamicComponent = dynamic(() => import('../components/Heavy'), {
loading: () => <p>Φόρτωση...</p>,
})
// Lazy load με named export
const DynamicChart = dynamic(() => import('../components/Chart').then(mod => mod.Chart), {
ssr: false // Disable SSR αν χρειάζεται
})
Route-based Code Splitting
// pages/dashboard.js
import dynamic from 'next/dynamic'
const Analytics = dynamic(() => import('../components/Analytics'))
const Reports = dynamic(() => import('../components/Reports'))
export default function Dashboard() {
return (
<div>
<h1>Dashboard</h1>
<Analytics />
<Reports />
</div>
)
}
Caching Strategies
Static Generation (SSG)
// pages/blog/[slug].js
export async function getStaticProps({ params }) {
const post = await getPost(params.slug)
return {
props: { post },
revalidate: 60 * 60 * 24 // Revalidate κάθε 24 ώρες
}
}
export async function getStaticPaths() {
const posts = await getAllPosts()
return {
paths: posts.map(post => ({ params: { slug: post.slug } })),
fallback: 'blocking' // ή true για ISR
}
}
API Route Caching
// pages/api/posts.js
export default async function handler(req, res) {
// Set cache headers
res.setHeader(
'Cache-Control',
'public, s-maxage=60, stale-while-revalidate=300'
)
const posts = await getPosts()
res.json(posts)
}
Bundle Analysis
Webpack Bundle Analyzer
npm install --save-dev @next/bundle-analyzer
// next.config.js
const withBundleAnalyzer = require('@next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true',
})
module.exports = withBundleAnalyzer({
// Άλλες ρυθμίσεις
})
// package.json
{
"scripts": {
"analyze": "ANALYZE=true npm run build"
}
}
Font Optimization
Google Fonts με Next/Font
import { Inter, Roboto_Mono } from 'next/font/google'
const inter = Inter({
subsets: ['latin'],
display: 'swap',
})
const robotoMono = Roboto_Mono({
subsets: ['latin'],
display: 'swap',
})
export default function MyApp({ Component, pageProps }) {
return (
<main className={inter.className}>
<Component {...pageProps} />
</main>
)
}
Local Fonts
import localFont from 'next/font/local'
const myFont = localFont({
src: './my-font.woff2',
display: 'swap',
})
Database Optimization
Connection Pooling
// lib/db.js
import { Pool } from 'pg'
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
max: 20, // Maximum pool size
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 2000,
})
export default pool
Query Optimization
// Κακό - N+1 problem
const users = await getUsers()
for (const user of users) {
user.posts = await getPostsByUserId(user.id)
}
// Καλό - Batch loading
const users = await getUsers()
const userIds = users.map(user => user.id)
const posts = await getPostsByUserIds(userIds)
users.forEach(user => {
user.posts = posts.filter(post => post.userId === user.id)
})
Core Web Vitals
Largest Contentful Paint (LCP)
// Optimize LCP με priority loading
function Hero() {
return (
<div>
<Image
src="/hero.jpg"
alt="Hero"
width={1200}
height={600}
priority // Critical για LCP
/>
<h1>Welcome to our site</h1>
</div>
)
}
Cumulative Layout Shift (CLS)
// Καθορίστε dimensions για images
<Image
src="/image.jpg"
alt="Description"
width={400}
height={300}
style={{
maxWidth: '100%',
height: 'auto',
}}
/>
First Input Delay (FID)
// Lazy load non-critical JavaScript
useEffect(() => {
const loadAnalytics = async () => {
const analytics = await import('../lib/analytics')
analytics.init()
}
// Load μετά το initial render
setTimeout(loadAnalytics, 1000)
}, [])
Advanced Techniques
Prefetching
import Link from 'next/link'
function Navigation() {
return (
<nav>
<Link href="/dashboard" prefetch={false}>
Dashboard
</Link>
<Link href="/profile" prefetch>
Profile (prefetched)
</Link>
</nav>
)
}
Service Workers
// public/sw.js
const CACHE_NAME = 'my-app-v1'
self.addEventListener('fetch', event => {
if (event.request.destination === 'image') {
event.respondWith(
caches.match(event.request).then(response => {
return response || fetch(event.request)
})
)
}
})
Monitoring & Measurement
Web Vitals με Next.js
// pages/_app.js
export function reportWebVitals(metric) {
switch (metric.name) {
case 'FCP':
// First Contentful Paint
break
case 'LCP':
// Largest Contentful Paint
break
case 'CLS':
// Cumulative Layout Shift
break
case 'FID':
// First Input Delay
break
case 'TTFB':
// Time to First Byte
break
}
// Send to analytics
console.log(metric)
}
Συμπερασμάτα
Η βελτιστοποίηση της απόδοσης είναι μια συνεχής διαδικασία. Χρησιμοποιήστε εργαλεία όπως το Google PageSpeed Insights και το Lighthouse για να μετράτε την πρόοδό σας.
Βασικές αρχές:
- Μετρήστε πριν βελτιστοποιήσετε
- Εστιάστε στα Critical Path
- Χρησιμοποιήστε τα built-in εργαλεία του Next.js
- Κάντε regular performance audits
Χρειάζεστε βοήθεια με την optimization της εφαρμογής σας; Επικοινωνήστε μαζί μας για professional performance audit!