问题:
自开发资源的内容,通过发布应用(重新部署前端后端资源)来实现,但是最新资源会替换到app.abc1.js 中的一个字符串(app.abc1.js资源更新内容,但是资源地址没有任何变化)。再结合js资源缓存策略配置的是强缓存+协商缓存,导致重新部署后,应用端自开发资源还是老旧资源
缓存策略如下:
虽然没有设置强缓存,但是会受到默认缓存的影响,走了强缓存无Cache-Control、Expires下浏览器默认强缓存
解决方案:
方案一:不使用强缓存,明确设置Cache-Control: max-age=0,缺点:资源每次都要加载,消耗宽带,也增大了LCP时间
方案二:针对重新发布这个业务操作,在发布的时候,给后端预设时间戳占位字符。利用资源请求地址不一致会重新加载最新资源的特性,获取最新app.js资源。旧地址:app.abc.js?timestamp=1752808486700 ->新地址: app.abc.js?timestamp=1752808511200
优点:可针对资源加时间戳,只在需要的时候更新资源
实现如下:
项目:vue2.7 文件:vue.config.js
js
new (class AppTimestampPlugin {
apply(compiler) {
compiler.hooks.afterEmit.tapAsync('AppTimestampPlugin', (compilation, callback) => {
try {
const outputPath = compilation.outputOptions.path
this.processTimestamp(outputPath)
callback()
} catch (error) {
callback(error)
}
})
}
// 为HTML文件中的app.js添加时间戳占位符
addTimestampToScripts(folderPath) {
const fs = require('fs')
const path = require('path')
fs.readdirSync(folderPath).forEach((file) => {
const filePath = path.join(folderPath, file)
const stats = fs.statSync(filePath)
if (stats.isDirectory()) {
this.addTimestampToScripts(filePath)
} else if (path.extname(file) === '.html') {
let content = fs.readFileSync(filePath, 'utf-8')
// 匹配包含 "app." 的 js 文件,如 js/app.12345678.js 或 app.12345678.js
content = content.replace(
/<script([^>]*)\s+src=["']([^"']*[\/]?app\.[^"']*\.js)(?!\?[^"']*timestamp)["']([^>]*)>/gi,
(match, beforeSrc, srcUrl, afterSrc) => {
const separator = srcUrl.includes('?') ? '&' : '?'
const newSrc = `${srcUrl}${separator}timestamp=___TIMESTAMP___`
return `<script${beforeSrc} src="${newSrc}"${afterSrc}>`
}
)
fs.writeFileSync(filePath, content, 'utf-8')
}
})
}
processTimestamp(outputPath) {
this.addTimestampToScripts(outputPath)
}
})()
总结
简单好用,解决了资源缓存问题
祝愿生活愉快