aimbytes
Back to journalJournal / (012)
Mobile Development

Progressive webapps:developer guide

By AimBytesJune 20, 202516 min read

Master modern PWA development with advanced capabilities, offline-first strategies, push notifications, and native app-like experiences that rival mobile apps. Discover the latest PWA technologies and implementation patterns.

Progressive Web Apps

Progressive Web Apps have reached a new level of maturity, offering experiences that are virtually indistinguishable from native mobile applications. With enhanced browser APIs, improved performance capabilities, and better platform integration, PWAs are now a compelling alternative to traditional app development for many use cases.

PWA Evolution

The PWA landscape has evolved dramatically, with major platforms now providing first-class support for PWA installation, distribution, and integration. Modern PWAs leverage advanced web capabilities that bridge the gap between web and native applications.

Modern PWA Capabilities

  • Advanced offline functionality
  • Native-like navigation patterns
  • Device hardware access
  • Background synchronization
  • Push notifications
  • App store distribution

Platform Integration

  • iOS Safari enhanced support
  • Android Chrome improvements
  • Windows PWA integration
  • macOS standalone apps
  • Chrome OS native feel
  • Microsoft Store distribution

Advanced Service Worker Patterns

Service Workers remain the backbone of PWA functionality, but 2025 brings sophisticated patterns for caching, background processing, and seamless offline experiences. Understanding these patterns is crucial for building robust PWAs.

Advanced Service Worker Implementation
// Modern Service Worker with advanced caching strategies
import { precacheAndRoute, cleanupOutdatedCaches } from 'workbox-precaching';
import { registerRoute } from 'workbox-routing';
import { StaleWhileRevalidate, CacheFirst, NetworkFirst } from 'workbox-strategies';
import { BackgroundSync } from 'workbox-background-sync';

// Precache static assets
precacheAndRoute(self.__WB_MANIFEST);
cleanupOutdatedCaches();

// Cache Strategy 1: Static assets (images, fonts, etc.)
registerRoute(
  ({ request }) => 
    request.destination === 'image' || 
    request.destination === 'font',
  new CacheFirst({
    cacheName: 'static-assets',
    plugins: [{
      cacheKeyWillBeUsed: async ({ request }) => {
        return request.url + '?version=2025.1';
      }
    }]
  })
);

// Cache Strategy 2: API responses with network-first
registerRoute(
  ({ url }) => url.pathname.startsWith('/api/'),
  new NetworkFirst({
    cacheName: 'api-cache',
    networkTimeoutSeconds: 3,
    plugins: [{
      cacheWillUpdate: async ({ response }) => {
        return response.status === 200 ? response : null;
      }
    }]
  })
);

// Cache Strategy 3: Pages with stale-while-revalidate
registerRoute(
  ({ request }) => request.mode === 'navigate',
  new StaleWhileRevalidate({
    cacheName: 'pages-cache',
    plugins: [{
      cachedResponseWillBeUsed: async ({ cachedResponse }) => {
        if (cachedResponse) {
          // Add custom headers to indicate cached response
          const response = cachedResponse.clone();
          response.headers.set('X-Served-From', 'Cache');
          return response;
        }
        return null;
      }
    }]
  })
);

// Background Sync for failed requests
const bgSync = new BackgroundSync('api-sync', {
  maxRetentionTime: 24 * 60 // 24 hours
});

registerRoute(
  ({ url }) => url.pathname.startsWith('/api/sync/'),
  async ({ event }) => {
    try {
      const response = await fetch(event.request.clone());
      return response;
    } catch (error) {
      await bgSync.replayWhenOnline(event.request);
      return Response.json({ queued: true }, { status: 202 });
    }
  },
  'POST'
);

// Advanced Push Notification Handling
self.addEventListener('push', (event) => {
  const options = {
    body: event.data.text(),
    icon: '/icons/notification-icon.png',
    badge: '/icons/badge-icon.png',
    tag: 'notification-tag',
    actions: [
      { action: 'view', title: 'View' },
      { action: 'dismiss', title: 'Dismiss' }
    ],
    data: {
      url: '/dashboard',
      timestamp: Date.now()
    }
  };

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

// Handle notification clicks
self.addEventListener('notificationclick', (event) => {
  event.notification.close();
  
  if (event.action === 'view') {
    event.waitUntil(
      clients.openWindow(event.notification.data.url)
    );
  }
});

Enhanced Web App Manifest

The Web App Manifest has been enhanced with new capabilities that enable better platform integration, improved user experiences, and more native-like behaviors. These enhancements are crucial for creating PWAs that feel truly native.

Offline-First Architecture

Modern PWAs embrace offline-first architecture principles, ensuring that applications work seamlessly regardless of network connectivity. This approach requires careful planning of data synchronization, conflict resolution, and user experience patterns.

Offline Support

App functionality available offline

Sync Success

Data synchronization accuracy

Performance

Fast offline load times

Security and Performance

PWA security and performance have become more critical as these applications handle sensitive data and compete directly with native apps. Modern PWAs implement comprehensive security measures and optimization techniques.

PWA Security Implementation
// Content Security Policy for PWAs
const cspHeader = {
  'Content-Security-Policy': [
    "default-src 'self'",
    "script-src 'self' 'unsafe-inline' https://apis.google.com",
    "style-src 'self' 'unsafe-inline' https://fonts.googleapis.com",
    "font-src 'self' https://fonts.gstatic.com",
    "img-src 'self' data: https:",
    "connect-src 'self' https://api.example.com wss://ws.example.com",
    "manifest-src 'self'",
    "worker-src 'self'"
  ].join('; ')
};

// Implement HTTPS everywhere
if (location.protocol !== 'https:' && location.hostname !== 'localhost') {
  location.replace('https:' + window.location.href.substring(window.location.protocol.length));
}

// Secure storage for sensitive data
class SecureStorage {
  static async setItem(key: string, value: any): Promise<void> {
    const encrypted = await this.encrypt(JSON.stringify(value));
    localStorage.setItem(key, encrypted);
  }

  static async getItem(key: string): Promise<any> {
    const encrypted = localStorage.getItem(key);
    if (!encrypted) return null;
    
    const decrypted = await this.decrypt(encrypted);
    return JSON.parse(decrypted);
  }

  private static async encrypt(text: string): Promise<string> {
    const encoder = new TextEncoder();
    const data = encoder.encode(text);
    
    const key = await window.crypto.subtle.generateKey(
      { name: 'AES-GCM', length: 256 },
      true,
      ['encrypt', 'decrypt']
    );
    
    const iv = window.crypto.getRandomValues(new Uint8Array(12));
    const encrypted = await window.crypto.subtle.encrypt(
      { name: 'AES-GCM', iv },
      key,
      data
    );
    
    return btoa(JSON.stringify({
      encrypted: Array.from(new Uint8Array(encrypted)),
      iv: Array.from(iv),
      key: await window.crypto.subtle.exportKey('raw', key)
    }));
  }
}

// Performance monitoring
class PWAMetrics {
  static trackLoadTime(): void {
    window.addEventListener('load', () => {
      const loadTime = performance.now();
      this.sendMetric('load_time', loadTime);
    });
  }

  static trackCacheHitRate(): void {
    let cacheHits = 0;
    let totalRequests = 0;

    const originalFetch = window.fetch;
    window.fetch = async (...args) => {
      totalRequests++;
      const response = await originalFetch(...args);
      
      if (response.headers.get('X-Served-From') === 'Cache') {
        cacheHits++;
      }
      
      this.sendMetric('cache_hit_rate', cacheHits / totalRequests);
      return response;
    };
  }

  private static sendMetric(name: string, value: number): void {
    navigator.sendBeacon('/analytics', JSON.stringify({
      metric: name,
      value,
      timestamp: Date.now()
    }));
  }
}

Future of PWAs

The future of PWAs looks incredibly promising, with continued platform support, enhanced capabilities, and growing adoption. Emerging technologies will further blur the lines between web and native applications.

Not sure your app is production-ready?

Send us your link. Within 2 working days you'll get a short screen recording showing 10 security and speed checks on your live app. Free, no call needed.

Written by

AB

AimBytes

Founder-led product engineering studio, Gurugram

AimBytes audits, hardens and scales MVPs and AI-built apps on Next.js, React Native, Supabase and Postgres. Founder-led, with vetted specialists.