VUE2/3前端项目重新部署,开发者或用户部署成功的更新通知

104 阅读3分钟

前言

image.png

image.png

image.png

部署了、更新了、更了、发了等等,这无疑是每次新功能或bug修复打的最多频繁的字了。

再来就是怎么让用户知道我们发版了新功能,让用户刷新使用,不过不太清楚用户是否使用的到这个功能,或者说如果需要实现这个通知功能,我们应该让后端参与配合,使用WebSocket之类的。

当前功能只通过前端实现,我实现这个功能也只是更服务于我们自己开发者和测试人员,算是个小优化。

正文

功能的本质

通过定时器轮询去获取当前文件不同,文件不同,每次新功能开发打包,新的包和旧的包肯定是不相同的,但是我们无法直接去比较包的内容,成本太高。那么我们就从每次打开文件命名下手,在文件命名后缀上加上hash值、加上时间戳等方法,再来就比对文件名称,就可以知道当前项目是否重新部署过。

代码

定义一个类,Updater,可以单独创建一个js文件,专门放这个类

export class Updater {
	constructor(options) {
		this.oldScript = [] //旧hash
		this.newScript = [] //新hash
		this.dispatch = {} //分发
		this.init() //初始化
		this.timing(options?.timer) //轮询
	}

	// 初始化,获取最开始的
	async init() {
		const html = await this.getHtml()
		this.oldScript = this.parserScript(html)
	}
	//读取index html
	async getHtml() {
                //获取打包之后的html文件
		const html = await fetch('./').then(res => res.text())
		return html
	}
	//匹配script标签
	parserScript(html) {
                // 打包之后,html文件中会有关于js文件的引入,比较js文件的后缀命名
		const reg = new RegExp(/<script(?:\s+[^>]*)?>(.*?)<\/script\s*>/gi)
                console.log(html.match(reg))
		return html.match(reg)
	}
	//发布订阅通知
	on(key = 'no-update' | 'update', fn) {
		this.dispatch[key] || (this.dispatch[key] = []).push(fn)
		return this
	}
        // 比对
	compare(oldArr, newArr) {
		const base = oldArr.length
		const arr = Array.from(new Set(oldArr.concat(newArr)))
		//如果新旧length 一样无更新
		if (arr.length === base) {
			this.dispatch['no-update'].forEach(fn => {
				fn()
			})
		} else {
			//否则通知更新
			this.dispatch['update'].forEach(fn => {
				fn()
			})
		}
	}

	timing(time = 10000) {
		//轮询
		setInterval(async () => {
			const newHtml = await this.getHtml()
			this.newScript = this.parserScript(newHtml)
			this.compare(this.oldScript, this.newScript)
		}, time)
	}
}

获取script文件,可以去dist里的html查找有引入的js文件,那么怎么给打包的文件名添加hash,通过vue.config

image.png

chainWebpack中有个output对打包文件配置,这里hash、时间戳都用上了

const Timestamp = new Date().getTime()
chainWebpack(config) {
    config.output.filename(`static/js/[name].[hash:8]${Timestamp}.js`).end()
    config.output.chunkFilename(`static/js/[name].[hash:8]${Timestamp}.js`).end()
    .....
}

最后是调用这个类,引入到main.js里,大功告成

import { Updater } from './utils/updater'
// 通知更新
const up = new Updater({
	timer: 60000,
})
let isUpdate = false
up.on('no-update', () => {
        // 没有重新部署会一直执行改方法,也可以不用
	console.log('无需更新')
})
up.on('update', () => {
        // 重新部署就执行这个方法,自己可以使用一些提示之类的
	console.log('更新')
	if (!isUpdate) { // 这里设置他只提醒一次,如果用户关掉提示,没有刷新页面,就不会在提示了,看个人需求
		Notification({
			title: 'Update the new version and refresh the page',
			dangerouslyUseHTMLString: true,
			type: 'success',
			duration: 0,
		})
		isUpdate = true
	}
})

image.png

最后

掘金上还有许多其他的通知方法,这里只是成本较低的一种。如果需要参与用户层面,可以和后端提提需求,更好运用