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,有改动
完