Tavo-IT Logo
Webentwicklung12 min Lesezeit2025-06-12

Next.js PerformanceOptimization

Optimierung von Next.js-Anwendungen für maximale Performance und SEO – Best Practices, Techniken und Tools für moderne Web-Anwendungen.

Next.jsPerformanceSEOWeb VitalsOptimization

Performance in Next.js

Next.js bietet viele eingebaute Performance-Optimierungen, aber um das Maximum herauszuholen, müssen wir zusätzliche Techniken und Best Practices anwenden. Performance ist nicht nur für die Benutzererfahrung wichtig, sondern auch ein Ranking-Faktor für Suchmaschinen.

  • Automatische Optimierungen: Code Splitting, Image Optimization, Font Optimization
  • Rendering-Strategien: SSR, SSG, ISR für optimale Performance
  • Bundle-Optimierung: Tree Shaking, Minimierung, Compression
  • Caching: HTTP Caching, CDN, Browser Cache

📊 Core Web Vitals

Google's Core Web Vitals sind entscheidende Metriken für die Benutzererfahrung:

LCP (Largest Contentful Paint)

Sollte unter 2.5 Sekunden liegen

FID (First Input Delay)

Sollte unter 100 Millisekunden liegen

CLS (Cumulative Layout Shift)

Sollte unter 0.1 liegen

Next.js Web Vitals messen:

// pages/_app.js
export function reportWebVitals(metric) {
  console.log(metric);
  
  // Google Analytics
  if (metric.label === 'web-vital') {
    gtag('event', metric.name, {
      value: Math.round(metric.name === 'CLS' ? metric.value * 1000 : metric.value),
      event_label: metric.id,
      non_interaction: true,
    });
  }
}

🖼️ Image Optimization

Next.js Image-Komponente bietet automatische Optimierungen:

Optimierte Image-Komponente:

import Image from 'next/image';

// Basis-Verwendung
<Image
  src="/hero-image.jpg"
  alt="Hero Image"
  width={800}
  height={600}
  priority // Für above-the-fold Bilder
  placeholder="blur"
  blurDataURL="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQ..."
/>

// Responsive Bilder
<Image
  src="/responsive-image.jpg"
  alt="Responsive Image"
  fill
  sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
  style={{ objectFit: 'cover' }}
/>

Image-Konfiguration:

// next.config.js
module.exports = {
  images: {
    formats: ['image/webp', 'image/avif'],
    deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
    imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
    domains: ['example.com', 'cdn.example.com'],
  },
}

📦 Code Splitting & Lazy Loading

Reduziere die initiale Bundle-Größe durch intelligentes Code Splitting:

Dynamic Imports:

import dynamic from 'next/dynamic';
import { Suspense } from 'react';

// Lazy Loading für Komponenten
const HeavyComponent = dynamic(() => import('../components/HeavyComponent'), {
  loading: () => <div>Loading...</div>,
  ssr: false // Nur client-side laden
});

// Lazy Loading für Libraries
const loadChart = async () => {
  const { Chart } = await import('chart.js');
  return Chart;
};

// Route-basiertes Code Splitting (automatisch in Next.js)
// pages/dashboard.js wird nur geladen wenn Route besucht wird

React Suspense:

import { Suspense, lazy } from 'react';

const LazyComponent = lazy(() => import('./LazyComponent'));

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <LazyComponent />
    </Suspense>
  );
}

💾 Caching Strategien

HTTP Headers optimieren:

// next.config.js
module.exports = {
  async headers() {
    return [
      {
        source: '/static/(.*)',
        headers: [
          {
            key: 'Cache-Control',
            value: 'public, max-age=31536000, immutable',
          },
        ],
      },
      {
        source: '/api/(.*)',
        headers: [
          {
            key: 'Cache-Control',
            value: 'public, s-maxage=60, stale-while-revalidate=30',
          },
        ],
      },
    ];
  },
};

ISR (Incremental Static Regeneration):

// pages/products/[id].js
export async function getStaticProps({ params }) {
  const product = await fetchProduct(params.id);
  
  return {
    props: { product },
    revalidate: 60, // Revalidate every 60 seconds
  };
}

export async function getStaticPaths() {
  return {
    paths: [],
    fallback: 'blocking', // Generate pages on-demand
  };
}

🏗️ SSR vs. SSG Optimierung

Wähle die richtige Rendering-Strategie:

Static Site Generation (SSG)

  • • Beste Performance
  • • Ideal für statische Inhalte
  • • SEO-optimiert
  • • CDN-freundlich

Server-Side Rendering (SSR)

  • • Immer aktuelle Daten
  • • Personalisierte Inhalte
  • • Längere TTFB
  • • Server-Last

🔍 Bundle Analyse

Bundle Analyzer installieren:

npm install --save-dev @next/bundle-analyzer

// next.config.js
const withBundleAnalyzer = require('@next/bundle-analyzer')({
  enabled: process.env.ANALYZE === 'true',
});

module.exports = withBundleAnalyzer({
  // Ihre Next.js Konfiguration
});

// Package.json Script hinzufügen
"analyze": "ANALYZE=true next build"

Webpack Bundle Optimizer:

// next.config.js
module.exports = {
  webpack: (config, { isServer }) => {
    // Remove unnecessary polyfills
    config.resolve.fallback = { fs: false, path: false };
    
    // Optimize bundle splitting
    if (!isServer) {
      config.optimization.splitChunks.cacheGroups = {
        ...config.optimization.splitChunks.cacheGroups,
        vendor: {
          test: /[\/]node_modules[\/]/,
          name: 'vendors',
          chunks: 'all',
        },
      };
    }
    
    return config;
  },
};

📈 Performance Monitoring

Real User Monitoring (RUM):

// lib/analytics.js
export function trackWebVitals(metric) {
  const analyticsId = process.env.NEXT_PUBLIC_ANALYTICS_ID;
  
  if (analyticsId) {
    // Google Analytics
    gtag('event', metric.name, {
      event_category: 'Web Vitals',
      event_label: metric.id,
      value: Math.round(metric.name === 'CLS' ? metric.value * 1000 : metric.value),
      non_interaction: true,
    });
  }
  
  // Custom Analytics
  fetch('/api/analytics', {
    method: 'POST',
    body: JSON.stringify(metric),
    headers: { 'Content-Type': 'application/json' },
  });
}

Performance API nutzen:

// Performance-Metriken sammeln
useEffect(() => {
  const observer = new PerformanceObserver((list) => {
    list.getEntries().forEach((entry) => {
      if (entry.entryType === 'navigation') {
        console.log('Page Load Time:', entry.loadEventEnd - entry.fetchStart);
      }
      
      if (entry.entryType === 'paint') {
        console.log(entry.name + ':', entry.startTime);
      }
    });
  });
  
  observer.observe({ entryTypes: ['navigation', 'paint'] });
}, []);

Best Practices

  • Preload kritische Ressourcen: Verwende <link rel="preload"> für wichtige Assets
  • Font-Optimierung: Nutze next/font für automatische Font-Optimierung
  • Third-Party Scripts: Verwende next/script mit strategy="lazyOnload"
  • API-Optimierung: Implementiere effiziente API-Routes mit Caching
  • Database-Optimierung: Verwende Connection Pooling und optimierte Queries
  • Prefetching: Nutze Next.js Link Prefetching für bessere Navigation
  • Service Worker: Implementiere für erweiterte Caching-Strategien
  • Compression: Aktiviere gzip/brotli Compression auf Server-Ebene