業務場景
前端業務開發完成後進行打包部署,前端自動更新。
解決方案
每次build
打包程式碼時,在 public
目錄下生成一個 version.json
版本資訊檔案,頁面重新整理或跳轉時獲取到伺服器端的 version.json
中的版本號和瀏覽器本地快取的版本號進行對比,實現對版本監控迭代更新,進而實現頁面自動更新,獲取新的 index.html
檔案。
注意:前提是伺服器端對 index.html
和 version.json
不快取。
實現方式
首先應該禁止瀏覽器快取
index.html
和version.json
,設定nginx
不快取的配置。
location / { try_files $uri $uri/ /index.html; expires -1; }
編寫 Vite 外掛實現打包時自動生成版本資訊。外掛檔案路徑:
src/utils/updater.js
(根據個人習慣選擇檔案位置)
// updater.js // const fs = require("fs"); // const path = require("path"); // vite不支援require的引入方式故使用import方式代替,可根據自身專案配置自行選擇 import fs from "fs"; import path from "path"; const writeVersion = (versionFile, content) => { // 寫入檔案 fs.writeFile(versionFile, content, (err) => { if (err) throw err; }); }; export default (options) => { let config; return { name: "version-update", apply: 'build', // 指明外掛在 'build' 或 'serve' 模式時呼叫 configResolved(resolvedConfig) { // 儲存最終解析的配置 config = resolvedConfig; }, buildStart() { // 生成版本資訊檔案路徑 const file = config.publicDir + path.sep + "version.json"; // 這裏使用編譯時間作為版本資訊 const content = JSON.stringify({ version: options.version }); if (fs.existsSync(config.publicDir)) { writeVersion(file, content); } else { fs.mkdir(config.publicDir, (err) => { if (err) throw err; writeVersion(file, content); }); } }, }; };
vite.config.js
對應配置
// 引入updater外掛 import updater from "./src/utils/updater"; export default defineConfig((config) => { const timestamp = new Date().getTime(); return { // ... define: { // 定義全域性變數 APP_VERSION: timestamp, }, plugins: [ // ... updater({ version: timestamp }), ], // ... } })
4.頁面跳轉或頁面重新整理時,實時檢測版本,檢測到新版本自動重新整理頁面,應該使用前置守衛,在跳轉失敗報錯前檢測,跳轉失敗不會觸發後置守衛。
import axios from "axios"; import { showToast } from "vant"; const router = useRouter(); // 這裏在路由全域性前置守衛中檢查版本 router.beforeEach(async () => { await versionCheck(); }) // 版本監控 const versionCheck = async () => { if (import.meta.env.MODE === "development") return; const response = await axios.get("version.json"); if (APP_VERSION !== response.data.version) { showToast({ message: "發現新內容,自動更新中...", type: "loading", duration: 1500, onClose: () => { window.location.reload(); }, }); } }