fix: 撤销弹窗及强制跳回机制;在 vite 中去除 Chunk 打包 Hash,并给服务端路由补充无 Hash 回退机制,从物理上消灭缓存旧引用导致的死锁 404

This commit is contained in:
tangxinyue 2026-07-24 16:37:11 +08:00
parent 1308bf86fd
commit e2ada92510
3 changed files with 35 additions and 28 deletions

View File

@ -94,10 +94,29 @@ const matchFile = async (request, response) => {
if (fs.existsSync(mappedPath)) { if (fs.existsSync(mappedPath)) {
targetPath = mappedPath targetPath = mappedPath
} else if (cleanPath.startsWith('/assets/')) { } else if (cleanPath.startsWith('/assets/')) {
response.writeHead(404, { 'Content-Type': 'text/plain' }) // 如果请求的是带 hash 的旧文件,尝试摘除 -[hash] 请求固定文件
response.end('Asset Not Found') const filename = cleanPath.split('/').pop()
resolve(true) const parts = filename.split('.')
return const ext = parts.pop()
const nameParts = parts.join('.').split('-')
if (nameParts.length > 1) {
nameParts.pop() // 移除最后的 hash
const baseName = nameParts.join('-')
const fallbackPath = dist + '/assets/' + baseName + '.' + ext
if (fs.existsSync(fallbackPath)) {
targetPath = fallbackPath
} else {
response.writeHead(404, { 'Content-Type': 'text/plain' })
response.end('Asset Not Found')
resolve(true)
return
}
} else {
response.writeHead(404, { 'Content-Type': 'text/plain' })
response.end('Asset Not Found')
resolve(true)
return
}
} }
} }
fs.readFile(targetPath, (err, file) => { fs.readFile(targetPath, (err, file) => {

View File

@ -48,25 +48,14 @@ router.beforeEach(async (to, from, next) => {
router.onError((error) => { router.onError((error) => {
const pattern = /Failed to fetch dynamically imported module|Importing a module script failed/i const pattern = /Failed to fetch dynamically imported module|Importing a module script failed/i
if (pattern.test(error?.message || '')) { if (pattern.test(error?.message || '')) {
if (window._chunkErrorHandled) return const isReloaded = sessionStorage.getItem('chunk_reload_flag')
window._chunkErrorHandled = true if (!isReloaded) {
sessionStorage.setItem('chunk_reload_flag', 'true')
const forceReload = () => { const forceReload = () => {
// 不再重载当前错误路径,直接跳回首页,并带上时间戳跳出 CDN 缓存 const url = new URL(window.location.href)
window.location.href = window.location.origin + '/?t=' + Date.now() url.searchParams.set('t', Date.now())
} window.location.href = url.href
const cleanAndReload = async () => {
// 暴力清空所有的 Cache API防止 SW 缓存 index.html 等
if (window.caches) {
try {
const keys = await window.caches.keys()
for (const key of keys) {
await window.caches.delete(key)
}
} catch (e) {}
} }
if ('serviceWorker' in navigator) { if ('serviceWorker' in navigator) {
navigator.serviceWorker.getRegistrations().then(registrations => { navigator.serviceWorker.getRegistrations().then(registrations => {
for (const registration of registrations) { for (const registration of registrations) {
@ -78,12 +67,6 @@ router.onError((error) => {
forceReload() forceReload()
} }
} }
if (window.confirm('系统检测到版本更新,当前页面数据已过期。点击【确定】立即刷新体验最新版本!')) {
cleanAndReload()
} else {
window._chunkErrorHandled = false
}
} }
}) })

View File

@ -41,6 +41,11 @@ export default defineConfig({
build: { build: {
chunkSizeWarningLimit: 2000, chunkSizeWarningLimit: 2000,
rollupOptions: { rollupOptions: {
output: {
entryFileNames: 'assets/[name].js',
chunkFileNames: 'assets/[name].js',
assetFileNames: 'assets/[name].[ext]'
},
onwarn(warning, warn) { onwarn(warning, warn) {
if (warning.code === 'UNRESOLVED_IMPORT' || warning.code === 'UNUSED_EXTERNAL_IMPORT') return; if (warning.code === 'UNRESOLVED_IMPORT' || warning.code === 'UNUSED_EXTERNAL_IMPORT') return;
warn(warning); warn(warning);