Workbox 应用
约 833 字大约 3 分钟
PWAWorkbox
2026-04-08
什么是 Workbox
Workbox 是 Google 推出的一套 PWA 工具库,封装了 Service Worker 的常见场景(预缓存、路由、策略、过期管理、后台同步等),把原本几百行的 sw.js 缩减为几十行配置。
核心价值:
- 处理预缓存的版本管理与失效(自动生成 revision hash)
- 提供 5 种内置策略,一行代码对接
- 插件机制支持 LRU、TTL、Broadcast、Background Sync
- 与 Webpack/Vite/CLI/Rollup 等构建工具无缝集成
模块结构
| 包 | 用途 |
|---|---|
workbox-core | 基础设施,日志、cache 命名 |
workbox-precaching | 预缓存 |
workbox-routing | 路由注册 |
workbox-strategies | 缓存策略(CacheFirst/NetworkFirst...) |
workbox-expiration | LRU + TTL 过期管理 |
workbox-cacheable-response | 按状态码/header 筛选可缓存响应 |
workbox-background-sync | 失败请求队列重放 |
workbox-broadcast-update | 新版本通知 |
workbox-window | 主线程侧封装(注册、更新提示) |
手写 sw.js 使用 Workbox
// sw.js
import { precacheAndRoute, cleanupOutdatedCaches } from 'workbox-precaching';
import { registerRoute, setCatchHandler } from 'workbox-routing';
import {
CacheFirst,
NetworkFirst,
StaleWhileRevalidate
} from 'workbox-strategies';
import { ExpirationPlugin } from 'workbox-expiration';
import { CacheableResponsePlugin } from 'workbox-cacheable-response';
import { BackgroundSyncPlugin } from 'workbox-background-sync';
self.skipWaiting();
clientsClaim();
// 1. 预缓存(self.__WB_MANIFEST 由构建工具注入)
precacheAndRoute(self.__WB_MANIFEST || []);
cleanupOutdatedCaches();
// 2. HTML 导航:Network First
registerRoute(
({ request }) => request.mode === 'navigate',
new NetworkFirst({
cacheName: 'pages',
networkTimeoutSeconds: 3,
plugins: [new CacheableResponsePlugin({ statuses: [200] })]
})
);
// 3. 静态资源:Stale While Revalidate
registerRoute(
({ request }) => ['style', 'script', 'worker'].includes(request.destination),
new StaleWhileRevalidate({ cacheName: 'assets' })
);
// 4. 图片:Cache First + LRU
registerRoute(
({ request }) => request.destination === 'image',
new CacheFirst({
cacheName: 'images',
plugins: [
new CacheableResponsePlugin({ statuses: [0, 200] }),
new ExpirationPlugin({
maxEntries: 60,
maxAgeSeconds: 30 * 24 * 60 * 60,
purgeOnQuotaError: true
})
]
})
);
// 5. API:Background Sync 重放失败的 POST
const bgSyncPlugin = new BackgroundSyncPlugin('api-queue', { maxRetentionTime: 24 * 60 });
registerRoute(
({ url }) => url.pathname.startsWith('/api/'),
new NetworkFirst({ plugins: [bgSyncPlugin] }),
'POST'
);
// 6. 离线兜底
setCatchHandler(async ({ request }) => {
if (request.destination === 'document') {
return caches.match('/offline.html');
}
return Response.error();
});构建工具集成
Vite(vite-plugin-pwa)
// vite.config.ts
import { defineConfig } from 'vite';
import { VitePWA } from 'vite-plugin-pwa';
export default defineConfig({
plugins: [
VitePWA({
registerType: 'autoUpdate', // 或 'prompt'
strategies: 'generateSW', // 或 'injectManifest' 用自己的 sw.js
manifest: {
name: 'ZhenYu Knowledge',
short_name: 'KB',
theme_color: '#4285f4',
icons: [/* ... */]
},
workbox: {
globPatterns: ['**/*.{js,css,html,svg,png,woff2}'],
runtimeCaching: [
{
urlPattern: /^https:\/\/api\.example\.com\//,
handler: 'NetworkFirst',
options: {
cacheName: 'api',
expiration: { maxEntries: 50, maxAgeSeconds: 300 }
}
}
]
}
})
]
});Webpack(workbox-webpack-plugin)
const { GenerateSW, InjectManifest } = require('workbox-webpack-plugin');
module.exports = {
plugins: [
new GenerateSW({
clientsClaim: true,
skipWaiting: true,
runtimeCaching: [/* ... */]
})
// 或者
// new InjectManifest({ swSrc: './src/sw.js' })
]
};两种模式对比
| 模式 | 说明 | 适合 |
|---|---|---|
| GenerateSW | 零配置,由插件根据选项生成完整的 sw.js | 简单场景、静态站点 |
| InjectManifest | 自己写 sw.js,插件只注入 __WB_MANIFEST | 需要自定义逻辑 |
workbox-window
在主线程处理 SW 注册与更新提示:
import { Workbox } from 'workbox-window';
if ('serviceWorker' in navigator) {
const wb = new Workbox('/sw.js');
wb.addEventListener('waiting', () => {
if (confirm('发现新版本,是否立即更新?')) {
wb.addEventListener('controlling', () => window.location.reload());
wb.messageSkipWaiting();
}
});
wb.register();
}常用插件组合
1. 只缓存成功响应 + LRU + 新版本广播
new StaleWhileRevalidate({
cacheName: 'articles',
plugins: [
new CacheableResponsePlugin({ statuses: [200] }),
new ExpirationPlugin({ maxEntries: 30, maxAgeSeconds: 7 * 24 * 3600 }),
new BroadcastUpdatePlugin()
]
});2. 监听更新广播
// 页面
navigator.serviceWorker.addEventListener('message', (event) => {
if (event.data?.meta === 'workbox-broadcast-update') {
const { cacheName, updatedURL } = event.data.payload;
// 提示用户或自动重新渲染
}
});注意事项
- 不要同时注册
generateSW和手写 sw.js,会互相覆盖 - 预缓存列表过大会严重拖慢 install 阶段,
globPatterns要精确 - InjectManifest 模式下
self.__WB_MANIFEST必须被引用一次,否则构建报错 - CDN 资源必须设置
CacheableResponsePlugin({ statuses: [0, 200] }),否则 opaque 响应被忽略 - 生产构建要开启
cleanupOutdatedCaches()清理旧版本缓存
调试
workbox.setConfig({ debug: true })开启详细日志- Chrome DevTools → Application → Cache Storage 可查看
workbox-precache-v2等自动创建的 cache
