vite 项目更新后客户端更新提示
发布于
# Vite
原理
- 打包时在
index.html
写入打包时间 - 定时检测服务端的
index.html
中的时间 - 比对当前浏览器缓存中的时间和服务器时间
- 弹窗提示更新
Vite 部分配置
在项目根目录添加一个 build
文件夹,存放 vite
相关的 .ts
文件。
在 build
文件夹添加 html.ts
,编写一个 vite
插件,作用是打包时候在 index.html
文件的 head
内插入当前打包的时间。
// 路径 /build/html.ts
import type { Plugin } from 'vite'
export function setupHtmlPlugin(buildTime: string) {
const plugin: Plugin = {
name: 'html-plugin',
apply: 'build',
transformIndexHtml(html) {
return html.replace('<head>', `<head>\n <meta name="buildTime" content="${buildTime}">`)
}
}
return plugin
}
在 build
文件夹添加 time.ts
,并且安装 dayjs
库,编写一个获取时间的函数。
// 路径 /build/time.ts
import dayjs from 'dayjs'
import timezone from 'dayjs/plugin/timezone'
import utc from 'dayjs/plugin/utc'
export function getBuildTime() {
dayjs.extend(utc)
dayjs.extend(timezone)
const buildTime = dayjs.tz(Date.now(), 'Asia/Shanghai').format('YYYY-MM-DD HH:mm:ss')
return buildTime
}
在 vite.config.ts
文件中引用
import process from 'node:process'
import { fileURLToPath, URL } from 'node:url'
import { defineConfig, loadEnv } from 'vite'
import { setupHtmlPlugin } from './build/html'
import { getBuildTime } from './build/time'
export default defineConfig(() => {
// 当前打包时间
const buildTime = getBuildTime()
return {
base: '/',
plugins: [
vue(),
// 使用插件
setupHtmlPlugin(buildTime)
],
define: {
// 注入全局的 BUILD_TIME 变量
BUILD_TIME: JSON.stringify(buildTime)
},
}
})
项目配置部分
添加 src/plugins
目录,添加 app.ts
文件,编写相关逻辑,这里使用 Vue3
和 Naive UI
作为参考
// 路径 src/plugin/app.ts
import type { App } from 'vue'
import { NButton } from 'naive-ui'
import { h } from 'vue'
const UPDATE_CHECK_INTERVAL = 3 * 60 * 1000
export function setupAppVersionNotification() {
let isShow = false
let updateInterval: ReturnType<typeof setInterval> | undefined
const shouldCheckForUpdates = [!isShow, document.visibilityState === 'visible', !import.meta.env.DEV].every(Boolean)
const checkForUpdates = async () => {
if (!shouldCheckForUpdates)
return
const buildTime = await getHtmlBuildTime()
if (buildTime === BUILD_TIME) {
return
}
isShow = true
const n = window.$notification?.create({
title: '系统版本更新通知',
content: '检测到系统有新版本发布,是否立即刷新页面?',
action() {
return h('div', { style: { display: 'flex', justifyContent: 'end', gap: '12px', width: '325px' } }, [
h(
NButton,
{
onClick() {
n?.destroy()
}
},
() => '稍后再说'
),
h(
NButton,
{
type: 'primary',
onClick() {
location.reload()
}
},
() => '立即刷新'
)
])
},
onClose() {
isShow = false
}
})
}
const startUpdateInterval = () => {
if (updateInterval) {
clearInterval(updateInterval)
}
updateInterval = setInterval(checkForUpdates, UPDATE_CHECK_INTERVAL)
}
if (shouldCheckForUpdates) {
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') {
checkForUpdates()
startUpdateInterval()
}
})
startUpdateInterval()
}
}
async function getHtmlBuildTime() {
const baseUrl = '/'
const res = await fetch(`${baseUrl}index.html?time=${Date.now()}`)
const html = await res.text()
const match = html.match(/<meta name="buildTime" content="(.*)">/)
const buildTime = match?.[1] || ''
return buildTime
}
在 src/main.ts
文件引入刚刚文件
import { createApp } from 'vue'
import App from './App.vue'
import { setupAppVersionNotification } from './plugins/app'
async function bootstrap() {
const app = createApp(App)
// 如果是 react,同理也是在 dom 加载前
setupAppVersionNotification()
app.mount('#app')
}
bootstrap()
其它方案
使用 vite-plugin-version
插件在打包时读取 package.json
内的版本号并生成 version.json
文件,比对文件版本进行提示更新,原理其实一样。
备注
代码部份来自 SoybeanAdmin,有改动
完