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

330 Dokumentationen verfügbar

Wissensdatenbank

Service Worker PWA Grundlagen

Zuletzt aktualisiert: 14.07.2026 um 12:29 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

Texterstellung mit KI-Unterstützung

Enjix Beta

Enjyn AI Agent

Hallo 👋 Ich bin Enjix — wie kann ich dir helfen?
LLMs können Fehler machen. Ihre Nachrichten werden an Google Gemini weitergeleitet.
120