|
背景:
随着项目体量越来越大,用户群体越来越多,用户的声音也越来越明显;关于应用发版之后用户无感知,导致用户用的是仍然还是老版本功能,除非用户手动刷新,否则体验不到最新的功能;这样的体验非常不好,于是我们团队针对该问题给出了相应的解决方案来处理;
技术栈:vue3+ts+vite+ant-design-vue
1、web应用版本检测方案:
1.1、基于vite开发自定义插件version-update,vite打包流程运行version-update插件在项目结构目录public文件夹下生成version.json文件,通过读取version.json文件内容与服务器上的资源文件作为版本更新的比对依据- 1 /** src/plugin/versionUpdate.ts **/
- 2 import fs from 'fs'
- 3 import path from 'path'
- 4 interface OptionVersion {
- 5 version: number | string
- 6 }
- 7 interface configObj extends Object {
- 8 publicDir: string
- 9 }
- 10
- 11 const writeVersion = (versionFileName: string, content: string | NodeJS.ArrayBufferView) => {
- 12 // 写入文件
- 13 fs.writeFile(versionFileName, content, (err) => {
- 14 if (err) throw err
- 15 })
- 16 }
- 17
- 18 export default (options: OptionVersion) => {
- 19 let config: configObj = { publicDir: '' }
- 20 return {
- 21 name: 'version-update',
- 22 configResolved(resolvedConfig: configObj) {
- 23 // 存储最终解析的配置
- 24 config = resolvedConfig
- 25 },
- 26
- 27 buildStart() {
- 28 // 生成版本信息文件路径
- 29 const file = config.publicDir + path.sep + 'version.json'
- 30 // 这里使用编译时间作为版本信息
- 31 const content = JSON.stringify({ version: options.version })
- 32 /** 判断目录是否存在 */
- 33 if (fs.existsSync(config.publicDir)) {
- 34 writeVersion(file, content)
- 35 } else {
- 36 /** 创建目录 */
- 37 fs.mkdir(config.publicDir, (err) => {
- 38 if (err) throw err
- 39 writeVersion(file, content)
- 40 })
- 41 }
- 42 }
- 43 }
- 44 }
复制代码 1.2、将该文件作为插件放入到vite的plugin中去执行,并在vite构建过程中声明一个全局变量process.env.VITE__APP_VERSION__(这里仅仅只是一个变量,只用来记录打包时间和服务器json内容对比),值为当前时间戳- 1 /** vite.config.ts **/
- 2 import { defineConfig } from 'vite'
- 3 import vue from '@vitejs/plugin-vue'
- 4 import vueJsx from '@vitejs/plugin-vue-jsx'
- 5 import VueSetupExtend from 'vite-plugin-vue-setup-extend'
- 6 import { visualizer } from 'rollup-plugin-visualizer'
- 7 import viteCompression from 'vite-plugin-compression'
- 8 import versionUpdatePlugin from './src/plugins/versionUpdate' //Rollup 的虚拟模块
- 9 // vite.config.ts
- 10 import type { ViteSentryPluginOptions } from 'vite-plugin-sentry'
- 11 import viteSentry from 'vite-plugin-sentry'
- 12 // @ts-ignore
- 13 const path = require('path')
- 14
- 15 const NODE_ENV = process.env.NODE_ENV
- 16 const IS_PROD = NODE_ENV === 'production'
- 17 const CurrentTimeVersion = new Date().getTime()
- 18 /*
- 19 Configure sentry plugin
- 20 */
- 21 const sentryConfig: ViteSentryPluginOptions = {
- 22 url: 'https://sentry.jtexpress.com.cn',
- 23 authToken: '85ceca5d01ba46b2b6e92238486250d04329713adf5b4ef68a8e094102a4b6e1',
- 24 org: 'yl-application',
- 25 project: 'post-station',
- 26 release: process.env.npm_package_version,
- 27 deploy: {
- 28 env: 'production'
- 29 },
- 30 setCommits: {
- 31 auto: true
- 32 },
- 33 sourceMaps: {
- 34 include: ['./dist/static/js'],
- 35 ignore: ['node_modules'],
- 36 urlPrefix: '~/static/js'
- 37 }
- 38 }
- 39
- 40 // https://vitejs.dev/config/
- 41 export default defineConfig({
- 42 define: {
- 43 // 定义全局变量
- 44 'process.env.VITE__APP_VERSION__': CurrentTimeVersion
- 45 },
- 46 plugins: [
- 47 IS_PROD && versionUpdatePlugin({
- 48 version: CurrentTimeVersion
- 49 }),
- 50 vueJsx(),
- 51 vue(),
- 52 VueSetupExtend(),
- 53 visualizer(),
- 54 // gzip压缩 生产环境生成 .gz 文件
- 55 viteCompression({
- 56 verbose: true,
- 57 disable: false,
- 58 threshold: 10240,
- 59 algorithm: 'gzip',
- 60 ext: '.gz'
- 61 }),
- 62 IS_PROD && viteSentry(sentryConfig)
- 63 ],
- 64 resolve: {
- 65 alias: {
- 66 // @ts-ignore
- 67 '@': path.resolve(__dirname, 'src')
- 68 }
- 69 },
- 70 css: {
- 71 preprocessorOptions: {
- 72 less: {
- 73 modifyVars: {
- 74 // antd 自定义主题 https://www.antdv.com/docs/vue/customize-theme-cn
- 75 'primary-color': '#1890ff',
- 76 'link-color': '#1890ff',
- 77 'border-radius-base': '2px'
- 78 },
- 79 additionalData: '@import "@/assets/style/common.less";',
- 80 javascriptEnabled: true
- 81 }
- 82 }
- 83 },
- 84 server: {
- 85 host: '0.0.0.0',
- 86 port: 8080,
- 87 open: false,
- 88 https: false,
- 89 proxy: {}
- 90 },
- 91 build: {
- 92 minify: 'terser',
- 93 terserOptions: {
- 94 compress: {
- 95 /* 清除console */
- 96 drop_console: true,
- 97 /* 清除debugger */
- 98 drop_debugger: true
- 99 }
- 100 },
- 101 rollupOptions: {
- 102 output: {
- 103 chunkFileNames: 'static/js/[name]-[hash].js',
- 104 entryFileNames: 'static/js/[name]-[hash].js',
- 105 assetFileNames: 'static/[ext]/[name]-[hash].[ext]',
- 106 manualChunks(id) {
- 107 //静态资源分拆打包
- 108 if (id.includes('node_modules')) {
- 109 return id.toString().split('node_modules/')[1].split('/')[0].toString()
- 110 }
- 111 }
- 112 }
- 113 },
- 114 sourcemap: IS_PROD
- 115 }
- 116 })
复制代码 1.3、封装全局方法,请求当前域名下的/version.json资源,将vite中定义的全局变量和当前域名下的json文件内容做对比,如果不一致,我们则认为发布了新版本- 1 /** src/utils/checkVersion.ts **/
- 2 import { Modal } from 'ant-design-vue'
- 3 export default function versionCheck() {
- 4 const timestamp = new Date().getTime()
- 5 //import.meta.env.MODE 获取的是开发还是生产版本的
- 6 if (import.meta.env.MODE === 'development') return
- 7
- 8 fetch(`/version.json?t=${timestamp}`)
- 9 .then((res) => {
- 10 return res.json()
- 11 })
- 12 .then((response) => {
- 13 if (process.env.VITE__APP_VERSION__ !== response.version) {
- 14 Modal.confirm({
- 15 title: '发现新版本',
- 16 content: '检测到最新版本,刷新后立即使用...',
- 17 okText: '立即更新',
- 18 cancelText: '暂不更新',
- 19 onOk() {
- 20 window.location.reload()
- 21 }
- 22 })
- 23 }
- 24 })
- 25 }
复制代码 1.4 、在layout全局文件中,监听路由变化,去调版本检测的方法来决定是否弹出提醒(尊重用户的选择,是否更新页面由用户来决定)- 1 /** src/layout/index.vue **/
- 2 watch(
- 3 () => router.currentRoute.value,
- 4 (newValue: any) => {
- 5 /** 判断是否有更高的版本 */
- 6 checkVersion()
- 7 },
- 8 { immediate: true }
- 9 )
复制代码
2、微信小程序应用版本检测方案:
流程图:
技术栈:Taro-vue+ts+nut-ui (京东物流风格轻量移动端组件库)
2.1、基于微信开发文档提供的getUpdateManager版本更新管理器api去实现版本更新的检测与新版本应用的下载,封装全局方法- 1 /** 检查小程序版本更新 */
- 2 export function checkMiniProgramVersion() {
- 3 if (Taro.canIUse('getUpdateManager')) {
- 4 const updateManager = Taro.getUpdateManager();
- 5 updateManager.onCheckForUpdate(function (res) {
- 6 // 请求完新版本信息的回调
- 7 if (res.hasUpdate) {
- 8 Taro.showModal({
- 9 title: '新版本更新提示',
- 10 content: '检测到新版本,是否下载新版本并重启小程序?',
- 11 success: function (res) {
- 12 if (res.confirm) {
- 13 downloadAndUpdate(updateManager);
- 14 }
- 15 },
- 16 });
- 17 }
- 18 });
- 19 } else {
- 20 Taro.showModal({
- 21 title: '新版本更新提示',
- 22 showCancel: false,
- 23 content: '当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试。',
- 24 success: function () {
- 25 Taro.exitMiniProgram();
- 26 },
- 27 });
- 28 }
- 29 }
- 30
- 31 /** 新版本应用下载 */
- 32 export function downloadAndUpdate(updateManager) {
- 33 Taro.showLoading();
- 34 updateManager.onUpdateReady(function () {
- 35 Taro.hideLoading();
- 36 Taro.showModal({
- 37 title: '新版本更新提示',
- 38 content: '新版本已经准备好,是否重启应用?',
- 39 success: function (res) {
- 40 if (res.confirm) {
- 41 // 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
- 42 updateManager.applyUpdate();
- 43 }
- 44 },
- 45 });
- 46 });
- 47
- 48 updateManager.onUpdateFailed(function () {
- 49 Taro.showLoading();
- 50 Taro.showModal({
- 51 title: '新版本更新提示',
- 52 showCancel: false,
- 53 content: '新版本已经上线啦~,请您删除当前小程序,重新搜索打开哟~',
- 54 success: function () {
- 55 // 退出应用
- 56 Taro.exitMiniProgram();
- 57 },
- 58 });
- 59 });
- 60 }
复制代码 2.2、在app.ts入口文件onLaunch的生命周期钩子函数中去调用方法检测版本- 1 // src/app.ts
- 2 import { createApp } from 'vue';
- 3 import Taro from '@tarojs/taro';
- 4 import './app.scss';
- 5 import store from './store';
- 6 import installPlugin from '@/plugins/index';
- 7 import { wxLogin, checkMiniProgramVersion } from '@/utils/common';
- 8
- 9 const App = createApp({
- 10 onLaunch() {
- 11 /** 检测小程序版本 */
- 12 checkMiniProgramVersion();
- 13 },
- 14 });
- 15
- 16 App.use(store);
- 17 installPlugin(App);
- 18
- 19 export default App;
复制代码 坑点Tips:
小程序更新方案中由于受限于小程序的更新机制,第一次发版无效,因为微信小程序服务器上的版本中不存在checkMiniProgramVersion方法,所以无法执行;更新提示弹窗需要在第二次发版时才生效;
出处:https://www.cnblogs.com/dengyao-blogs/本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。
来源:https://www.cnblogs.com/dengyao-blogs/p/17708054.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作! |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
|