PWA(Progressive Web Apps)

Web 技術で作って「ネイティブアプリのように」振る舞わせる仕組み。 ホーム画面に追加、オフライン動作、プッシュ通知、フルスクリーン表示。
Service Worker + Web App Manifest + HTTPS の3点セット。

PWA でできること

PWA で難しい / できないこと

3 つの最低要件

  1. HTTPS(または localhost) — Service Worker は HTTPS でしか動かない
  2. Web App Manifest — アプリ名・アイコン・色・起動 URL の設定
  3. Service Worker — オフライン・キャッシュ・通知の中核

30 秒のメンタルモデル

  1. HTML から manifest.json をリンク
  2. JS で navigator.serviceWorker.register("/sw.js")
  3. SW が初回起動してinstall / activateのライフサイクルを通る
  4. 以降、fetch イベントで全リクエストを SW が intercept できる
  5. キャッシュ・オフライン・通知は SW の中で実装

最小コード

index.html
<link rel="manifest" href="/manifest.json" />
<meta name="theme-color" content="#0b0d12" />
<script>
  if ("serviceWorker" in navigator) {
    navigator.serviceWorker.register("/sw.js")
  }
</script>
manifest.json
{
  "name": "My PWA",
  "short_name": "MyPWA",
  "start_url": "/",
  "display": "standalone",
  "background_color": "#0b0d12",
  "theme_color": "#0b0d12",
  "icons": [
    { "src": "/icon-192.png", "sizes": "192x192", "type": "image/png" },
    { "src": "/icon-512.png", "sizes": "512x512", "type": "image/png" }
  ]
}
sw.js
self.addEventListener("install", () => self.skipWaiting())
self.addEventListener("activate", (e) => e.waitUntil(self.clients.claim()))

self.addEventListener("fetch", (e) => {
  e.respondWith(
    caches.match(e.request).then((cached) => cached || fetch(e.request))
  )
})

これだけで「PWA」を名乗れる土台は揃う。後は要件に応じてキャッシュ戦略・通知・オフラインを足す。

2026 春の周辺事情

このノートの読み方

  1. Web App Manifest でメタ情報設定
  2. Service Worker 基本 でライフサイクル
  3. キャッシュ で戦略(CacheFirst / NetworkFirst 等)
  4. オフライン で UX 設計
  5. インストール で beforeinstallprompt
  6. プッシュ通知 で Web Push
  7. バックグラウンド で Sync 系 API
  8. 注意点・iOS の制約 で本番の罠