如果你在使用
vite-plugin-pwa
(如在 Nuxt 或 Vite 项目中),却没有在sw.generated.js
中手动添加必要的代码,构建时将会报错或 PWA 无法正常工作。
😵 常见错误场景
许多开发者初次使用 vite-plugin-pwa
时,会这样配置:
ts
// nuxt.config.ts / vite.config.ts
VitePWA({
registerType: 'autoUpdate'
})
然后就以为 "自动更新" 已经开启,不需要再管其他的东西。
但这时候,构建可能会报错类似:
bash
[workbox] The precache manifest must be set via self.__WB_MANIFEST.
或者 PWA 安装后根本没有任何缓存效果。
🧠 真相是:
❗ vite-plugin-pwa
并不会自动生成完整的 Service Worker 文件。
你必须在 public/sw.generated.js
文件中手动写入以下两行代码:
js
import { precacheAndRoute } from 'workbox-precaching'
precacheAndRoute(self.__WB_MANIFEST)
否则:
- 构建时
vite-plugin-pwa
注入的__WB_MANIFEST
会找不到目标 - Service Worker 注册失败或缓存失败
- PWA 根本无法离线访问或无法更新
📦 背后原理:你需要告诉 Workbox 该怎么缓存资源
vite-plugin-pwa
使用的是 Workbox 的预缓存策略。
它会在打包时生成一个资源清单,注入到你指定的 SW 文件中(默认是 sw.generated.js
):
js
precacheAndRoute(self.__WB_MANIFEST)
这句代码的意思是:将所有静态资源清单注册到缓存中并自动路由。
如果你没写这行,Workbox 无法正常工作。
✅ 正确做法:自动写入 sw.generated.js
建议在打包前,通过构建脚本自动写入 public/sw.generated.js
,如下:
scripts/write-sw-file.mjs
js
import fs from 'fs'
import path from 'path'
import { fileURLToPath } from 'url'
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
export async function writeSWFile() {
const filePath = path.resolve(__dirname, '../public/sw.generated.js')
const content = [
`import { precacheAndRoute } from 'workbox-precaching'`,
`precacheAndRoute(self.__WB_MANIFEST)`
].join('\n') + '\n'
fs.writeFileSync(filePath, content, 'utf-8')
console.log(`✅ 已写入 ${filePath}`)
}
然后在 nuxt.config.ts
添加:
ts
hooks: {
async 'build:before'() {
const { writeSWFile } = await import('./scripts/write-sw-file.mjs')
await writeSWFile()
}
}
✨ Bonus:添加自动更新逻辑(推荐)
为了让用户自动看到新版本,你还可以监听 Service Worker 更新事件:
ts
// plugins/pwa-updater.client.ts
import { registerSW } from 'virtual:pwa-register'
const updateSW = registerSW({
onNeedRefresh() {
if (confirm('检测到新版本,是否刷新?')) {
updateSW(true)
}
},
onOfflineReady() {
console.log('✅ 离线使用就绪')
}
})
🧩 总结
问题 | 说明 |
---|---|
没写 sw.generated.js |
会导致 PWA 报错或缓存失效 |
没写 precacheAndRoute |
__WB_MANIFEST 无法生效,构建失败或 PWA 空壳 |
解决方案 | 打包前自动写入 sw.generated.js 内容 |
用户更新逻辑(非强制但推荐) | 提示用户刷新或自动刷新 |
✅ 最佳实践组合
- ✔️ 使用
vite-plugin-pwa
的autoUpdate
模式 - ✔️ 打包前写入
sw.generated.js
- ✔️ 添加
registerSW()
实现更新提示 - ✔️ 保证
workbox
成功预缓存静态资源