_CORE
AI & Agentic Systems Core Information Systems Cloud & Platform Engineering Data Platform & Integration Security & Compliance QA, Testing & Observability IoT, Automation & Robotics Mobile & Digital Banking & Finance Insurance Public Administration Defense & Security Healthcare Energy & Utilities Telco & Media Manufacturing Logistics & E-commerce Retail & Loyalty
References Technologies Blog Know-how Tools
About Collaboration Careers
CS EN
Let's talk

Progressive Web Apps (PWA) — A Complete Guide 2025

28. 02. 2022 3 min read beginner

A complete guide to building Progressive Web Apps. Service Workers, Web App Manifest, offline strategies, push notifications and device installation.

Introduction to PWA

Progressive Web Apps (PWAs) combine the best of web and mobile applications. They provide native-like experiences while remaining web applications that work across all devices and platforms.

Key PWA characteristics: - Progressive - Work for every user, regardless of browser choice - Responsive - Fit any form factor: desktop, mobile, tablet - Offline functionality - Work offline or with poor connectivity - App-like - Feel like native apps with app-style interactions - Secure - Served via HTTPS to prevent tampering - Installable - Can be installed on the home screen

Core Technologies

1. Web App Manifest

The manifest file provides metadata about your application:

{
  "name": "My PWA App",
  "short_name": "PWA App",
  "description": "A progressive web application",
  "start_url": "/",
  "display": "standalone",
  "theme_color": "#2196F3",
  "background_color": "#ffffff",
  "icons": [
    {
      "src": "/icons/icon-192x192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "/icons/icon-512x512.png",
      "sizes": "512x512",
      "type": "image/png"
    }
  ]
}

2. Service Workers

Service Workers enable offline functionality and background sync:

// Register service worker
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js')
    .then(registration => console.log('SW registered'))
    .catch(error => console.log('SW registration failed'));
}

// sw.js - Service Worker
const CACHE_NAME = 'my-pwa-v1';
const urlsToCache = [
  '/',
  '/styles/main.css',
  '/scripts/main.js',
  '/offline.html'
];

self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(cache => cache.addAll(urlsToCache))
  );
});

self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request)
      .then(response => {
        // Return cached version or fetch from network
        return response || fetch(event.request);
      })
      .catch(() => {
        // Return offline page for navigation requests
        if (event.request.destination === 'document') {
          return caches.match('/offline.html');
        }
      })
  );
});

3. Offline Strategies

Different caching strategies for different content types:

// Cache first - for static assets
self.addEventListener('fetch', event => {
  if (event.request.url.includes('/assets/')) {
    event.respondWith(
      caches.match(event.request)
        .then(response => response || fetch(event.request))
    );
  }
});

// Network first - for API data
self.addEventListener('fetch', event => {
  if (event.request.url.includes('/api/')) {
    event.respondWith(
      fetch(event.request)
        .then(response => {
          // Cache successful responses
          const responseClone = response.clone();
          caches.open(CACHE_NAME)
            .then(cache => cache.put(event.request, responseClone));
          return response;
        })
        .catch(() => caches.match(event.request))
    );
  }
});

Installation and App-like Experience

Install Prompt

Handle the install prompt programmatically:

let deferredPrompt;

window.addEventListener('beforeinstallprompt', e => {
  // Prevent Chrome 67 and earlier from showing prompt
  e.preventDefault();

  // Stash event for later trigger
  deferredPrompt = e;

  // Show install button
  showInstallButton();
});

function showInstallPrompt() {
  if (deferredPrompt) {
    deferredPrompt.prompt();
    deferredPrompt.userChoice.then(result => {
      if (result.outcome === 'accepted') {
        console.log('User accepted install');
      }
      deferredPrompt = null;
    });
  }
}

App Shell Architecture

Implement the app shell pattern for instant loading:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>My PWA</title>
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <link rel="manifest" href="/manifest.json">

  <!-- Critical CSS inlined -->
  <style>
    .app-shell { /* minimal shell styles */ }
  </style>
</head>
<body>
  <div class="app-shell">
    <header class="header">
      <!-- App header -->
    </header>
    <main class="main">
      <!-- Dynamic content loaded here -->
    </main>
    <nav class="navigation">
      <!-- App navigation -->
    </nav>
  </div>

  <script src="/js/app.js"></script>
</body>
</html>

Push Notifications

Implement push notifications for user engagement:

// Request permission
Notification.requestPermission().then(permission => {
  if (permission === 'granted') {
    subscribeToNotifications();
  }
});

// Subscribe to push notifications
function subscribeToNotifications() {
  navigator.serviceWorker.ready.then(registration => {
    return registration.pushManager.subscribe({
      userVisibleOnly: true,
      applicationServerKey: urlBase64ToUint8Array(publicVapidKey)
    });
  }).then(subscription => {
    // Send subscription to server
    fetch('/api/subscribe', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(subscription)
    });
  });
}

// Handle push events in service worker
self.addEventListener('push', event => {
  const options = {
    body: event.data.text(),
    icon: '/icons/icon-192x192.png',
    badge: '/icons/badge-72x72.png',
    actions: [
      { action: 'open', title: 'Open App' },
      { action: 'close', title: 'Close' }
    ]
  };

  event.waitUntil(
    self.registration.showNotification('PWA Notification', options)
  );
});

Best Practices

  1. Start with App Shell - Load core UI instantly
  2. Cache Strategy - Use appropriate strategies for different content
  3. Offline Experience - Provide meaningful offline functionality
  4. Performance - Optimize for mobile networks
  5. Progressive Enhancement - Work without service workers
  6. Install Experience - Guide users through installation

PWAs provide a powerful way to deliver app-like experiences on the web platform, combining the reach of web with the engagement of native applications.

pwaservice workerofflineweb app
Share:

CORE SYSTEMS tým

Stavíme core systémy a AI agenty, které drží provoz. 15 let zkušeností s enterprise IT.