vue 部署更新提醒功能

一、实现背景

        在公司编写一些内部用的项目页面时,经常更新了内容 但是用户一直在使用缓存的网页。并且F5以后也是用原来的缓存,一直没有更新网页 导致功能或者数据变动了 用户挂着网页 感知不到有刷新,那怎么办呢?

二、实现功能

        要让用户感知到有刷新的提醒,所以需要一个弹窗提示。当部署了新的内容后 有在正常使用页面的用户 能够收到提醒

        看了几篇文章 实现的方式差不多 基本都是 创建一个版本文件的缓存 检查有无变动

  • Service Worker 通过开启一个worker去监听 感觉过于麻烦了 我觉得一切从简
  • plugin-web-update-notification插件 需要配置webpack的 以及定义配置 还是太复杂了 界面也不是我想要的类型 还要修改版本号再发布 (我的不太正式 所以我只需要部署的时候触发更新提醒就好了)
  • 轮询fetch 当前本地下的版本文件 比对与缓存的版本号是否有改变 然后提醒用户刷新

那不安装新的插件的同时 我觉得第三种方式最适合我 那现在开始实现

1.编写创建版本文件脚本 不太会配置webpack 所以使用node

 在vue的根文件夹根目录创建一个version.js脚本

require("fs").writeFileSync("./public/version.txt", new Date().getTime().toString())

        往public下生成一个叫version.txt的文件夹 存储的打包时候的时间戳 其实一行代码就可以实现 因为后续打包的时候会把public下的文件移动到dist下

并且要与打包联动的情况下 我们要先于打包前去生成 所以 更改package.json build的命令 保证每次打包都是最新的版本 不部署的前提下不会影响到

 "build": "node version.js && vue-cli-service build --mode production"

2.编写轮询检测脚本

在src的文件夹下创建一个叫utils的文件夹(随便取名) 创建update.js代码

并且在main.js下引入

import "./utils/update"

update.js代码内容

/*
 * @Author: 羊驼
 * @Date: 2023-10-26 16:06:37
 * @LastEditors: 羊驼
 * @LastEditTime: 2023-10-27 11:10:36
 * @Description: file content
 */
// 引入提示框页面组件
import Modal from "./updateModal.vue"
import Vue from "vue"

let time = 0            // 计算轮询次数
let version = ""        // 缓存的版本号

// 轮询用检测方法
let timerFuncion = async () => {
    // 次数超过的时候 停止轮询 防止用户挂着网页一直轮询
    if (time >= 5) {
        // 仅清除计时器
        clearInterval(timer)
        return timer = null
    }
    // fetch 部署后同层级的version文件 并且加上时间戳参数 防止去访问本地硬盘的缓存
    let res = await fetch(`/version.txt?v=${new Date().getTime().toString()}`).then((res) => {
        return res.json()
    }).catch((err) => {
        console.log(err)
        return clearTimer() // 访问失败就完全关闭轮询
    })
    // console.log("存储的version:" + version)
    // console.log("获取到version:" + res)
    // console.log("比较结果:", res == version)

    // 首次加载网页的时候 存储第一份version
    if (!version) {
        version = res
    } else if (version != res) {
        // 弹出更新提示 发现verison文件更新了 就代表新部署了
        // 借鉴Element的Message实现挂载vue组件到页面上
        let MessageConstructor = Vue.extend(Modal);
        let instance = new MessageConstructor({
            data: {}
        })
        instance.id = new Date().getTime().toString()
        instance.$mount();
        document.body.appendChild(instance.$el);
        return clearTimer()
    }

    time++
}
// 检测鼠标是否移动 移动代表用户活跃中 把轮询比较用的次数一直清0
let moveFunction = () => {
    time = 0
    // 长时间挂机后 不在轮询的网页 在鼠标活跃于窗口的时候重新检测
    if (!timer) {
        timer = setInterval(timerFuncion, 1000)
    }
}
// 当被main.js 引用的时候 开始轮询于监听鼠标移动事件
let timer = setInterval(timerFuncion, 5000)
window.addEventListener("mousemove", moveFunction)
// 完全清除轮询 不轮询 不监听鼠标事件
let clearTimer = () => {
    clearInterval(timer)
    window.removeEventListener("mousemove", moveFunction)
    timer = null
}

3、编写自定义想要的弹窗说明 以及点击事件

在utils下添加一个updateModal.vue 可自由编写样式与界面

<!--
 * @Author: 羊驼
 * @Date: 2023-10-26 16:47:22
 * @LastEditors: 羊驼
 * @LastEditTime: 2023-10-27 09:29:35
 * @Description: file content
-->
<template>
  <div class="update-modal">
    <div class="title">
      系统更新🚀
    </div>
    <div class="content">
      系统已更新,请刷新页面(请在刷新前注意保存当前页面数据)。
    </div>
    <div class="actions">
      <button @click="handleAfterLeave">忽略</button>
      <button @click="refresh">刷新</button>
    </div>
  </div>
</template>

<script>
export default {
  methods: {
    handleAfterLeave() {
      this.$destroy(true);
      this.$el.parentNode.removeChild(this.$el);
    },
    refresh() {
      this.handleAfterLeave();
      // window.location.replace(window.location.href); //没有刷新缓存
        location.reload(true);  // 刷新了缓存
    },
  },
};
</script>

<style scoped>
.update-modal {
  user-select: none;
  position: fixed;
  right: 10px;
  bottom: 20px;
  max-width: 300px;
  min-width: 250px;
  width: 50%;
  background-color: #fff;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
  border-radius: 5px;
  padding: 10px 15px;
  animation: shakeY 1.5s linear;
  z-index: 99999;
}
@keyframes shakeY {
  from,
  to {
    transform: translate3d(0, 0, 0);
  }

  10%,
  30%,
  50%,
  70%,
  90% {
    transform: translate3d(0, -10px, 0);
  }

  20%,
  40%,
  60%,
  80% {
    transform: translate3d(0, 10px, 0);
  }
}

.shakeY {
  animation-name: shakeY;
}
.update-modal .title {
  height: 50px;
  line-height: 50px;
  font-size: 18px;
  margin-bottom: 10px;
}
.update-modal .content {
  text-indent: 2em;
  font-size: 16px;
}
.update-modal .actions {
  display: flex;
  justify-content: flex-end;
  margin-top: 30px;
}
.update-modal .actions button {
  display: inline-block;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  background: #fff;
  border: 1px solid #dcdfe6;
  color: #606266;
  -webkit-appearance: none;
  text-align: center;
  box-sizing: border-box;
  outline: none;
  margin: 0;
  transition: 0.1s;
  font-weight: 500;
  -moz-user-select: none;
  -webkit-user-select: none;
  -ms-user-select: none;
  padding: 10px 20px;
  font-size: 14px;
  border-radius: 4px;
  margin-left: 10px;
}
.update-modal .actions button:last-child {
  background-color: #409eff;
  color: #fff;
  border-color: #409eff;
}
</style>

4、通过jenkins部署(下篇会讲 减少了常规部署的步骤)

将更新内容提交到github上 并使用jenkins部署 可用webhooks同步触发 但是觉得还是手点部署保险

打开一个正在监听更新的网页

点击部署网页 

当部署完成后 界面就会弹出提示更新

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值