在做基于Vite和React16的项目时,需要前端做版本号管理,当有新版本上线后友好提示客户更新;
1 编写版本号生成插件
- 根目录新建vite-plugin-version.ts 文件;
新手建议使用buildStart()内封装方法,
如果觉得每次编译后本地也提示版本升级会很麻烦;
就使用closeBundle()但要写死指定目录;
import fs from 'fs';
import path from 'path';
export default function vitePluginVersion() {
const config = {
publicDir: ''
}
return {
name: 'vite-plugin-version',
configResolved(resolvedConfig: any) {
config.publicDir = resolvedConfig.publicDir
},
// 编译前执行回调
buildStart() {
/* 大致的意思就是找到存放静态资源的目录,然后新建version.json
利用编译后静态资源会复制到dist目录下面的逻辑, 来达到目的;
优点是:灵活,哪怕你是自定义输出目录页也不用担心
缺点是:每次编译静态文件里面的version.json版本号都会边,也就是每次本地运行都会弹窗要更新版本;
*/
const file = config.publicDir + path.sep + "version.json";
const content = JSON.stringify({ version: new Date().getTime() });
if (fs.existsSync(config.publicDir)) {
fs.writeFileSync(file, content, 'utf8');
} else {
fs.mkdir(config.publicDir, { recursive: true }, (err: any) => {
if (err) {
console.error('创建目录失败:', err);
} else {
fs.writeFileSync(file, content, 'utf8');
}
});
}
},
// 编译后执行回调
closeBundle() {
/*
这个是编译后的执行回调: 如果在这里使用的话:
逻辑1:编译完毕后生成一个version.json到,你指定的dist文件夹;如果不自定义输出文件夹,直接写死也不错;
逻辑2: 加判断,判断静态文件夹是否有version.json文件;如果没有顺便新建一个; 然后单独在dist文件夹输出version.json;
优点是: 项目已经成功编译了,最后做这件事; 本地静态文件version.json生成一次后续不在重新生成;
缺点是:每次都要判断静态文件夹是否有, version.json;
*/
// 创建version.json文件内容
// const content = JSON.stringify({ version: new Date().getTime() });
// 指定输出文件路径第二种方法
// const outputPath = path.join(process.cwd(), 'dist', 'version.json');
// const outputPath = path.resolve(__dirname, 'dist', 'version.json');
// 写入文件
// fs.writeFileSync(outputPath, content, 'utf8');
// 判断静态文件目录是否存在,不存在就给它生成一个
// const publicVersionPath = path.join(__dirname, 'public', 'version.json');
// if (!fs.existsSync(publicVersionPath)) {
// fs.writeFileSync(publicVersionPath, content, 'utf8');
// };
}
};
}
2.使用插件
打开vite.config.ts文件
import vitePluginVersion from './vite-plugin-version'
export default defineConfig({
plugins: [
vitePluginVersion(),
]
})
3.编写请求获取版本号方法fetchVersionJson.ts
// 引入第三方localStore存储插件
import storejs from 'storejs';
function fetchBuildVersion() {
return new Promise((resolve, reject) => {
fetch('./version.json', {
cache: 'no-cache', // 禁用缓存
}).then(response => {
if (response.status === 404) {
reject({code: 0, message: `文件找不到`});
return;
}
// 检查响应状态
if (!response.ok) {
// 如果响应状态码不是ok,我们认为文件不存在
reject({code: 0, message: `${response.statusText}`});
return;
}
resolve(response.json());
}).catch(error => {
// 网络请求错误处理
return reject({code: 0, message: '获取version.json时发生错误'});
});
});
}
// 最后一次查询时间
let lastFetchTime = 0;
export function HandleGetSoftVersionCode() {
const currentTime = Date.now();
// 避免接口密集频繁触发,设置为5秒内只触发1次
if (currentTime - lastFetchTime < 5000) {
// return reject({code: 0, message: '请求太频繁, 5秒内只能请求一次'});
return;
}
lastFetchTime = currentTime;
// 获取本地版本
const currLocalVerCode = storejs.get('YYH_Version');
throttledFetchVersion().then((data: any) => {
const {version} = data;
// 表示版本号一致
if (currLocalVerCode === version) {
return;
} else {
// 版本号不一致, 弹窗提示用户更新
}
}).catch((error) => {
// 表示不是最新版本, 直接提示用户刷新页面获取
if (error.message === '文件找不到') {
// 文件找不到, 弹窗提示用户更新
};
});
}
4.在Axios全局请求的时候的时候,调用封装方法和本地存储的版本号是否一致;
// 导入获取版本方法
import {HandleGetSoftVersionCode} from './fetchVersionJson';
import axios from "axios";
const service = axios.create({
timeout: 120 * 1000
});
const request = (config: any) => {
return new Promise((resolve, reject) => {
/* 这里可以调用获取版本方法;
* 还可以排除登陆url,当是登陆的话就不调用获取版本方法;
* if (config.url !== 'user/login') {};
*/
HandleGetSoftVersionCode();
service(config).then((res) => {
resolve(res);
}).catch((err) => {
reject(err);
});
});
});
export default request;
5.如果不一致就弹窗提示用户更新版本;
// 引入第三方localStore存储插件
import storejs from 'storejs';
// 点击确定存入最新版本,并刷新页面
storejs.set('YYH_Version', '123456789');
location.reload();