经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 移动开发 » 微信小程序 » 查看文章
web应用及微信小程序版本更新检测方案实践
来源:cnblogs  作者:有梦想的咸鱼前端  时间:2023/9/18 9:05:56  对本文有异议

背景:

  随着项目体量越来越大,用户群体越来越多,用户的声音也越来越明显;关于应用发版之后用户无感知,导致用户用的是仍然还是老版本功能,除非用户手动刷新,否则体验不到最新的功能;这样的体验非常不好,于是我们团队针对该问题给出了相应的解决方案来处理;

技术栈:vue3+ts+vite+ant-design-vue

1、web应用版本检测方案:

        1.1、基于vite开发自定义插件version-update,vite打包流程运行version-update插件在项目结构目录public文件夹下生成version.json文件,通过读取version.json文件内容与服务器上的资源文件作为版本更新的比对依据

  1. 1 /** src/plugin/versionUpdate.ts **/
  2. 2 import fs from 'fs'
  3. 3 import path from 'path'
  4. 4 interface OptionVersion {
  5. 5 version: number | string
  6. 6 }
  7. 7 interface configObj extends Object {
  8. 8 publicDir: string
  9. 9 }
  10. 10
  11. 11 const writeVersion = (versionFileName: string, content: string | NodeJS.ArrayBufferView) => {
  12. 12 // 写入文件
  13. 13 fs.writeFile(versionFileName, content, (err) => {
  14. 14 if (err) throw err
  15. 15 })
  16. 16 }
  17. 17
  18. 18 export default (options: OptionVersion) => {
  19. 19 let config: configObj = { publicDir: '' }
  20. 20 return {
  21. 21 name: 'version-update',
  22. 22 configResolved(resolvedConfig: configObj) {
  23. 23 // 存储最终解析的配置
  24. 24 config = resolvedConfig
  25. 25 },
  26. 26
  27. 27 buildStart() {
  28. 28 // 生成版本信息文件路径
  29. 29 const file = config.publicDir + path.sep + 'version.json'
  30. 30 // 这里使用编译时间作为版本信息
  31. 31 const content = JSON.stringify({ version: options.version })
  32. 32 /** 判断目录是否存在 */
  33. 33 if (fs.existsSync(config.publicDir)) {
  34. 34 writeVersion(file, content)
  35. 35 } else {
  36. 36 /** 创建目录 */
  37. 37 fs.mkdir(config.publicDir, (err) => {
  38. 38 if (err) throw err
  39. 39 writeVersion(file, content)
  40. 40 })
  41. 41 }
  42. 42 }
  43. 43 }
  44. 44 }

  1.2、将该文件作为插件放入到vite的plugin中去执行,并在vite构建过程中声明一个全局变量process.env.VITE__APP_VERSION__(这里仅仅只是一个变量,只用来记录打包时间和服务器json内容对比),值为当前时间戳

  1. 1 /** vite.config.ts **/
  2. 2 import { defineConfig } from 'vite'
  3. 3 import vue from '@vitejs/plugin-vue'
  4. 4 import vueJsx from '@vitejs/plugin-vue-jsx'
  5. 5 import VueSetupExtend from 'vite-plugin-vue-setup-extend'
  6. 6 import { visualizer } from 'rollup-plugin-visualizer'
  7. 7 import viteCompression from 'vite-plugin-compression'
  8. 8 import versionUpdatePlugin from './src/plugins/versionUpdate' //Rollup 的虚拟模块
  9. 9 // vite.config.ts
  10. 10 import type { ViteSentryPluginOptions } from 'vite-plugin-sentry'
  11. 11 import viteSentry from 'vite-plugin-sentry'
  12. 12 // @ts-ignore
  13. 13 const path = require('path')
  14. 14
  15. 15 const NODE_ENV = process.env.NODE_ENV
  16. 16 const IS_PROD = NODE_ENV === 'production'
  17. 17 const CurrentTimeVersion = new Date().getTime()
  18. 18 /*
  19. 19 Configure sentry plugin
  20. 20 */
  21. 21 const sentryConfig: ViteSentryPluginOptions = {
  22. 22 url: 'https://sentry.jtexpress.com.cn',
  23. 23 authToken: '85ceca5d01ba46b2b6e92238486250d04329713adf5b4ef68a8e094102a4b6e1',
  24. 24 org: 'yl-application',
  25. 25 project: 'post-station',
  26. 26 release: process.env.npm_package_version,
  27. 27 deploy: {
  28. 28 env: 'production'
  29. 29 },
  30. 30 setCommits: {
  31. 31 auto: true
  32. 32 },
  33. 33 sourceMaps: {
  34. 34 include: ['./dist/static/js'],
  35. 35 ignore: ['node_modules'],
  36. 36 urlPrefix: '~/static/js'
  37. 37 }
  38. 38 }
  39. 39
  40. 40 // https://vitejs.dev/config/
  41. 41 export default defineConfig({
  42. 42 define: {
  43. 43 // 定义全局变量
  44. 44 'process.env.VITE__APP_VERSION__': CurrentTimeVersion
  45. 45 },
  46. 46 plugins: [
  47. 47 IS_PROD && versionUpdatePlugin({
  48. 48 version: CurrentTimeVersion
  49. 49 }),
  50. 50 vueJsx(),
  51. 51 vue(),
  52. 52 VueSetupExtend(),
  53. 53 visualizer(),
  54. 54 // gzip压缩 生产环境生成 .gz 文件
  55. 55 viteCompression({
  56. 56 verbose: true,
  57. 57 disable: false,
  58. 58 threshold: 10240,
  59. 59 algorithm: 'gzip',
  60. 60 ext: '.gz'
  61. 61 }),
  62. 62 IS_PROD && viteSentry(sentryConfig)
  63. 63 ],
  64. 64 resolve: {
  65. 65 alias: {
  66. 66 // @ts-ignore
  67. 67 '@': path.resolve(__dirname, 'src')
  68. 68 }
  69. 69 },
  70. 70 css: {
  71. 71 preprocessorOptions: {
  72. 72 less: {
  73. 73 modifyVars: {
  74. 74 // antd 自定义主题 https://www.antdv.com/docs/vue/customize-theme-cn
  75. 75 'primary-color': '#1890ff',
  76. 76 'link-color': '#1890ff',
  77. 77 'border-radius-base': '2px'
  78. 78 },
  79. 79 additionalData: '@import "@/assets/style/common.less";',
  80. 80 javascriptEnabled: true
  81. 81 }
  82. 82 }
  83. 83 },
  84. 84 server: {
  85. 85 host: '0.0.0.0',
  86. 86 port: 8080,
  87. 87 open: false,
  88. 88 https: false,
  89. 89 proxy: {}
  90. 90 },
  91. 91 build: {
  92. 92 minify: 'terser',
  93. 93 terserOptions: {
  94. 94 compress: {
  95. 95 /* 清除console */
  96. 96 drop_console: true,
  97. 97 /* 清除debugger */
  98. 98 drop_debugger: true
  99. 99 }
  100. 100 },
  101. 101 rollupOptions: {
  102. 102 output: {
  103. 103 chunkFileNames: 'static/js/[name]-[hash].js',
  104. 104 entryFileNames: 'static/js/[name]-[hash].js',
  105. 105 assetFileNames: 'static/[ext]/[name]-[hash].[ext]',
  106. 106 manualChunks(id) {
  107. 107 //静态资源分拆打包
  108. 108 if (id.includes('node_modules')) {
  109. 109 return id.toString().split('node_modules/')[1].split('/')[0].toString()
  110. 110 }
  111. 111 }
  112. 112 }
  113. 113 },
  114. 114 sourcemap: IS_PROD
  115. 115 }
  116. 116 })

  1.3、封装全局方法,请求当前域名下的/version.json资源,将vite中定义的全局变量和当前域名下的json文件内容做对比,如果不一致,我们则认为发布了新版本

  1. 1 /** src/utils/checkVersion.ts **/
  2. 2 import { Modal } from 'ant-design-vue'
  3. 3 export default function versionCheck() {
  4. 4 const timestamp = new Date().getTime()
  5. 5 //import.meta.env.MODE 获取的是开发还是生产版本的
  6. 6 if (import.meta.env.MODE === 'development') return
  7. 7
  8. 8 fetch(`/version.json?t=${timestamp}`)
  9. 9 .then((res) => {
  10. 10 return res.json()
  11. 11 })
  12. 12 .then((response) => {
  13. 13 if (process.env.VITE__APP_VERSION__ !== response.version) {
  14. 14 Modal.confirm({
  15. 15 title: '发现新版本',
  16. 16 content: '检测到最新版本,刷新后立即使用...',
  17. 17 okText: '立即更新',
  18. 18 cancelText: '暂不更新',
  19. 19 onOk() {
  20. 20 window.location.reload()
  21. 21 }
  22. 22 })
  23. 23 }
  24. 24 })
  25. 25 }

        1.4 、在layout全局文件中,监听路由变化,去调版本检测的方法来决定是否弹出提醒(尊重用户的选择,是否更新页面由用户来决定)

  1. 1 /** src/layout/index.vue **/
  2. 2 watch(
  3. 3 () => router.currentRoute.value,
  4. 4 (newValue: any) => {
  5. 5 /** 判断是否有更高的版本 */
  6. 6 checkVersion()
  7. 7 },
  8. 8 { immediate: true }
  9. 9 )

 

2、微信小程序应用版本检测方案:

 流程图:

  技术栈:Taro-vue+ts+nut-ui (京东物流风格轻量移动端组件库)

   2.1、基于微信开发文档提供的getUpdateManager版本更新管理器api去实现版本更新的检测与新版本应用的下载,封装全局方法

  1. 1 /** 检查小程序版本更新 */
  2. 2 export function checkMiniProgramVersion() {
  3. 3 if (Taro.canIUse('getUpdateManager')) {
  4. 4 const updateManager = Taro.getUpdateManager();
  5. 5 updateManager.onCheckForUpdate(function (res) {
  6. 6 // 请求完新版本信息的回调
  7. 7 if (res.hasUpdate) {
  8. 8 Taro.showModal({
  9. 9 title: '新版本更新提示',
  10. 10 content: '检测到新版本,是否下载新版本并重启小程序?',
  11. 11 success: function (res) {
  12. 12 if (res.confirm) {
  13. 13 downloadAndUpdate(updateManager);
  14. 14 }
  15. 15 },
  16. 16 });
  17. 17 }
  18. 18 });
  19. 19 } else {
  20. 20 Taro.showModal({
  21. 21 title: '新版本更新提示',
  22. 22 showCancel: false,
  23. 23 content: '当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试。',
  24. 24 success: function () {
  25. 25 Taro.exitMiniProgram();
  26. 26 },
  27. 27 });
  28. 28 }
  29. 29 }
  30. 30
  31. 31 /** 新版本应用下载 */
  32. 32 export function downloadAndUpdate(updateManager) {
  33. 33 Taro.showLoading();
  34. 34 updateManager.onUpdateReady(function () {
  35. 35 Taro.hideLoading();
  36. 36 Taro.showModal({
  37. 37 title: '新版本更新提示',
  38. 38 content: '新版本已经准备好,是否重启应用?',
  39. 39 success: function (res) {
  40. 40 if (res.confirm) {
  41. 41 // 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
  42. 42 updateManager.applyUpdate();
  43. 43 }
  44. 44 },
  45. 45 });
  46. 46 });
  47. 47
  48. 48 updateManager.onUpdateFailed(function () {
  49. 49 Taro.showLoading();
  50. 50 Taro.showModal({
  51. 51 title: '新版本更新提示',
  52. 52 showCancel: false,
  53. 53 content: '新版本已经上线啦~,请您删除当前小程序,重新搜索打开哟~',
  54. 54 success: function () {
  55. 55 // 退出应用
  56. 56 Taro.exitMiniProgram();
  57. 57 },
  58. 58 });
  59. 59 });
  60. 60 }

  2.2、在app.ts入口文件onLaunch的生命周期钩子函数中去调用方法检测版本

  1. 1 // src/app.ts
  2. 2 import { createApp } from 'vue';
  3. 3 import Taro from '@tarojs/taro';
  4. 4 import './app.scss';
  5. 5 import store from './store';
  6. 6 import installPlugin from '@/plugins/index';
  7. 7 import { wxLogin, checkMiniProgramVersion } from '@/utils/common';
  8. 8
  9. 9 const App = createApp({
  10. 10 onLaunch() {
  11. 11 /** 检测小程序版本 */
  12. 12 checkMiniProgramVersion();
  13. 13 },
  14. 14 });
  15. 15
  16. 16 App.use(store);
  17. 17 installPlugin(App);
  18. 18
  19. 19 export default App;

 坑点Tips:

  小程序更新方案中由于受限于小程序的更新机制,第一次发版无效,因为微信小程序服务器上的版本中不存在checkMiniProgramVersion方法,所以无法执行;更新提示弹窗需要在第二次发版时才生效;

原文链接:https://www.cnblogs.com/dengyao-blogs/p/17708054.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号