Service Worker & PWA: Web-Apps wie native Apps | Enjyn Gruppe
Hallo Welt
Hallo Welt
Original Lingva Deutsch
Übersetzung wird vorbereitet...
Dieser Vorgang kann bis zu 60 Sekunden dauern.
Diese Seite wird erstmalig übersetzt und dann für alle Besucher gespeichert.
0%
DE Zurück zu Deutsch
Übersetzung durch Lingva Translate

235 Dokumentationen verfügbar

Wissensdatenbank

Service Worker PWA Grundlagen

Zuletzt aktualisiert: 20.01.2026 um 10:04 Uhr

Service Worker & PWA: Web-Apps wie native Apps

Progressive Web Apps (PWAs) bringen native App-Features ins Web. Offline-Support, Push-Benachrichtigungen und Installation – alles mit Service Workern möglich.

Was ist ein Service Worker?

Ein Service Worker ist ein JavaScript, das im Hintergrund läuft – getrennt von der Webseite. Er kann:

  • Netzwerk-Anfragen abfangen und cachen
  • Offline-Funktionalität ermöglichen
  • Push-Benachrichtigungen empfangen
  • Hintergrund-Synchronisation durchführen

Service Worker registrieren

// main.js - Service Worker registrieren
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('/sw.js')
      .then(registration => {
        console.log('SW registriert:', registration.scope);
      })
      .catch(error => {
        console.log('SW Registrierung fehlgeschlagen:', error);
      });
  });
}

Service Worker Lebenszyklus

// sw.js - Service Worker

const CACHE_NAME = 'my-app-v1';
const urlsToCache = [
  '/',
  '/styles.css',
  '/script.js',
  '/offline.html'
];

// 1. Install Event - Dateien cachen
self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(cache => {
        console.log('Cache geöffnet');
        return cache.addAll(urlsToCache);
      })
  );
});

// 2. Activate Event - Alte Caches löschen
self.addEventListener('activate', event => {
  event.waitUntil(
    caches.keys().then(cacheNames => {
      return Promise.all(
        cacheNames.map(cacheName => {
          if (cacheName !== CACHE_NAME) {
            console.log('Alter Cache gelöscht:', cacheName);
            return caches.delete(cacheName);
          }
        })
      );
    })
  );
});

// 3. Fetch Event - Anfragen abfangen
self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request)
      .then(response => {
        // Cache hit - return response
        if (response) {
          return response;
        }
        // Nicht im Cache - Netzwerk anfragen
        return fetch(event.request);
      })
  );
});

Caching-Strategien

Cache First (Offline First)

// Erst Cache, dann Netzwerk
self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request)
      .then(response => response || fetch(event.request))
  );
});

Network First

// Erst Netzwerk, Cache als Fallback
self.addEventListener('fetch', event => {
  event.respondWith(
    fetch(event.request)
      .then(response => {
        // Erfolgreiche Antwort cachen
        const responseClone = response.clone();
        caches.open(CACHE_NAME).then(cache => {
          cache.put(event.request, responseClone);
        });
        return response;
      })
      .catch(() => caches.match(event.request))
  );
});

Stale While Revalidate

// Cache sofort liefern, im Hintergrund aktualisieren
self.addEventListener('fetch', event => {
  event.respondWith(
    caches.open(CACHE_NAME).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;
      });
    })
  );
});

Web App Manifest

Das Manifest macht aus der Website eine installierbare PWA:

// manifest.json
{
  "name": "Meine App",
  "short_name": "App",
  "description": "Eine tolle Progressive Web App",
  "start_url": "/",
  "display": "standalone",
  "background_color": "#ffffff",
  "theme_color": "#3b82f6",
  "icons": [
    {
      "src": "/icons/icon-192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "/icons/icon-512.png",
      "sizes": "512x512",
      "type": "image/png"
    },
    {
      "src": "/icons/icon-512-maskable.png",
      "sizes": "512x512",
      "type": "image/png",
      "purpose": "maskable"
    }
  ]
}

Manifest einbinden

<!-- Im <head> -->
<link rel="manifest" href="/manifest.json">
<meta name="theme-color" content="#3b82f6">

<!-- iOS-spezifisch -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<link rel="apple-touch-icon" href="/icons/icon-192.png">

Offline-Seite

// sw.js - Offline Fallback
self.addEventListener('fetch', event => {
  if (event.request.mode === 'navigate') {
    event.respondWith(
      fetch(event.request)
        .catch(() => caches.match('/offline.html'))
    );
  }
});

Push-Benachrichtigungen

Berechtigung anfragen

// main.js
async function subscribeToPush() {
  const permission = await Notification.requestPermission();
  if (permission !== 'granted') return;

  const registration = await navigator.serviceWorker.ready;
  const subscription = await registration.pushManager.subscribe({
    userVisibleOnly: true,
    applicationServerKey: urlBase64ToUint8Array(PUBLIC_VAPID_KEY)
  });

  // Subscription an Server senden
  await fetch('/api/push-subscribe', {
    method: 'POST',
    body: JSON.stringify(subscription),
    headers: { 'Content-Type': 'application/json' }
  });
}

Push empfangen

// sw.js
self.addEventListener('push', event => {
  const data = event.data.json();

  const options = {
    body: data.body,
    icon: '/icons/icon-192.png',
    badge: '/icons/badge.png',
    vibrate: [100, 50, 100],
    data: { url: data.url }
  };

  event.waitUntil(
    self.registration.showNotification(data.title, options)
  );
});

// Klick auf Benachrichtigung
self.addEventListener('notificationclick', event => {
  event.notification.close();
  event.waitUntil(
    clients.openWindow(event.notification.data.url)
  );
});

Workbox (Google Library)

Vereinfacht Service Worker Entwicklung:

// sw.js mit Workbox
importScripts('https://storage.googleapis.com/workbox-cdn/releases/6.5.4/workbox-sw.js');

// Cache First für Bilder
workbox.routing.registerRoute(
  ({request}) => request.destination === 'image',
  new workbox.strategies.CacheFirst({
    cacheName: 'images',
    plugins: [
      new workbox.expiration.ExpirationPlugin({
        maxEntries: 60,
        maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Tage
      }),
    ],
  })
);

// Network First für API
workbox.routing.registerRoute(
  ({url}) => url.pathname.startsWith('/api/'),
  new workbox.strategies.NetworkFirst({
    cacheName: 'api-cache',
  })
);

// Stale While Revalidate für CSS/JS
workbox.routing.registerRoute(
  ({request}) => request.destination === 'style' ||
                 request.destination === 'script',
  new workbox.strategies.StaleWhileRevalidate({
    cacheName: 'static-resources',
  })
);

PWA Checkliste

✅ PWA Requirements:
  • HTTPS (außer localhost)
  • Web App Manifest
  • Service Worker
  • Icons (min. 192x192 und 512x512)
  • Responsive Design
  • Offline-Funktionalität

Weitere Informationen

Enjix Beta

Enjyn AI Agent

Hallo 👋 Ich bin Enjix — wie kann ich dir helfen?
120