日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > HTML >内容正文

HTML

实践总结 3 种前端部署后页面检测版本的方法

發布時間:2024/1/11 HTML 53 coder
生活随笔 收集整理的這篇文章主要介紹了 实践总结 3 种前端部署后页面检测版本的方法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

領導:為什么每次項目部署后,有的用戶要清緩存才能看到最新的頁面

我:瀏覽器有默認的緩存策略,如果服務器在響應頭中沒有禁用緩存,那么瀏覽器每次請求頁面會先看看緩存里面有沒有,有的話從緩存取,造成還是取的舊頁面。正常來說,用戶只需要點擊刷新按鈕,刷新一下頁面就好了,不必清除瀏覽器緩存刷新。

領導:為什么緩存這么嚴重,有的用戶清除緩存刷新還是不行,關掉瀏覽器重新進來還是不行,要重啟電腦才有效。

我:要重啟電腦?這 。。。。。。用戶都這樣么,還是只有一小部分用戶。

領導:不是所有的用戶,有個別用戶會出現這種情況

我:那可能得到用戶電腦上看看了

每次需求投產后,因為有緩存問題導致用戶看到的還是舊版內容,使用過程中出現了問題,聯系我們才知道項目更新了,用戶體驗不好;

于是查找資料,尋找合適的方案,根據 評論區 的討論,實踐總結了下面 3 種前端部署后頁面檢測版本更新的方法

當檢測到版本更新則及時通知用戶,用戶可以選擇是否立即更新,并不會影響用戶當前進行的業務;

下面以 vue 項目為例

1、輪詢打包后的 index.html,比較生成的 js 文件的 hash

項目打包后,index.html 會包含打包后的 js 文件,這些文件的文件名包含的 hash 將會和上一次打包的不同,比較 hash 也就能判斷是否有版本更新;

let firstV = [] //記錄初始獲得的 script 文件字符串
let currentv = [] //記錄當前獲得的 script 文件字符串

// 獲得的文件字符串類似這樣 `<script src="/js/chunk-vendors.1234fff.js"></script>`

async function getHtml() {
let res = await axios.get('/index.html?date=' + Date.now())
    if (res.status == '200') {
        let text = res.data
        if (text) {
            // 解析 html 內容,匹配 script 字符串
            let reg = /<script([^>]+)><\/script>/ig
            return text.match(reg) 
        }
    }
    return []
}
function isEqual(a, b) {
    return a.length = Array.from(new Set(a.concat(b))).length
}

export async function checkIfNewVersion() {

    firstV = await getHtml()

    window.checkVersionInterval && clearInterval(window.checkVersionInterval)

    window.checkVersionInterval = setInterval(async () =>{

        currentV = await getHtml()
        console.log(firstV,currentv)
        // 當前 script hash 和初始的不同時,說明已經更新
        if(!isEqual(firstV, currentv)) {
            console.log('已更新')
        }
    },3000)
}

// 文檔可見時檢測版本是否更新
document.addEventListener("visibilitychange", () => {
  if (document.visibilityState === "visible") {
    checkIfNewVersion();
  } else {
    window.checkVersionInterval && clearInterval(window.checkVersionInterval)
  }
});

getHtml() 得到的結果示例如下:

[
    '<script src="/js/chunk-vendors.1234fff.js"></script>',
    '<script src="/js/app.1234fff.js"></script>',
]

改動了一點業務代碼后,再次打包,上面 app.js 的 hash 就會發生變化

[
    '<script src="/js/chunk-vendors.1234fff.js"></script>',
    '<script src="/js/app.12ed5ca.js"></script>',
]

比較兩個的結果,如果結果不一樣,則代表有版本更新。

2、HEAD 方*詢響應頭中的 etag

ETag 是資源的特定版本的標識符。當資源內容發生變化時,會生成新的 ETag
HEAD?方法請求資源的響應頭信息,服務器不會返回響應體,可以節省帶寬資源;

這里可以輪詢打包后的 index.html,取兩次響應頭中的 eTag 比較,如果不同,說明版本更新了;前提是服務器沒有禁用緩存。

let firstEtag = `` //記錄第一次進來請求獲得的 etag
let currentEtag = `` //記錄當前的 etag,會不斷的刷新

async function getEtag(){
    let res = await axios.head('/index.html')
    if(res.status == '200'){
        if(res.headers && res.headers.etag){
            return res.headers.etag
        }
    }
    return ''
}

export async function checkEtag() {

    firstEtag = await getEtag()

    window.checkEtagInterval && clearInterval(window.checkEtagInterval)

    window.checkEtagInterval = setInterval(async() =>{
        // 每隔一定時間請求最新的 etag
        currentEtag = await getEtag()
        // 當前最新的 currentEtag 和初始 firstEtag 進行比較,不同則說明資源更新了;
        if(firstEtag && currentEtag && firstEtag!==currentEtag){
            console.log('已更新')
        }
    },3000)
}

// 文檔可見時檢測版本是否更新
document.addEventListener("visibilitychange", () => {
  if (document.visibilityState === "visible") {
    checkEtag();
  } else {
    window.checkEtagInterval && clearInterval(window.checkEtagInterval)
  }
});

3、監聽 git commit hash 變化

項目改動提交 git 時會生成唯一的 hash 字符串,將最近提交的 commit hash 作為版本號保存在一個 json 文件中;通過輪詢 json 文件,檢測里面的版本號是否和上次不同,不同則表示有版本更新;

監聽 git commit hash 變化的好處是只要投產的版本有 git 提交記錄,而不管靜態文件變化還是代碼變化,都能檢測到版本更新;

在 vue.config.js 中引入 git-revision-webpack-plugin,該插件可獲取到項目本地 git 的最新提交 commit hash

const GitRevisionPlugin  = require('git-revision-webpack-plugin')
const gitRevision = new GitRevisionPlugin()

const { writeFile , existsSync } = require('fs')
if(existsSync('./public')){
    fs.writeFile(
        './public/version.json', 
        `{"commitHash":${JSON.stringify(gitRevision.commithash())}`, 
        (error) =>{}
    )
}

上面代碼使用 gitRevision.commithash() 獲取 commit hash,將其存入到 public/versionHash.json 文件中;

項目打包會執行上面的代碼,生成后的 'versionHash.json' 文件類似這樣

// 示例
{ "commitHash" : "234fjsdr322f32f322f32f3g32g23jglk32gjkl32lg3" }

項目改動后,提交改動的地方后,再次打包,會將最新的 commit hash 存入到 public/versionHash.json

// 示例
{ "commitHash" : "234fjsdr322f3eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" }

然后在頁面中輪詢 '/versionHash.json',比較 commit hash ,檢測是否有更新

let firstCommitHash = ``
let currentCommitHash = ``

async function getCommitHash() {
    // 避免瀏覽器緩存加上時間戳參數
    let res = await axios.get('/versionHash.json?date=' + Date.now())
    if (res.status == '200') {
        if (res.data && res.data.commitHash) {
            return res.data.commitHash
        }
    }
    return ''
}

export async function checkCommitHash() {

    firstCommitHash = await getCommitHash()

    window.checkCommitHash && clearInterval(window.checkCommitHash)

    window.checkCommitHash = setInterval(async () => {
        // 輪詢 versionHash.json 文件
        currentCommitHash = await getCommitHash()

        if (firstCommitHash && currentCommitHash && firstCommitHash !== currentCommitHash) {

            console.log('已更新')
            // 作相應處理
        }

    }, 3000)
}

關于檢測版本更新的時機

檢測時機,我覺得有三種比較合適,可以靈活搭配上面的方法使用

  • 資源加載錯誤時(常常發生在切換菜單時),檢測版本更新
  • 路由切換發生錯誤時(也發生在切換菜單時或者當前頁面引用其他路由時),檢測版本更新
  • 監聽 visibilitychange + focus 事件
1、資源加載錯誤時

前端部署后,某些資源已經更新,當切換菜單時,可能會出現資源加載失敗的錯誤(404)。此時可以使用 addEventListener('error') 捕獲資源加載錯誤

window.addEventListener('error',(event) =>{
    // 檢測版本更新
    // window.location.reload()
},true)
2、路由切換發生錯誤時

和上面的 addEventListener('error') 捕獲資源加載錯誤類似, vue-routerrouter.onError() 方法可以捕獲到路由加載的錯誤。

路由切換時某些資源加載失敗,會拋出 Loading chunk chunk-xxxx failed,可以用正則匹配它并作相應處理;

router.onError((error) =>{
    let reg = /Loading.*?failed/g
    if(reg.test(error)){
        // 檢測版本更新
        // window.location.reload()
    }
})
3、監聽 visibilitychange + focus 事件

visibilitychange:當其選項卡的內容變得可見或被隱藏時,會在 document 上觸發?visibilitychange?事件。

當用戶導航到新頁面、切換標簽頁、關閉標簽頁、最小化或關閉瀏覽器,或者在移動設備上從瀏覽器切換到不同的應用程序時,該事件就會觸發,其?visibilityState?為?hidden

在 pc 端,從瀏覽器切換到其他應用程序并不會觸發 visibilitychange 事件,所以加以 focus 輔佐;當鼠標點擊過當前頁面(必須 focus 過),此時切換到其他應用會觸發頁面的 blur 實踐;再次切回到瀏覽器則會觸發 focus 事件;

document.addEventListener("visibilitychange", () => {
    if (document.visibilityState === "visible") {
        
        // 開始檢測更新
    } else {
        
        // 結束檢測更新
    }
});

document.addEventListener('focus',() =>{

    // 開始檢測更新
})

關于禁用緩存

禁用 html 緩存
<!-- HTTP/1.1 -->
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">

<!-- HTTP/1.0; 與 Cache-Control: no-cache 效果一致 -->
<meta http-equiv="Pragma" content="no-cache"> 

<!-- 如果在 Cache-Control 設置了 "max-age" 或者 "s-max-age" 指令,那么?`Expires`?頭會被忽略。-->
<meta http-equiv="Expires" content="0">

如果只在 html 中設置這個的話,只在 IE 中有效;若要在其他瀏覽器中生效,則需要對服務器設置禁用緩存;

nginx 設置禁用緩存
// 配置 html 和 htm 文件不緩存
location / {
    root   html;
    index  index.html index.htm;
    add_header Cache-Control "no-cache,no-store,must-revalidate";
}

總結

本文總結了 3 種前端部署后頁面檢測版本更新的方法;

  • 輪詢打包后的 index.html,比較生成的 js 文件的 hash
  • HEAD 方*詢響應頭中的 etag
  • 監聽 git commit hash 變化

3 種都有用武之地,看具體場景和需求;

監聽 git commit hash 變化優勢是可以檢測到靜態資源的變化;

HEAD 方*詢響應頭中的 etag,優勢是只需要取響應頭中的字段,服務器不需要返回響應體,節約資源;

總結

以上是生活随笔為你收集整理的实践总结 3 种前端部署后页面检测版本的方法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。