iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

PWA

Ionic apps are web apps wrapped in Capacitor for native targets, which means the same codebase ships as a Progressive Web App with almost no extra work. PWA gives you: an installable home-screen icon, offline service-worker caching, push notifications (Android/desktop), and a Lighthouse-friendly score that helps SEO.

PWA manifest, service worker, and install prompt

EXAMPLE
// 1) manifest.webmanifest — describes the installable app
{
  "name": "Shop",
  "short_name": "Shop",
  "description": "Lightweight Shop client",
  "start_url": "/",
  "display": "standalone",
  "orientation": "portrait",
  "background_color": "#ffffff",
  "theme_color": "#2563eb",
  "icons": [
    { "src": "/icons/192.png", "sizes": "192x192", "type": "image/png" },
    { "src": "/icons/512.png", "sizes": "512x512", "type": "image/png" },
    { "src": "/icons/maskable-512.png", "sizes": "512x512", "type": "image/png",
      "purpose": "maskable" }
  ]
}

<!-- index.html: link the manifest and theme colour -->
<link rel='manifest' href='/manifest.webmanifest'>
<meta name='theme-color' content='#2563eb'>

// 2) service-worker.ts (Workbox-style) — cache shell + runtime cache
import { precacheAndRoute } from 'workbox-precaching';
import { registerRoute } from 'workbox-routing';
import { CacheFirst, StaleWhileRevalidate, NetworkFirst } from 'workbox-strategies';
import { ExpirationPlugin } from 'workbox-expiration';

precacheAndRoute(self.__WB_MANIFEST);

registerRoute(
  ({ request }) => request.destination === 'image',
  new CacheFirst({
    cacheName: 'images',
    plugins: [new ExpirationPlugin({ maxEntries: 100, maxAgeSeconds: 30 * 24 * 60 * 60 })],
  }),
);

registerRoute(
  ({ url }) => url.pathname.startsWith('/api/'),
  new NetworkFirst({ cacheName: 'api', networkTimeoutSeconds: 3 }),
);

registerRoute(
  ({ request }) => ['style', 'script', 'worker'].includes(request.destination),
  new StaleWhileRevalidate({ cacheName: 'assets' }),
);

self.addEventListener('install', () => self.skipWaiting());
self.addEventListener('activate', () => self.clients.claim());

// 3) Register the service worker once the page is ready
// src/main.ts
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('/service-worker.js');
  });
}

// 4) Custom install prompt — beforeinstallprompt is Chrome/Edge only
let deferred: any = null;
window.addEventListener('beforeinstallprompt', (e: Event) => {
  e.preventDefault();
  deferred = e;
  showInstallButton();
});

document.getElementById('install-btn')?.addEventListener('click', async () => {
  if (!deferred) return;
  deferred.prompt();
  const choice = await deferred.userChoice;
  console.log(choice.outcome);    // 'accepted' or 'dismissed'
  deferred = null;
});

// 5) iOS install — Safari does not implement beforeinstallprompt.
//    Show your own instructions: 'Tap Share -> Add to Home Screen'.

Why it matters

Aim for a perfect 100 PWA Lighthouse score before shipping — Chrome will only offer the install prompt to users when the page passes its installability checks. A missing maskable icon, a non-HTTPS asset, or a missing start_url all silently disqualify you.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
// In index.html
<link rel="manifest" href="/manifest.json">
// Register a service worker. Ionic ships PWA-ready by default.
Try it Yourself »

Discussion

Loading…