前端部署后自动提醒用户更新

2024-11-09 09:02   重庆  

点击关注公众号,“技术干货” 及时达!

前言

前端项目经常碰到更新部署了,但是更新过的功能并没有及时的展示,还需要刷新一下页面,才能看到最新的内容。如果是远程给客户进行的部署,还要口头告知客户需要刷新,体验不友好。

技术涉及

vue、webpack、js等。

问题思考

想要解决整个问题的关键点在于,检测部署文件的变化。部署文件的变化,前后端都可以做,或者配合一起来完成。纯前端实现的话,就是需要前端自己打包文件的变更进行一个变动检测,如果当前文件与上次部署文件发生变化,那么就得提醒需要刷新,或者自动刷新。前端文件变化,主要在打包后的js、css、以及html的文件变化。而后端的话,主要是记录更新日志记录,检测到版本更新日志变化,那么就得告知前端个进行更新,这里主要通过接口的形式告知版本信息,前端根据接口信息进行更新。

实现方案

方案一:生成git提交的hash信息json文件,请求本地json文件获取更新信息

在项目中一直使用插件git-revision-webpack-plugin,记录前端项目的git提交信息,以便于运维人员进行版本比对和维护。

「安装依赖」

npm install git-revision-webpack-plugin --save-dev

「webpack主要打包配置中引入git-revision-webpack-plugin插件」

引入GitRevisionPlugin
const GitRevisionPlugin = require('git-revision-webpack-plugin')
const gitRevisionPlugin = new GitRevisionPlugin()

「webpack插件配置plugins以及生成version.json」

 plugins: [
 //配插件
  new GitRevisionPlugin(),
  
 //在dist或者自定义的打包输出目录下生成包含hash的json
     {
      apply(compiler) => {
        compiler.plugin('emit', (compilation, callback) => {
          // 获取 Git 版本和哈希
          const version = gitRevisionPlugin.version();
          const hashCommit = gitRevisionPlugin.commithash();

          const versionInfo = {
            version,
            hashcommit,
          };
          // 将 version.json 文件添加到 compilation.assets 中
          compilation.assets['version.json'] = {
            source() => JSON.stringify(versionInfo, null2), // 文件内容
            size() => JSON.stringify(versionInfo).length,      // 文件大小
          };
          // 确保回调函数被调用,通知 Webpack 继续处理
          callback();
        });
      },
    },
 ]

在这里要注意两点:一是apply中compiler的写法,比如在高版本中使用compiler.hooks.emit。emit参数的意思是生成打包文件时,当然还有其他一些周期性参数,可以查看webpack官方文档。二是js将对象versionInfo转成json文件。

「version.json文件内容」

{
  "version""Afmos3.00.1-alpha-176-ge10504cc",
  "hashcommit""e10504cc8e9dd629685713f1d2a57322ab5b48c5"
}

「打包成功后截图示例」

「写一个mixins来监听版本文件变化」

利用vue的mixins混淆功能,创建一个自定义的hashVersion.js

export const hashVersionMixins = {
  data () {
    return {
      current_hash: localStorage.getItem('location_hash') || '',
      new_hash''
    }
  },
  created () {
    this.checkVersion()
  },
  methods: {
    async checkVersion () {
      try {
        const res = await this.$http.get('/version.json?date=' + Date.now())
        this.new_hash = res.data.hashcommit
        if (this.new_hash !== this.current_hash) {
          localStorage.setItem('location_hash'this.new_hash)
          this.$notify({
            title'Afmos系统提醒',
            message'有新版本更新啦~请刷新页面查看最新内容',
            type'success'
          })
        }
      } catch (error) {
        console.error('获取版本信息失败:', error)
      }
    }
  }
}

在这里只做了一个弹框信息提醒,当然也可以根据实际需求进行直接刷新或者定时器之后再刷新。

setTimeout(() => { 
  window.location.reload(); 
}, 5000); // 5秒后自动刷新页面

「在App组件中使用」

import { hashVersionMixins } from '@/mixins/hashVersion'

export default {
 mixins:[hashVersionMixins],
}

「方案一更新提醒截图」

「优缺点:」

  1. 全部在前端做工作量多了一些,但是对自己也是一种学习和进步。
  2. 后端可能需要配置静态文件指定路径,比如在python环境中指定了静态文件static,此时前端的version.json与index同级,会拿不到文件,要再次将文件移到前端的static下。或者在webpack打包配置中,直接写入到static中。
  3. 只更新了后端部分,前端文件不更新的话,hash值也没有改变。

方案二:记录更新日志,通过接口返回更新版本号

每个项目进行更新,都会有更新记录,比如每次更新,会把本次更新的内容记录到readme中,方便其他人员查看。在发布部署时也需要记录当前更新的内容。在这就可以做一个版本号管理和更新记录。再暴露出一个方法,进行查询记录。

「前端通过接口获取版本号」

<script>
import { softVersion } from '@/request/api/information'
export default {
  data () {
      version_num:localStorage.getItem('version_num') || ''
  }
}
methods:{
  async getVersion() {
    const res = await softVersion({})
    if (res.result) {
        const new_version = res.data[0].version_num
        if (new_version !== this.version_num) {
          localStorage.setItem('version_num'this.new_version)
          this.$notify({
            title'Afmos系统提醒',
            message'有新版本更新啦~请刷新页面查看最新内容',
            type'success'
          })
        }
        
    } else {
      this.$message.error(res.msg);
    }
  }
}
</script>

「优缺点:」

  1. 无论前后端更新都能及时的获取到更新的版本和信息
  2. 工作量问题,以及方案的实施需要多方人员配合。毕竟有的人呀,只要是没有领导说明和写在需求里面的,那就是不知道,不清楚,我不做,压根不会去给自己增加额外的工作量。

方案三:比对前端打包后的index.html中js中文件名hash值

「Webpack 配置确保生成带 hash 的文件」

确保 Webpack 配置中开启了带有内容hash值的文件名输出,这样在每次打包时,如果文件内容发生变化,生成的js文件名会带上新的hash值。

module.exports = {
  output: {
    filename'[name].[contenthash].js'// 确保文件名带有 hash
    path: path.resolve(__dirname, 'dist'),
  },
  // 其他配置...
};

「构建前端 hash 值提取功能」

首先,需要在打包后提取出 index.html 中的 JS 文件 hash 值。通常,Vue 项目通过 Webpack 打包时,生成的 JS 文件名会带有 hash 值(例如:app.123abc456.js)。我们可以通过正则表达式从 index.html 中提取这些 hash 值。

// 假设是通过 AJAX 请求或 fetch 方式来获取 index.html
function extractHashFromHtml(htmlContent{
  const scriptRegex = /<script\s+[^>]*lay-src="([^"]+\.js)"/g;
  const hashes = [];
  let match;
  while ((match = scriptRegex.exec(htmlContent)) !== null) {
    const scriptSrc = match[1];
    const hashMatch = scriptSrc.match(/(\w+)\.js$/);
    if (hashMatch) {
      hashes.push(hashMatch[1]);
    }
  }
  return hashes;
}

「保存和比较 hash 值」

每次加载应用时,将当前页面的 hash 值与之前保存的 hash 值进行比对。如果 hash 值发生变化,则表明前端文件已更新,可以提示用户刷新页面。你可以将 hash 值存储在 localStorage 中。

function checkForUpdates({
  fetch('/index.html', { cache'no-store' }) // 确保获取的是最新的 index.html
    .then(response => response.text())
    .then(htmlContent => {
      const newHashes = extractHashFromHtml(htmlContent);
      const oldHashes = JSON.parse(localStorage.getItem('appHashes')) || [];

      // 比较 hash 值
      if (JSON.stringify(newHashes) !== JSON.stringify(oldHashes)) {
        // 如果有变化,提示用户
        alert('新版本已经发布,请刷新页面以获取最新内容!');
        // 更新存储的 hash 值
        localStorage.setItem('appHashes'JSON.stringify(newHashes));
      }
    })
    .catch(error => console.error('Error fetching index.html:', error));
}

// 页面加载时检查更新
window.addEventListener('load', checkForUpdates);

总结

这里涉及到了webpack的配置和node的一些内容。webpack依赖node的环境,所以在webpcak的配置中就能使用node中自带的fs以及path,在指定的地方输出或者生成我们需要的内容信息。

点击关注公众号,“技术干货” 及时达!

稀土掘金技术社区
掘金,一个帮助开发者成长的技术社区
 最新文章