欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

前端項(xiàng)目部署后如何提示用戶版本更新詳解

 更新時(shí)間:2024年03月30日 09:24:48   作者:不叫貓先生  
這篇文章主要給大家介紹了關(guān)于前端項(xiàng)目部署后如何提示用戶版本更新的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),對(duì)大家的工作或者學(xué)習(xí)具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

前言

項(xiàng)目部署上線后,特別是網(wǎng)頁(yè)項(xiàng)目,提示正在操作系統(tǒng)的用戶去更新版本非常 important。一般我們都會(huì)用“刷新大法”來(lái)清理緩存,但是對(duì)于正在操作網(wǎng)頁(yè)的用戶,不造系統(tǒng)更新了,請(qǐng)求的還是老版本的資源。

為了確保用戶能夠及時(shí)獲得最新的功能和修復(fù)的 bug,我們需要通知用戶刷新頁(yè)面獲取最新的代碼。

解決方案

每次打包時(shí),都生成一個(gè)時(shí)間戳,作為系統(tǒng)的偽版本,放到JSON文件中,通過(guò)對(duì)比文件的響應(yīng)頭Etag判斷是否有更新。具體步驟如下:

  • 在public文件夾下加入manifest.json文件,里面存放兩個(gè)字段:更新內(nèi)容、更新時(shí)間戳
  • 前端打包的時(shí)候向manifest.json寫(xiě)入當(dāng)前時(shí)間戳信息
  • 在入口文件main.js中引入檢查版本更新的邏輯,有更新則提示更新。有兩種方式提示提示用戶:
    • 路由守衛(wèi)router.beforeResolve(Vue-Router為例),檢查更新,對(duì)比manifest.json文件的響應(yīng)頭Etag判斷是否有更新
    • 通過(guò)Worker輪詢,檢查更新,對(duì)比manifest.json文件的響應(yīng)頭Etag判斷是否有更新。Worker線程并不影響其他線程的邏輯。

整體邏輯如下所示:

1、public目錄下新建manifest.json

{
   "timestamp":21312321311,
   "msg":"更新內(nèi)容如下:\n--1.添加系統(tǒng)更新提示機(jī)制"
}

2、寫(xiě)入當(dāng)前時(shí)間戳到manifest.json

vue.config.js文件中

const { readFile, writeFile } = require('fs')
// 獲取路徑
const filePath = path.resolve(`./public`, 'manifest.json')
// 讀取文件內(nèi)容
readFile(filePath, 'utf8', (err, data) => {
  if (err) {
    console.error('讀取文件時(shí)出錯(cuò):', err)
    return
  }
  // 將文件內(nèi)容轉(zhuǎn)換JSON
  const dataObj = JSON.parse(data)
  //修改時(shí)間戳
  dataObj.timestamp = new Date().getTime()
  // 將修改后的內(nèi)容寫(xiě)回文件
  writeFile(filePath, JSON.stringify(dataObj), 'utf8', err => {
    if (err) {
      console.error('寫(xiě)入文件時(shí)出錯(cuò):', err)
      return
    }
  })
})

3、檢查版本更新

新建 checkUpdate.js 文件

(1)初始化變量

import Worker from "./checkUpdate.worker.js";
import router from '../router'
//上次的Etag
let lastEtag = '';
//是否更新
let hasUpdate = false
//創(chuàng)建worker線程
const worker = new Worker();

(2)檢查版本更新

//檢查版本更新
async function checkUpdate() {
  try {
    // 檢測(cè)前端資源是否有更新
    let response = await fetch(`/manifest.json?v=${Date.now()}`, {
      method: 'head'
    })
    // 獲取最新的etag  
    let etag = response.headers.get('etag')
    hasUpdate = lastEtag && etag !== lastEtag
    lastEtag = etag
  } catch (e) {
    return Promise.reject(e)
  }
}

其中let response = await fetch(/manifest.json?v=${Date.now()}, { method: 'head' })
使用 fetch 函數(shù)發(fā)起了一個(gè) HTTP 請(qǐng)求,獲取了指定資源的頭信息(HTTP 頭部)。其中 manifest.json 是要請(qǐng)求的資源,Date.now() 會(huì)生成當(dāng)前時(shí)間的時(shí)間戳,作為查詢參數(shù) v 的值,這樣可以避免瀏覽器緩存,強(qiáng)制獲取最新的資源。請(qǐng)求方式為 HEAD,這意味著只請(qǐng)求資源的頭部信息而不獲取具體的內(nèi)容。

let etag = response.headers.get('etag'),從 HTTP 響應(yīng)中獲取了 ETag 頭部信息,ETag 是服務(wù)器生成的資源唯一標(biāo)識(shí),用于檢查資源是否發(fā)生了變化。具體比較邏輯如下:

1、客戶端發(fā)起請(qǐng)求,請(qǐng)求中包含上次獲取的資源的ETag。
2、服務(wù)器收到請(qǐng)求后,比較客戶端提供的ETag與當(dāng)前資源的ETag是否一致。
3、如果一致,則返回HTTP 304 Not Modified響應(yīng),表示資源未發(fā)生變化,客戶端可以使用緩存的版本。
4、如果不一致,服務(wù)器返回最新的資源內(nèi)容,同時(shí)更新ETag。
5、客戶端收到響應(yīng)后,更新本地緩存的資源內(nèi)容和ETag。

(3)路由跳轉(zhuǎn)檢測(cè)版本更新

 // 路由攔截
 router.beforeEach(async (to, from, next) => {
  next()
  try {
    await checkUpdate()
    if (hasUpdate) {
      worker.postMessage({
        type: 'destroy'
      })
      location.reload()
    }
  } catch (e) {}
})

(4)向worker線程發(fā)送檢查版本更新邏輯

worker.postMessage({
  type: 'check'
})

(5)接收到 worker 線程數(shù)據(jù)更新

worker.onmessage = ({ data }) => {
  console.log(data,'data')
  if (data.type === 'hasUpdate') {
    hasUpdate = true
    confirmReload(data.msg, data.lastEtag)
  }
}

(6)收到版本更新信息,進(jìn)行彈框提示

收到版本更新信息后,先暫停輪詢檢查版本更新,點(diǎn)擊確定按鈕,則發(fā)送destory消息,點(diǎn)擊取消按鈕則發(fā)送recheck消息

async function confirmReload(msg = '', lastEtag) {
  worker &&
    worker.postMessage({
      type: 'pause'
    })
  try {
  //彈框提示邏輯
  } catch (e) { }
}

checkUpdate.js 全部代碼實(shí)現(xiàn)

import Worker from "./checkUpdate.worker.js";
import router from '../router'
//上次的Etag
let lastEtag = '';
//是否更新
let hasUpdate = false
//創(chuàng)建worker線程
const worker = new Worker();

//檢查版本更新
async function checkUpdate() {
  try {
    // 檢測(cè)前端資源是否有更新
    let response = await fetch(`/manifest.json?v=${Date.now()}`, {
      method: 'head'
    })
    // 獲取最新的etag  
    let etag = response.headers.get('etag')
    hasUpdate = lastEtag && etag !== lastEtag
    lastEtag = etag
    console.log(lastEtag = etag,'lastEtag = etag')
  } catch (e) {
    return Promise.reject(e)
  }
}

async function confirmReload(msg = '', lastEtag) {
  worker &&
    worker.postMessage({
      type: 'pause'
    })
  try {
    console.log('版本更新了')
  } catch (e) { }
}
 // 路由攔截
 router.beforeEach(async (to, from, next) => {
  next()
  try {
    await checkUpdate()
    if (hasUpdate) {
      worker.postMessage({
        type: 'destroy'
      })
      location.reload()
    }
  } catch (e) {}
})

worker.postMessage({
  type: 'check'
})


worker.onmessage = ({ data }) => {
  console.log(data,'data')
  if (data.type === 'hasUpdate') {
    hasUpdate = true
    confirmReload(data.msg, data.lastEtag)
  }
}

4、woker線程

新建 checkUpdate.worker.js

(1)初始化變量

let lastEtag;//上次的Etag
let hasUpdate = false;//是否更新
let intervalId = '';

(2)檢查版本更新

邏輯更第三步差不多,唯一一點(diǎn)就是檢測(cè)到更新后,發(fā)送hasUpdate消息,給出彈框提示是否需要更新

async function checkUpdate() {
  try {
    // 檢測(cè)前端資源是否有更新
    let response = await fetch(`/manifest.json?v=${Date.now()}`, {
      method: 'get'
    })
    // 獲取最新的etag和data
    let etag = response.headers.get('etag')
    let data = await response.json()
    hasUpdate = lastEtag !== undefined && etag !== lastEtag
  
    if (hasUpdate) {
      postMessage({
        type: 'hasUpdate', 
        msg: data.msg,
        lastEtag: lastEtag,
        etag: etag
      })
    }
    lastEtag = etag
  } catch (e) {
    return Promise.reject(e)
  }
}

(3)監(jiān)聽(tīng)主線程發(fā)送過(guò)來(lái)的數(shù)據(jù)

// 監(jiān)聽(tīng)主線程發(fā)送過(guò)來(lái)的數(shù)據(jù)
addEventListener('message', ({ data }) => {
  console.log(data,'消息')
  if (data.type === 'check') {  
    // 每5分鐘執(zhí)行一次
    // 立即執(zhí)行一次,獲取最新的etag,避免在setInterval等待中系統(tǒng)更新,第一次獲取的etag是新的,但是lastEtag還是undefined,不滿足條件,錯(cuò)失刷新時(shí)機(jī)
    // checkUpdate()
    intervalId = setInterval(()=>{
      checkUpdate()
      //這里3s方便測(cè)試
    },  3 * 1000)
  }
  if (data.type === 'recheck') {
    // 每5分鐘執(zhí)行一次
    hasUpdate = false
    lastEtag = data.lastEtag
    intervalId = setInterval(()=>{
      checkUpdate()
    },  3 * 1000)
  }
  if (data.type === 'pause') {
    clearInterval(intervalId)
  }
  if (data.type === 'destroy') {
    clearInterval(intervalId)
    close()
  }
})

完整代碼邏輯如下:

let lastEtag
let hasUpdate = false
let intervalId = ''
async function checkUpdate() {
 
  try {
    // 檢測(cè)前端資源是否有更新
    let response = await fetch(`/manifest.json?v=${Date.now()}`, {
      method: 'get'
    })
    // 獲取最新的etag和data
    let etag = response.headers.get('etag')
    let data = await response.json()
    hasUpdate = lastEtag !== undefined && etag !== lastEtag
  
    if (hasUpdate) {
      postMessage({
        type: 'hasUpdate', 
        msg: data.msg,
        lastEtag: lastEtag,
        etag: etag
      })
    }
    lastEtag = etag
  } catch (e) {
    return Promise.reject(e)
  }
}

// 監(jiān)聽(tīng)主線程發(fā)送過(guò)來(lái)的數(shù)據(jù)
addEventListener('message', ({ data }) => {
  console.log(data,'消息')
  if (data.type === 'check') {  
     console.log('checkcheckcheck')
    // 每5分鐘執(zhí)行一次
    // 立即執(zhí)行一次,獲取最新的etag,避免在setInterval等待中系統(tǒng)更新,第一次獲取的etag是新的,但是lastEtag還是undefined,不滿足條件,錯(cuò)失刷新時(shí)機(jī)
    // checkUpdate()
    intervalId = setInterval(()=>{
      checkUpdate()
      console.log('檢查版本更新')
    },  3 * 1000)
  }
  if (data.type === 'recheck') {
    // 每5分鐘執(zhí)行一次
    hasUpdate = false
    lastEtag = data.lastEtag
    intervalId = setInterval(()=>{
      checkUpdate()
      console.log('檢查版本更新')
    },  3 * 1000)
    console.log('recheckrecheckrecheck')
  }
  if (data.type === 'pause') {
    clearInterval(intervalId)
  }
  if (data.type === 'destroy') {
    clearInterval(intervalId)
    close()
  }
})

5、入口文件引入

import "@/utils/checkUpdate.js"

可能出現(xiàn)的問(wèn)題

1、worker

webpack 5 可以使用 Web Workers

new Worker(new URL('./checkUpdate.worker.js', import.meta.url));

webpack 5 以下,使用 worker-loader,先安裝worker-loader

yarn add worker-loader -D

然后在vue.config.js 配置

  chainWebpack(config) {
    config.module
    .rule('worker')
    .test(/\.worker\.js$/)
    .use('worker')
    .loader('worker-loader')
    .end()
  }

如果配置有問(wèn)題,會(huì)一直出現(xiàn)下面這個(gè)問(wèn)題,worker-loader 的配置要放在其他 loader 前。

總結(jié) 

到此這篇關(guān)于前端項(xiàng)目部署后如何提示用戶版本更新的文章就介紹到這了,更多相關(guān)前端提示用戶版本更新內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論