背景
因为我的项目是用vite打包的,vite又是基于rollup的打包,rollup不像webpack有contentHash可以实现增量构建,而是每次打包,所有文件的hash都会更新,这样就会导致浏览器缓存的资源失效:
当用户已经打开页面,此时,重新部署代码; 会导致index html未更新, 而远程资讯已经替换,当用户切换路由时,因为按需加载的原因, 会访问旧的资源,导致404,控制台报错MIME类型错误, 此时加载的js资源content-type类型为text/html.
webpack有cententHash, vite没有这个概念,因此vite并不支持增量更新
解决思路
1、注入版本信息: 通过vite构建时,注入一个版本信息的version.json文件,json内容version: 版本号(这里会用时间戳代替)
2、定义全局常量: 通过vite提供的 define定义一个全局常量 __APP_VERSION__, __APP_VERSION__和verson.json共用一个时间戳
vite对define的解释: 定义全局常量替换方式。其中每项在开发环境下会被定义在全局,而在构建时被静态替换。
3、监控版本信息: 在合适的时机,请求version.json,对比全局常量APP_VERSION,二者不一致即版本已更新
代码
-
自定义vite插件:
// vite-version-plugin.ts文件 import fs from 'fs'; import path from 'path'; type Version = { version: number | string; }; interface Config { publicDir: string; } export default ({ version }: Version) => { let config: Config = { publicDir: '' }; return { name: 'version-plugin', // 必须的,将会在 warning 和 error 中显示 configResolved(resolvedConfig: Config) { // 存储最终解析的配置 config = resolvedConfig; }, buildStart() { // 生成版本信息文件路径 const file = config.publicDir + path.sep + 'version.json'; // 编译时间作为版本信息 const content = JSON.stringify({ version }); writeVersion(file, content); } }; }; /** * 写入文件 * @param fileName * @param version */ function writeVersion(fileName: string, version: string | NodeJS.ArrayBufferView) { fs.writeFile(fileName, version, (err) => { if (err) throw err; }); } -
vite.config.js中引入插件,并define
__APP_VERSION__,这样在打包的时候__APP_VERSION__和version.json中的值是保持一致.... import versionPlugin from './build/vite-version-plugin'; const timeVersion = new Date().getTime(); ... return defineConfig({ define: { // 定义全局版本信息 __APP_VERSION__: JSON.stringify(timeVersion) }, plugins: [ versionPlugin({ version: timeVersion }) ], ... }) -
版本监控,检查
__APP_VERSION__和version.josn是否一致,不一致表示服务器资源已更新.import axios from 'axios'; export async function versionCheck() { console.log('versionCheck'); if (import.meta.env.MODE === 'development') return; const res = await axios.get('version.json'); if (__APP_VERSION__ !== res.data.version) { // 这里看个人需求 window.location.reload(); } } 版本监控方法,需在按需加载触发之前调用, 如路由的前置钩子、触发异步组件的点击事件,要在加载资源报错之前,确定版本是否已更新.