关于 pwa
面向开发可安装且支持离线行为的渐进式 Web 应用的参考技能,介绍清单文件、Workbox Service Worker、缓存策略和安装提示。
主要功能
- 01Web App Manifest 配置
- 02Workbox Service Worker 模式
- 03离线回退处理
- 04缓存策略选择
- 05安装提示处理
- 06生产就绪检查清单
适用场景
- 01为 Web 应用添加离线访问
- 02合理缓存静态资源和动态数据
- 03实现应用安装提示
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ claude-dev-suite/ claude-dev-suite --skill pwa安装后在 Claude Code 中输入/pwa确认已加载。
详细介绍
渐进式 Web 应用
Web 应用清单
{
"name": "My App",
"short_name": "MyApp",
"start_url": "/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#000000",
"icons": [
{ "src": "/icons/192.png", "sizes": "192x192", "type": "image/png" },
{ "src": "/icons/512.png", "sizes": "512x512", "type": "image/png", "purpose": "any maskable" }
]
}
<link rel="manifest" href="/manifest.json" />
<meta name="theme-color" content="#000000" />
<link rel="apple-touch-icon" href="/icons/192.png" />
Service Worker(Workbox — 推荐)
// sw.ts (using Workbox)
import { precacheAndRoute } from 'workbox-precaching';
import { registerRoute } from 'workbox-routing';
import { CacheFirst, NetworkFirst, StaleWhileRevalidate } from 'workbox-strategies';
import { ExpirationPlugin } from 'workbox-expiration';
// Precache app shell
precacheAndRoute(self.__WB_MANIFEST);
// Cache-first for static assets
registerRoute(
({ request }) => request.destination === 'image' || request.destination === 'font',
new CacheFirst({
cacheName: 'static-assets',
plugins: [new ExpirationPlugin({ maxEntries: 100, maxAgeSeconds: 30 * 24 * 60 * 60 })],
})
);
// Network-first for API calls
registerRoute(
({ url }) => url.pathname.startsWith('/api/'),
new NetworkFirst({
cacheName: 'api-cache',
plugins: [new ExpirationPlugin({ maxEntries: 50, maxAgeSeconds: 5 * 60 })],
})
);
// Stale-while-revalidate for pages
registerRoute(
({ request }) => request.mode === 'navigate',
new StaleWhileRevalidate({ cacheName: 'pages' })
);
注册
if ('serviceWorker' in navigator) {
window.addEventListener('load', async () => {
const registration = await navigator.serviceWorker.register('/sw.js');
console.log('SW registered:', registration.scope);
});
}
离线回退
// In service worker
import { setCatchHandler } from 'workbox-routing';
setCatchHandler(async ({ event }) => {
if (event.request.destination === 'document') {
return caches.match('/offline.html');
}
return Response.error();
});
缓存策略
| 策略 | 用途 | 新鲜度 |
|---|---|---|
| 缓存优先 | 静态资源、字体、图像 | 可接受过时 |
| 网络优先 | API 数据、动态页面 | 优先保持最新 |
| 边用边更新 | 半动态内容 | 可接受过时,正在更新 |
| 仅网络 | 身份验证、POST 请求 | 始终保持最新 |
| 仅缓存 | 预缓存的应用外壳 | 不可变 |
安装提示
let deferredPrompt: BeforeInstallPromptEvent | null = null;
window.addEventListener('beforeinstallprompt', (e) => {
e.preventDefault();
deferredPrompt = e;
showInstallButton();
});
async function installApp() {
if (!deferredPrompt) return;
deferredPrompt.prompt();
const { outcome } = await deferredPrompt.userChoice;
console.log(`Install ${outcome}`);
deferredPrompt = null;
}
反模式
| 反模式 | 修复方法 |
|---|---|
| 使用缓存优先策略缓存所有内容 | 对动态数据使用网络优先策略 |
| 没有离线回退页面 | 预缓存一个 offline.html |
| 没有缓存过期机制 | 使用带有 maxEntries/maxAge 的 ExpirationPlugin |
| Service Worker 缓存身份验证令牌 | 切勿缓存敏感数据 |
| 没有 Service Worker 更新策略 | 使用 skipWaiting() 并提示用户刷新 |
生产环境检查清单
- 包含图标和主题的 Web 应用清单
- 使用 Workbox 策略的 Service Worker
- 离线回退页面
- 缓存过期策略
- 安装提示体验
- Lighthouse PWA 审核通过
评论
支持 Markdown