渐进式 Web 应用(PWA)实现指南:将网站变成可安装的 App

PWA(Progressive Web App)让网站拥有原生应用的体验:可安装到主屏幕、离线运行、推送通知。

PWA 核心组件

PWA 由三个核心组件构成:

  1. Manifest.json — 应用的元数据(图标、名称、主题色)
  2. Service Worker — 离线缓存、推送通知、后台同步
  3. HTTPS — PWA 必须通过 HTTPS 提供服务

第一步:配置 Manifest

{
  "name": "16IDC",
  "short_name": "16IDC",
  "description": "Cloud service comparison and website building guide",
  "start_url": "/",
  "display": "standalone",
  "background_color": "#ffffff",
  "theme_color": "#4F46E5",
  "icons": [
    {
      "src": "/icons/icon-192x192.png",
      "sizes": "192x192",
      "type": "image/png",
      "purpose": "any maskable"
    },
    {
      "src": "/icons/icon-512x512.png",
      "sizes": "512x512",
      "type": "image/png",
      "purpose": "any maskable"
    }
  ]
}

在 HTML 中引用 Manifest:

<link rel="manifest" href="/manifest.json">
<meta name="theme-color" content="#4F46E5">

第二步:注册 Service Worker

// main.js
if ('serviceWorker' in navigator) {
    window.addEventListener('load', async () => {
        try {
            const registration = await navigator.serviceWorker.register('/sw.js');
            console.log('ServiceWorker registered:', registration.scope);
        } catch (error) {
            console.log('ServiceWorker registration failed:', error);
        }
    });
}

第三步:Service Worker 缓存策略

// sw.js
const CACHE_NAME = 'v1';
const STATIC_ASSETS = [
    '/',
    '/styles.css',
    '/app.js',
    '/offline.html'
];

// 安装:预缓存静态资源
self.addEventListener('install', event => {
    event.waitUntil(
        caches.open(CACHE_NAME)
            .then(cache => cache.addAll(STATIC_ASSETS))
            .then(() => self.skipWaiting())
    );
});

// 激活:清理旧缓存
self.addEventListener('activate', event => {
    event.waitUntil(
        caches.keys().then(keys =>
            Promise.all(keys.map(key => {
                if (key !== CACHE_NAME) return caches.delete(key);
            }))
        ).then(() => self.clients.claim())
    );
});

// 拦截请求:缓存优先策略
self.addEventListener('fetch', event => {
    event.respondWith(
        caches.match(event.request)
            .then(cached => cached || fetch(event.request))
            .catch(() => caches.match('/offline.html'))
    );
});

缓存策略选择

策略 说明 适用场景
Cache First 优先使用缓存,无缓存时才请求网络 静态资源(CSS、JS、图片)
Network First 优先请求网络,失败时使用缓存 API 请求、动态页面
Stale While Revalidate 返回缓存,同时后台更新 不经常变化的内容
Network Only 始终请求网络 支付、表单提交
Cache Only 仅使用缓存 离线页面

离线页面

创建 offline.html,当用户离线访问时显示友好的提示:

<!DOCTYPE html>
<html>
<head>
    <title>您处于离线状态</title>
    <style>
        body { text-align: center; padding: 50px; font-family: system-ui; }
    </style>
</head>
<body>
    <h1>暂无网络连接</h1>
    <p>请检查您的网络连接后重试</p>
</body>
</html>

PWA 检测工具

  • LighthouseChrome DevTools 内置的 PWA 审计
  • PWABuilder — Microsoft 的 PWA 打包工具
  • PWA Checker — 在线 PWA 合规性检测

16IDC 观察

PWA 是提升网站用户体验性价比最高的方案之一。实现成本低(只需一个 Manifest 文件和一个 Service Worker),但可以显著提升用户参与度。建议所有内容型网站和工具型网站都考虑实现 PWA。