如何解决前端上线之后用户页面不刷新的问题
前言
最近使用 Vue3 技術把公司的一個大的 Web 前端項目進行了一個升級。升級過程坎坷不斷,但最終是成功了,具體升級相關的另開篇講,這里主要講下使用 Vite 作為打包工具之后,每次打包上線完,用戶客戶端頁面路由跳轉報錯,必須要主動刷新頁面才可獲取最新資源的問題。
起因
剛剛說了,導致這個問題的具體原因,是因為在 vue-router 里使用了頁面模塊懶加載,通過 Vite 打包之后,不同于 Webpack ,生成的 dist/assite 文件夾中,會有很多個小的 js 文件,而 Webpack 打包會生成一個大的 app.js 文件。這樣的好處是,大大提升了項目首頁開屏的速度!但是缺點上完線之后就暴露出來了,由于上線打包,使用自動化工具,會把之前的項目文件清空,然后把 build 之后的文件移動過來,相當于整個做了一個替換!所以如果客戶端不主動刷新瀏覽器,用戶的本地項目還是上一個版本的,當它需要進行跳轉頁面或者引入其他的包時,自然在服務器上找不到之前的包了 -_-!
方案
針對這個問題,我想了以下幾種解決的辦法:
1. 通過前后端配合定義一個版本接口
這種場景就好像是 App 版本更新似的,每次上線都要定義一個版本,這個版本通過后端接口進行修改和獲取,但是需要前端和后端一起配合,以及一整套流程控制,數據表維護等。實現起來相對來說較麻煩,需要一定時間。
2. 前端打包生成一個json文件記錄版本,路由跳轉的時候,通過請求服務端版本號與本地版本號是否一致,決定是否刷新
這種相當于第一種方案的簡化版(不需要后端配合)。只需要在打包的時候,自己生成一個 json 文件來記錄本次打包的版本號就可以了,這個版本號不一定要按真實的版本來,只需要是唯一的就行了,換句話說,可以生成一個隨機碼,uaaId 、隨機數、時間戳都可以。這種可以完全自動化,弄好之后,不需要人工去改什么了。
3. 記錄路由跳轉時間,每隔6個小時刷新路由
簡化版,簡單粗暴,直接通過記錄頁面跳轉的時間,來判斷是否刷新,因為上線一般是晚上進行,所以第二天,基本也都能執行刷新動作了,但是不夠及時。萬一不夠時間,還是會有這個問題。
4. 退出登錄的時候刷新頁面
作為一個補充。
5. 重寫push方法,捕捉錯誤
這個 Vue3 中我沒有實現過,只是作為一個思路,如果能在路由 push 報錯的時候,捕捉錯誤并且刷新頁面,貌似也是可行。
解決
最終,我選擇了第二種方法,解決了這個問題,相對來說不需要后端配合也減少了工程量。以下是解決的具體實現:
1. 項目根目錄下新建 build/build.js
build.js 代碼:
console.log('build > 文件開始執行!') const fs = require('fs') const path = require('path')function getRootPath(...dir) {return path.resolve(process.cwd(), ...dir) } const runBuild = async () => {try {const OUTPUT_DIR = 'dist'const VERSION = 'version.json'const versionJson = {version: 'V_' + Math.floor(Math.random() * 10000) + Date.now()}fs.writeFileSync(getRootPath(`${OUTPUT_DIR}/${VERSION}`), JSON.stringify(versionJson))console.log(`version file is build successfully!`)} catch (error) {console.error('version build error:\n' + error)process.exit(1)} } runBuild() console.log('build > 文件執行結束!')通過 node 在打包完成以后生成一個 version.json 文件。同時生成一個隨機碼作為區分版本的 ID。
2. 在 package.json 中增加指令
package.json
"postbuild": "node ./build/build.js",此指令會在 build 之后自動被調用執行。具體不明白可參看這篇文章:
package.json中的scripts命令解析
3. 在 router/index.js 中處理版本更新
router/index.js
import axios from 'axios'// 路由攔截 router.beforeEach((to, from, next) => {// ... 其他邏輯// 檢查版本更新if (from.path !== '/') {checkAppNewVersion()}})// 檢查服務端是否已經更新,如果更新刷新頁面 async function checkAppNewVersion() {const url = `/version.json?t=${Date.now()}`let res = nulltry {res = await axios.get(url)} catch (err) {console.error('checkAppNewVersion error: ', err)}if (!res) returnconst version = res.data.versionconst localVersion = Local.get(localKeys.APP_VERSION)if (localVersion && localVersion !== version) {Local.set(localKeys.APP_VERSION, version)window.location.reload()}Local.set(localKeys.APP_VERSION, version) }這里之所以是在 beforeEach 鉤子里處理,是有原因的,afterEach 和 beforeResolve 是在 beforeEach 執行之后執行,當服務器文件已經更新了,然后本地還沒更新的情況下,是加載不到即將要跳轉的頁面文件的。
beforeResolve 執行的時候,說明所需要加載的組件已經加載好了,如果加載不到文件的話,這里已經開始拋錯了。
以上基本已經處理完了,服務端上線了新的文件之后,本地頁面跳轉的時候根據拿到的 version 和本地的進行對比,如果不同就先刷新頁面,重新獲取最新資源文件。
但是這樣做還是有個小問題:
當用戶在登錄頁時,服務端更新了版本,所以用戶在輸入用戶名和密碼之后,點擊登錄,顯示登錄成功,正常是應該直接跳到首頁,但是此時跳轉前檢測到版本更新,所以會原地刷新一下獲取最新資源,導致頁面又恢復到了登錄之前的狀態,用戶需要重新登錄。這點體驗很不好。所以后期加了以下處理:
增加了頁面顯示的監聽,在用戶打開頁面時,先獲取版本更新一下,這樣就可以避免這個問題。
感謝閱讀,如果這篇文章對你有幫助的話,幫忙點個贊吧,謝謝!
總結
以上是生活随笔為你收集整理的如何解决前端上线之后用户页面不刷新的问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: oracle安装步骤缺少实例,oracl
- 下一篇: 【BLE-CC2640】CC2640之S