乐趣区

关于javascript:WEB项目部署发版通知用户在线更新方案

技术背景

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

问题

我的项目迭代频繁,每次上线后,须要告诉销售人员(用户)手动刷新,才可应用零碎,不然会呈现始终应用旧版本以及会呈现一些不可预知的谬误。

起因

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

艰深解释

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

长处

     用户体验好、快、内容的扭转不须要从新加载整个页面,防止了不必要的跳转和反复渲染;甚至于下面的一点,SPA 绝对对服务器压力小;前后端职责拆散,架构清晰,前端进行交互逻辑,后端负责数据处理

毛病

     首次加载耗时多;为实现单页 Web 利用性能及显示成果,须要在加载页面的时候将 JavaScript、CSS 对立加载,局部页面按需加载,后退后退路由治理。

总结

     因为是单页面利用,用户一进入网站,就会把 HTML 与绝对应的资源利用浏览器的缓存机制,停留在本地,这样的益处,就是再次进入网站,能够利用缓存机制,可疾速进入网站。这也就造成了咱们我的项目版本迭代后,用户因缓存机制,会持续应用旧迭代版本,须要用户手动刷新去服务器申请获取新的 HTML,来应用新迭代版本。

     用户手动刷新获取新版本 html(须要在 nginx 配置,在 nginx.conf 文件做设置,让 index.html 不缓存)

需要

我的项目迭代后,用户应用会有版本更新的提醒或者主动刷新,实现版本升级用户有感知

计划

原理图

版本号为打包是主动创立的以后工夫戳
接口获取的版本号:是 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)
    })
  })
    }

版本号查看成果

页面提醒

控制台输入

下期预报

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

写到最初

     目前代码只实用于 vue2 版本,其外面原理能够借鉴到其余框架。因计划全程只是前端本人参加,所以在每次切换路由的时候,会造成须要申请一次版本号接口的比对,会造成接口的些许节约吧,目前临时没有想到更好的方法来解决这个问题,期待后续会有优化这方面的计划吧。

团队介绍

高灯科技交易合规前端团队(GFE), 隶属于高灯科技 (北京) 交易合规业务事业线研发部,是一个富裕激情、充斥创造力、保持技术驱动全面成长的团队, 团队平均年龄 27 岁,有在各自畛域深耕多年的大牛, 也有刚刚毕业的小牛, 咱们在工程化、编码品质、性能监控、微服务、交互体验等方向踊跃进行摸索, 谋求技术驱动产品落地的主旨,打造欠缺的前端技术体系。

  • 愿景: 成为最值得信赖、最有影响力的前端团队
  • 使命: 保持客户体验第一, 为业务发明更多可能性
  • 文化: 敢于承当、深刻业务、集思广益、简略凋谢

Github:github.com/gfe-team

团队邮箱:gfe@goldentec.com

作者:GFE 团队

著作权归作者所有。商业转载请分割作者取得受权,非商业转载请注明出处。

退出移动版