#Vue3篇: Vue 项目发版后如何提示用户刷新?基于 package.json 版本号的前端更新检测方案 核心思路利用package.json中的version字段作为版本标识构建时将 version 注入前端代码同时生成version.json到产物目录运行时轮询服务器上的version.json与本地版本对比不一致时弹窗提示用户刷新加载新资源发版package.json version 递增 → build → dist 含 version.json 代码内嵌版本号 ↓ 运行本地版本构建写入 vs 远程 version.json轮询 ↓ 更新版本不一致 → 弹窗 → location.reload()一、版本号来源统一从package.json读取发版前手动递增或使用npm version自动递增# 自动递增并打 git tag可选npmversion patch# 1.2.3 → 1.2.4npmversion minor# 1.2.3 → 1.3.0npmversion major# 1.2.3 → 2.0.0// package.json{name:my-app,version:1.2.3}二、Vue2 接入vue.config.js1. 顶部引入constwebpackrequire(webpack);const{version}require(./package.json);推荐注入为process.env.VUE_APP_VERSION与项目已有的VUE_APP_*环境变量风格一致。2. configureWebpack生产环境注入版本号在现有configureWebpack的production 分支中于config.plugins.push处加入DefinePlugin与 TerserPlugin、CompressionWebpackPlugin 等插件共存configureWebpack:config{if(process.env.NODE_ENVproduction){config.modeproduction;// 注入版本号config.plugins.push(newwebpack.DefinePlugin({process.env.VUE_APP_VERSION:JSON.stringify(version)}));config.optimization{// ... 原有 TerserPlugin、splitChunks 等配置};config.plugins.push(newCompressionWebpackPlugin({// ... 原有压缩配置}));}else{config.modedevelopment;}}3. chainWebpack构建时生成 version.json在chainWebpack末尾追加仅生产环境生效与 DLL、less 全局变量、alias、svg-sprite-loader 等配置互不影响chainWebpack:config{// ... 原有 dll、less、alias、svg 等配置if(process.env.NODE_ENVproduction){config.plugin(version-json).use(classVersionJsonPlugin{apply(compiler){compiler.hooks.emit.tapAsync(VersionJsonPlugin,(compilation,callback){constcontentJSON.stringify({version,buildTime:newDate().toISOString()// 可选便于排查});compilation.assets[version.json]{source:()content,size:()content.length};callback();});}});}}构建后产物结构dist/ ├── index.html ├── version.json ← 运行时轮询此文件 ├── js/ │ ├── app.[hash].js │ └── vendor.[hash].js └── css/ └── app.[hash].css4. 与现有 webpack 配置的兼容性现有配置是否冲突说明publicPath: ./⚠️ 需注意轮询路径必须用process.env.BASE_URL不能用/version.jsonCompressionWebpackPlugin✅ 无冲突仅压缩 js/html/css不影响 version.jsonDLL 插件✅ 无冲突版本检测独立于 DLL 预构建drop_console: true✅ 无冲突检测模块避免 console.log 即可splitChunks✅ 无冲突版本号在独立 version.json 中三、Vue3 接入vite.config.js// vite.config.jsimport{defineConfig}fromvite;importvuefromvitejs/plugin-vue;import{readFileSync,writeFileSync}fromfs;import{resolve}frompath;constpkgJSON.parse(readFileSync(./package.json,utf-8));exportdefaultdefineConfig({base:./,// 相对路径部署时与 Vue2 publicPath: ./ 等效plugins:[vue(),{name:generate-version-json,closeBundle(){writeFileSync(resolve(__dirname,dist/version.json),JSON.stringify({version:pkg.version,buildTime:newDate().toISOString()}));}}],define:{__APP_VERSION__:JSON.stringify(pkg.version)}});也可用import pkg from ./package.json需tsconfig开启resolveJsonModule。TypeScript 声明可选// env.d.tsdeclareconst__APP_VERSION__:string;四、运行时版本检测1. 检测策略项Vue2Vue3本地版本process.env.VUE_APP_VERSION__APP_VERSION__远程版本fetch(\${process.env.BASE_URL}version.json)fetch(\${import.meta.env.BASE_URL}version.json)防缓存URL 加?t${Date.now()}请求头cache: no-store同左触发时机页面加载 定时轮询5~30 minvisibilitychange切回同左环境限制仅production启用仅import.meta.env.PROD启用2. Vue2 检测模块// src/utils/versionCheck.jsconstLOCAL_VERSIONprocess.env.VUE_APP_VERSION;constVERSION_URL${process.env.BASE_URL}version.json;constCHECK_INTERVAL5*60*1000;lettimernull;lethasNotifiedfalse;asyncfunctioncheckVersion(onUpdate){try{constresawaitfetch(${VERSION_URL}?t${Date.now()},{cache:no-store});if(!res.ok)return;const{version}awaitres.json();if(versionversion!LOCAL_VERSION!hasNotified){hasNotifiedtrue;onUpdate(version);}}catch(e){// 网络异常静默处理下次轮询再试}}exportfunctionstartVersionCheck(onUpdate){if(process.env.NODE_ENV!production)return;checkVersion(onUpdate);timersetInterval(()checkVersion(onUpdate),CHECK_INTERVAL);document.addEventListener(visibilitychange,(){if(document.visibilityStatevisible)checkVersion(onUpdate);});}exportfunctionstopVersionCheck(){if(timer)clearInterval(timer);}3. Vue3 检测模块// src/utils/versionCheck.jsconstLOCAL_VERSION__APP_VERSION__;constVERSION_URL${import.meta.env.BASE_URL}version.json;constCHECK_INTERVAL5*60*1000;lettimernull;lethasNotifiedfalse;asyncfunctioncheckVersion(onUpdate){try{constresawaitfetch(${VERSION_URL}?t${Date.now()},{cache:no-store});if(!res.ok)return;const{version}awaitres.json();if(versionversion!LOCAL_VERSION!hasNotified){hasNotifiedtrue;onUpdate(version);// onUpdate(version) 「发现新版本后的处理函数」versionCheck.js 只负责检测并调用它具体弹窗、刷新等逻辑在 main.js 传入的回调里写。}}catch(e){// 静默失败}}exportfunctionstartVersionCheck(onUpdate){if(!import.meta.env.PROD)return;checkVersion(onUpdate);timersetInterval(()checkVersion(onUpdate),CHECK_INTERVAL);document.addEventListener(visibilitychange,(){if(document.visibilityStatevisible)checkVersion(onUpdate);});}exportfunctionstopVersionCheck(){if(timer)clearInterval(timer);}4. 入口挂载Vue2Element UI 示例// main.jsimport{startVersionCheck}from/utils/versionCheck;import{MessageBox}fromelement-ui;startVersionCheck(newVersion{MessageBox.confirm(发现新版本${newVersion}当前${process.env.VUE_APP_VERSION}是否立即刷新,版本更新,{confirmButtonText:刷新,cancelButtonText:稍后,type:info}).then(()location.reload());});Vue3Element Plus 示例// main.jsimport{startVersionCheck}from/utils/versionCheck;import{ElMessageBox}fromelement-plus;startVersionCheck(newVersion{ElMessageBox.confirm(发现新版本${newVersion}当前${__APP_VERSION__}是否立即刷新,版本更新,{confirmButtonText:刷新,cancelButtonText:稍后,type:info}).then(()location.reload());});五、publicPath / base 路径对照这是最容易踩坑的地方部署方式Vue2 publicPathVue3 baseversion.json 请求路径根路径部署///version.json相对路径部署././${BASE_URL}version.json子目录部署/app//app//app/version.jsonprocess.env.BASE_URLVue2和import.meta.env.BASE_URLVue3会自动与publicPath/base保持一致推荐始终通过 BASE_URL 拼接路径。六、发版流程1. package.json 递增 version或 npm version patch 2. npm run build 3. 部署 dist 目录确保 version.json 一并上传 4. 老用户浏览器运行旧 JS旧版本号 5. 轮询到新 version.json → 弹窗提示 → 用户刷新 → 加载新资源七、Nginx 缓存配置index.html和version.json必须禁用强缓存否则用户永远拿不到新版本信息带 contenthash 的 JS/CSS 可长期缓存# version.json 不缓存 location ~* version\.json$ { add_header Cache-Control no-cache, no-store, must-revalidate; } # index.html 不缓存 location /index.html { add_header Cache-Control no-cache, no-store, must-revalidate; } # JS/CSS 带 hash长期缓存 location ~* \.(js|css)$ { add_header Cache-Control public, max-age31536000, immutable; }八、可选优化1. 多 Tab 去重弹窗constnotifiedKeynotified_version;functionshouldNotify(newVersion){if(localStorage.getItem(notifiedKey)newVersion)returnfalse;localStorage.setItem(notifiedKey,newVersion);returntrue;}// 在 checkVersion 中判断if(versionversion!LOCAL_VERSIONshouldNotify(version)){onUpdate(version);}2. 一键发版脚本// package.json scripts{release:patch:npm version patch npm run build,release:minor:npm version minor npm run build}3. 轮询间隔建议场景建议间隔内部管理系统5 ~ 10 分钟面向 C 端用户15 ~ 30 分钟切回页面时立即检测visibilitychange九、方案对比方案优点缺点version.json 轮询推荐实现简单、框架无关、可控需额外请求依赖部署缓存策略轮询 index.html 解析 hash无需额外文件解析复杂、请求体积大Service Worker可静默更新实现成本高需 PWA 支持十、常见问题问题原因解决发版后用户无感知version.json 被 CDN/Nginx 缓存配置 no-cachefetch 404publicPath 为./却用绝对路径/version.json改用BASE_URL拼接开发环境也弹窗未判断环境加NODE_ENV production判断多标签重复弹窗各 Tab 独立检测localStorage 记录已提示版本刷新后仍是旧版index.html 被缓存index.html 配置 no-cache十一、最小实现清单✅ package.json 维护 version 字段 ✅ 构建配置注入版本号Vue2: VUE_APP_VERSION / Vue3: __APP_VERSION__ ✅ 构建产物生成 version.json ✅ 运行时通过 BASE_URL 轮询对比 更新提示 ✅ 仅生产环境启用检测 ✅ Nginx/CDN 对 version.json、index.html 禁用强缓存