WEB项目部署发版-通知用户在线更新方案

2.png

技术背景

项目使用的框架为vue2,构建工具为webpack

问题

项目迭代频繁,每次上线后,需要通知销售人员(用户)手动刷新,才可使用系统,不然会出现一直使用旧版本以及会出现一些不可预知的错误。

原因

vue框架开发是一种单页Web应用(SPA

通俗解释

尽在Web页面初始化时加载相应的HTML,JavaScript和CSS。一旦页面加载完成,SPA不会因为用户的操作而进行页面的重新加载或者跳转;取而代之的时利用路由机制实现HTML内容的变化,UI与用户的交互,避免页面的重新加载。

优点

用户体验好、快、内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复渲染;甚至于上面的一点,SPA相对对服务器压力小;前后端职责分离,架构清晰,前端进行交互逻辑,后端负责数据处理

缺点

初次加载耗时多;为实现单页Web应用功能及显示效果,需要在加载页面的时候将JavaScript、CSS统一加载,部分页面按需加载,前进后退路由管理。

总结

由于是单页面应用,用户一进入网站,就会把HTML与相对应的资源利用浏览器的缓存机制,停留在本地,这样的好处,就是再次进入网站,可以利用缓存机制,可快速进入网站。这也就造成了我们项目版本迭代后,用户因缓存机制,会继续使用旧迭代版本,需要用户手动刷新去服务器请求获取新的HTML,来使用新迭代版本。
用户手动刷新获取新版本html(需要在nginx 配置,在nginx.conf文件做设置,让 index.html 不缓存)

需求

项目迭代后,用户使用会有版本更新的提示或者自动刷新,实现版本升级用户有感知

方案

原理图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ucsUviTR-1677222865792)(null#lake_card_v2=eyJ0eXBlIjoibWVybWFpZCIsImNvZGUiOiJncmFwaCBURFxuXG5BW-aJk-W8gOe9keWdgF0gLS0-fCDmjqXlj6NB54mI5pys5Y-3IHwgQlxuQSAtLT4gfCDpnZnmgIHpobVC54mI5pys5Y-3IHwgQltB54mI5pys5Y-3ID89ICBC54mI5pys5Y-3XVxuQsKgLS0-fOebuOetiXzCoENb5LiN5YGa5pON5L2cXVxuQsKgLS0-fOS4jeebuOetiXzCoERb6Ieq5Yqo5Yi35pawXVxuXG4iLCJ1cmwiOiJodHRwczovL2Nkbi5ubGFyay5jb20veXVxdWUvX19tZXJtYWlkX3YzL2IzYTBkZTk0ZGM3MGM3NzA2OWYwMTM0YWExMmZhZjBjLnN2ZyIsImlkIjoiSVFUamIiLCJtYXJnaW4iOnsidG9wIjp0cnVlLCJib3R0b20iOnRydWV9LCJjYXJkIjoiZGlhZ3JhbSJ9)]

版本号为打包是自动创建的当前时间戳
接口获取的版本号:是webpack在构建的时候自动创建的版本号,生成 一个版本接口文件
静态页版本号:webpack构建过程中自动创建的版本号,自动写入index.html页面meta信息中

代码

nginx

配置-在nginx.conf文件做设置,让 index.html 不缓存

location = /index.html {
  root	 /usr/share/nginx/html;
  add_header Cache-Control "no-cache, no-store";
}

version.js

创建版本文件

const fs = require('fs')  // 引入文件模块
const Timestamp = new Date().getTime()
fs.writeFile('public/version.json', '{"version":' + Timestamp + '}\n', function (err) {
  if (err) {
    return console.log(err)
  }
  })

package.json

vue 构建命令:

"build:prodb": "node version.js && vue-cli-service build --mode prodb"

version.js为版本号自动生成的文件,为请求接口所用。

vue.config.js

vue2-配置文件-vue.config.js

// 获取版本号数据
const bpmVersion = process.env.NODE_ENV === 'production' 
|| process.env.NODE_ENV === 'prodb' ? require('./public/version.json') : {
  version: 'dev'
} 
module.exports = {
  pages: {
    index: {
      // page 的入口
      entry: 'src/main.js',
      // 模板来源
      template: 'public/index.html',
      // 在 dist/index.html 的输出
      filename: 'index.html',
      version: bpmVersion.version, // 版本号
      // 在这个页面中包含的块,默认情况下会包含
      // 提取出来的通用 chunk 和 vendor chunk。
      chunks: ['chunk-vendors', 'chunk-common', 'index']
    }
  }

index.html

index.html-页面配置版本号字段存储

<meta name="version" content="<%= htmlWebpackPlugin.options.version%>" />

generate-asset-webpack-plugin

也可以通过generate-asset-webpack-plugin插件创建

const GeneraterAssetPlugin = require('generate-asset-webpack-plugin');
const {
    name
} = require('./package.json');
const timestamp = new Date().getTime();
const version = `v${timestamp}`;

const createJson = function () {
    const data = {
        app: {
            name,
            version
        }
    };

    return JSON.stringify(data);
};
plugins: [
 // 生成版本标识
  new GeneraterAssetPlugin({
      filename: 'app.json',
      fn: (compilation, cb) => {

          cb(null, createJson());
      }
  })
],

chainWebpack: (config) => {
    config
        .plugin('html')
        .tap(args => {
            args[0].name = name;
            args[0].version = timestamp;
            return args
        });
}

生成app.json文件内容如下:

{"app":{"name":"app-name","version":"v1649818515910"}}

目前是页面的版本号与接口的版本号,都已经准备就绪。剩下来就是两个版本比对。
关于比对,为了避免不必要的接口比对,特意将比对时机定格在进入路由-加载页面完成之后,这样用户体验效果会好些(纯粹个人体会)。

router.js

比对代码
router.js

router.afterEach(async (to, form) => {
  // 生产环境提示升级
  if (process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'prodb') {
    const checkVersion = await store.dispatch('checkVersion')
    if (!checkVersion) { // 获取的版本号不等时
      Message.warning('正在自动升级新版本...', 2, () => {
        window.location.reload() // 版本不同 刷新 获取最新版本
      })
    }
  }
})

store.js

store.js

actions: {
  checkVersion ({ commit, state }) {
    return new Promise(resolve => {
      Axios.get('/version.json?v=' + new Date().getTime(), 
                { headers: { 'Cache-Control': 'no-cache' }, 
                 baseURL: window.location.origin })
      //反正就是要请求到json文件的内容, 并且禁止缓存
        .then(res => {
        const version = res.version
        const clientVersion = Number(document.querySelector('#BPMVersion').content 
                                     || '')
        resolve(version === clientVersion)
      })
    })
  }
}

优化

功能目前是可以达到需求要求,但我们还可以加入版本号的查看,方便知道目前使用的是哪个版本 以及什么时候上线的

store.js

checkVersion ({ commit, state }) {
  return new Promise(resolve => {
    Axios.get('/version.json?v=' + new Date().getTime(), 
              { headers: { 'Cache-Control': 'no-cache' },
               baseURL: window.location.origin })
    // 反正就是要请求到json文件的内容, 并且禁止缓存
      .then(res => {
      const version = res.version
      const clientVersion = Number(document.querySelector('#BPMVersion')
                                   .content || '')
      // 以下是查看版本号上线时间 - start
      console.info('%c Environment ' + '%c ' + process.env.NODE_ENV + ' ', 
                   'padding: 1px; border-radius: 3px 0 0 3px; 
                   color: #fff; background:#606060', 
                   'padding: 1px; border-radius: 0 3px 3px 0;
                   color: #fff; background:#42c02e')
                   console.info('%c Build Date ' + '%c ' + 
                   dateFtt('yyyy-MM-dd hh:mm:ss', 
                   new Date(clientVersion)) + ' ', 
        'padding: 1px; border-radius: 3px 0 0 3px; 
      color: #fff; background:#606060',
      'padding: 1px; border-radius: 0 3px 3px 0;
      color: #fff; background:#1475b2')
      console.info('%c Last Build Date ' + '%c ' + 
                   dateFtt('yyyy-MM-dd hh:mm:ss',
                           new Date(version)) + ' ',
                   'padding: 1px; border-radius: 3px 0 0 3px;
                   color: #fff; background:#606060',
                   'padding: 1px; border-radius: 0 3px 3px 0;
                   color: #fff; background:#1475b2')
                   // -end
                   resolve(version === clientVersion)
    })
  })
    }

版本号查看效果

页面提示

image.png

控制台输出


下期预告

针对目前项目中使用webpack打包速度越来越慢,希望自己在vite工具做多一些尝试,等踩完坑之后。4月底会出vite与webpack的对比文章及实例,以及踩到的所有坑分享给大家

写到最后

目前代码只适用于vue2版本,其里面原理可以借鉴到其他框架。因方案全程只是前端自己参与,所以在每次切换路由的时候,会造成需要请求一次版本号接口的比对,会造成接口的些许浪费吧,目前暂时没有想到更好的办法来解决这个问题,期待后续会有优化这方面的方案吧。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值