标签: pwa

  • Vite 项目里启动 PWA

    Vite 项目里启动 PWA

    很简单,使用 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 组件:

    1. pwa 完成缓存后,提示可脱机使用
    2. 线上版本更新后,提示有新版本可用
    3. 更新时,给出视觉反馈
    <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. 一些坑

    1. PWA 会拦截所有请求,以便缓存到本地。所以,打开网站,注册完 service worker,再请求其它文件,比如 ads.txt,也可能会看不到。这并不影响广告,因为广告商服务器不会受 PWA 影响;但是广告商运营人员可能只会操作浏览器,她们可能会认为你的广告文件没准备好。此时,请告诉她们使用匿名窗口。
    2. PWA 会自动预缓存 dist 目录内的东西,所以一定要注意 build.emptyOutDir,不要让目录过分膨胀,影响新用户体验。
    3. 有新版本后,上面的组件会提示用户刷新,但是刷新过程可能很慢(清理缓存,下载新内容等),所以点完之后可能没有反应。所以最好加上 spinner。

    4. 总结&扩展阅读

    整体来说,这个插件很好用,没什么特别需求的话,几乎可以零配置。

    建议感兴趣的同学好好阅读下 官方文档,尤其是 examples 目录里的内容,会有很大帮助。