很简单,使用 vite-plugin-pwa 插件,Antfu 出品,品质保证。零配置,简单易用。
0. 安装插件
pnpm i vite-plugin-pwa -D
1. 启动插件
修改 vite.config.ts
import { VitePWA} from 'vite-plugin-pwa';
import { definePlugin } from 'vite';
import vue from '@vitejs/plugin-vue';
export default definePlugin(({ command }) => {
const isDev = command === 'serve';
return {
plugins: [
vue(),
new VitePWA({
disable: isDev, // 开发环境不启动 pwa
includeAssets: [
// 非直接加载,但是需要预缓存的内容
],
}),
],
};
})
2. 可脱机提示及可更新提示
原则上来说,Vite、Vite 插件都是开发脚手架,不限定框架。不过我用的最多的还是 Vue。这里以 Vue3 为例示范一下如何使用插件快速实现 PWA 组件:
- pwa 完成缓存后,提示可脱机使用
- 线上版本更新后,提示有新版本可用
- 更新时,给出视觉反馈
<script setup lang="ts">
import { useRegisterSW } from 'virtual:pwa-register/vue'
import {ref} from "vue";
const {
offlineReady,
needRefresh,
updateServiceWorker,
} = useRegisterSW({
immediate: true,
onRegistered(r) {
// 每小时自动检查一次,是否有新版本
r && setInterval(async() => {
await r.update()
}, 60 * 60 * 1000)
},
});
const isRefreshing = ref<boolean>(false);
function doRefresh() {
isRefreshing.value = true;
updateServiceWorker();
}
const close = () => {
offlineReady.value = false
needRefresh.value = false
}
</script>
<template lang="pug">
.pwa-toast.fixed.right-4.bottom-4.p-3.border.border-gray-200.rounded.bg-white.z-index-10.shadow-md(
v-if="offlineReady || needRefresh"
role="alert"
)
p.message.mb-2
span(v-if="offlineReady") App ready to work offline
span(v-else-if="isRefreshing") Refreshing...
span(v-else) New content available, click on reload button to update.
button.border.border-gray-200.rounded.py-1.px-2(
v-if="needRefresh",
type="button",
:disabled="isRefreshing",
@click="doRefresh",
)
.spinner(v-if="isRefreshing")
template(v-else) Reload
button.border.border-gray-200.rounded.py-1.px-2.ml-2(type="button" @click="close") Close
</template>
3. 一些坑
- PWA 会拦截所有请求,以便缓存到本地。所以,打开网站,注册完 service worker,再请求其它文件,比如 ads.txt,也可能会看不到。这并不影响广告,因为广告商服务器不会受 PWA 影响;但是广告商运营人员可能只会操作浏览器,她们可能会认为你的广告文件没准备好。此时,请告诉她们使用匿名窗口。
- PWA 会自动预缓存
dist
目录内的东西,所以一定要注意build.emptyOutDir
,不要让目录过分膨胀,影响新用户体验。 - 有新版本后,上面的组件会提示用户刷新,但是刷新过程可能很慢(清理缓存,下载新内容等),所以点完之后可能没有反应。所以最好加上 spinner。
4. 总结&扩展阅读
整体来说,这个插件很好用,没什么特别需求的话,几乎可以零配置。
建议感兴趣的同学好好阅读下 官方文档,尤其是 examples
目录里的内容,会有很大帮助。
欢迎吐槽,共同进步