TL;DR
Zaawansowana optymalizacja wydajności to CDN, inteligentne caching, lazy loading i code splitting. Te techniki mogą poprawić czas ładowania o 50-80% i poprawić Core Web Vitals. Oto jak wdrożyć zaawansowaną optymalizację w 2026.
Dla kogo to jest
- Developerów optymalizujących wydajność stron
- Firm chcących poprawić Core Web Vitals
- Właścicieli stron z problemami wydajności
Fraza (SEO)
optymalizacja wydajności, cdn, caching, lazy loading, performance optimization
CDN (Content Delivery Network)
Czym jest CDN?
CDN to sieć serwerów rozproszonych geograficznie, które:
- Przechowują kopie statycznych zasobów
- Serwują je z najbliższego serwera
- Redukują latency
- Zmniejszają obciążenie głównego serwera
Główne CDN:
- Cloudflare (darmowy plan)
- Vercel Edge Network
- AWS CloudFront
- Fastly
Kiedy używać CDN?
Idealne dla:
- Statyczne pliki (CSS, JS, obrazy)
- Fonty
- Wideo
- Globalna audiencja
Korzyści:
- 30-50% szybsze ładowanie
- Lepsze Core Web Vitals
- Niższe koszty serwera
Implementacja
Vercel (automatyczne):
- Next.js automatycznie używa Edge Network
- Wszystkie statyczne pliki przez CDN
- Zero configuration
Cloudflare:
<!-- DNS setup -->
<!-- Cloudflare automatycznie cache'uje statyczne pliki -->
Custom CDN:
// Set Cache-Control headers
res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
Caching strategies
1. Browser Caching
Cache-Control headers:
// Statyczne pliki (obrazy, CSS, JS)
Cache-Control: public, max-age=31536000, immutable
// HTML (często zmienia się)
Cache-Control: public, max-age=3600, must-revalidate
// API responses (dynamiczne)
Cache-Control: private, max-age=300
Implementacja (Next.js):
// next.config.js
module.exports = {
async headers() {
return [
{
source: '/static/:path*',
headers: [
{
key: 'Cache-Control',
value: 'public, max-age=31536000, immutable',
},
],
},
];
},
};
2. Service Worker Caching
Strategie:
Cache First:
// Dla statycznych zasobów
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((response) => {
return response || fetch(event.request);
})
);
});
Network First:
// Dla dynamicznych danych
self.addEventListener('fetch', (event) => {
event.respondWith(
fetch(event.request).catch(() => {
return caches.match(event.request);
})
);
});
Stale While Revalidate:
// Dla często zmieniających się danych
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.open('v1').then((cache) => {
return cache.match(event.request).then((response) => {
const fetchPromise = fetch(event.request).then((networkResponse) => {
cache.put(event.request, networkResponse.clone());
return networkResponse;
});
return response || fetchPromise;
});
})
);
});
3. Server-Side Caching
Redis:
// Cache API responses
const cached = await redis.get(`api:${key}`);
if (cached) return JSON.parse(cached);
const data = await fetchData();
await redis.setex(`api:${key}`, 3600, JSON.stringify(data));
return data;
In-Memory Cache:
// Node.js memory cache
const cache = new Map();
function getCached(key) {
const cached = cache.get(key);
if (cached && cached.expires > Date.now()) {
return cached.data;
}
return null;
}
Lazy Loading
1. Images
Native lazy loading:
<img src="image.jpg" loading="lazy" alt="Description">
Intersection Observer:
const images = document.querySelectorAll('img[data-src]');
const imageObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
imageObserver.unobserve(img);
}
});
});
images.forEach(img => imageObserver.observe(img));
Next.js Image:
import Image from 'next/image';
<Image
src="/image.jpg"
alt="Description"
width={800}
height={600}
loading="lazy"
placeholder="blur"
/>
2. JavaScript
Dynamic imports:
// Lazy load component
const HeavyComponent = lazy(() => import('./HeavyComponent'));
<Suspense fallback={<Loading />}>
<HeavyComponent />
</Suspense>
Code splitting:
// Webpack automatic code splitting
import('./module').then(module => {
module.doSomething();
});
3. CSS
Critical CSS:
<!-- Inline critical CSS -->
<style>
/* Above-the-fold styles */
</style>
<!-- Lazy load rest -->
<link rel="preload" href="styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
Code Splitting
1. Route-based splitting
Next.js (automatic):
// Każda strona automatycznie splitowana
// pages/about.js → about.js bundle
// pages/contact.js → contact.js bundle
React Router:
const About = lazy(() => import('./pages/About'));
const Contact = lazy(() => import('./pages/Contact'));
2. Component-based splitting
React:
const Chart = lazy(() => import('./components/Chart'));
function Dashboard() {
return (
<Suspense fallback={<div>Loading chart...</div>}>
<Chart />
</Suspense>
);
}
3. Vendor splitting
Webpack:
// Split vendor libraries
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
},
},
},
}
Performance monitoring
1. Core Web Vitals
Metryki:
- LCP (Largest Contentful Paint) < 2.5s
- FID (First Input Delay) < 100ms
- CLS (Cumulative Layout Shift) < 0.1
Narzędzia:
- Google PageSpeed Insights
- Chrome DevTools Lighthouse
- Web Vitals Chrome Extension
2. Real User Monitoring (RUM)
Narzędzia:
- Google Analytics (Core Web Vitals)
- Vercel Analytics
- New Relic Browser
- Datadog RUM
3. Synthetic Monitoring
Narzędzia:
- Pingdom
- UptimeRobot
- StatusCake
Best practices
1. Minimize bundle size
Sposoby:
- Tree shaking
- Remove unused code
- Minification
- Compression (gzip, brotli)
2. Optimize images
Formaty:
- WebP (najlepszy)
- AVIF (najnowszy)
- Fallback do JPEG/PNG
Sizing:
- Responsive images (srcset)
- Proper dimensions
- Compression
3. Preload critical resources
<link rel="preload" href="/font.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/hero-image.jpg" as="image">
4. Defer non-critical JavaScript
<script src="analytics.js" defer></script>
<script src="chat-widget.js" defer></script>
FAQ
Jakie są najważniejsze metryki wydajności?
Core Web Vitals: LCP, FID, CLS. Dodatkowo: TTI (Time to Interactive), FCP (First Contentful Paint), TBT (Total Blocking Time).
Czy CDN jest zawsze potrzebny?
Dla globalnej audiencji tak. Dla lokalnej (jeden kraj) może nie być konieczny, ale nadal pomaga.
Jak często aktualizować cache?
Zależy od typu zasobu: statyczne pliki (1 rok), HTML (1 godzina), API (5 minut). Użyj odpowiednich Cache-Control headers.