fix: 修复部署后切换页面 JS chunk 404 白屏问题
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 2m22s
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 2m22s
- main.ts 监听 vite:preloadError,chunk 加载失败时自动刷新一次 - 新增 ChunkErrorBoundary 组件,捕获 Vue 渲染层 chunk 加载异常 - App.vue 包裹 ChunkErrorBoundary - docker/nginx.conf 修复缓存策略:index.html 不缓存,/assets/ 长缓存 immutable
This commit is contained in:
@@ -11,23 +11,26 @@ server {
|
|||||||
gzip_types text/plain text/css text/xml text/javascript application/javascript application/json application/xml;
|
gzip_types text/plain text/css text/xml text/javascript application/javascript application/json application/xml;
|
||||||
gzip_comp_level 6;
|
gzip_comp_level 6;
|
||||||
|
|
||||||
|
location = /index.html {
|
||||||
|
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
||||||
|
add_header Pragma "no-cache";
|
||||||
|
add_header Expires "0";
|
||||||
|
}
|
||||||
|
|
||||||
location /health {
|
location /health {
|
||||||
access_log off;
|
access_log off;
|
||||||
return 200 'OK';
|
return 200 'OK';
|
||||||
add_header Content-Type text/plain;
|
add_header Content-Type text/plain;
|
||||||
}
|
}
|
||||||
|
|
||||||
location / {
|
location /assets/ {
|
||||||
try_files $uri $uri/ /index.html;
|
add_header Cache-Control "public, max-age=31536000, immutable";
|
||||||
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
try_files $uri =404;
|
||||||
add_header Pragma "no-cache";
|
access_log off;
|
||||||
add_header Expires "0";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
location / {
|
||||||
expires 1y;
|
try_files $uri $uri/ /index.html;
|
||||||
add_header Cache-Control "public, immutable";
|
|
||||||
access_log off;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
error_page 404 /index.html;
|
error_page 404 /index.html;
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<ElConfigProvider size="default" :locale="locales[language]" :z-index="3000">
|
<ChunkErrorBoundary>
|
||||||
<RouterView></RouterView>
|
<ElConfigProvider size="default" :locale="locales[language]" :z-index="3000">
|
||||||
</ElConfigProvider>
|
<RouterView></RouterView>
|
||||||
|
</ElConfigProvider>
|
||||||
|
</ChunkErrorBoundary>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@@ -13,6 +15,7 @@
|
|||||||
import { ApiStatus } from './utils/http/status'
|
import { ApiStatus } from './utils/http/status'
|
||||||
import { setThemeTransitionClass } from '@/utils'
|
import { setThemeTransitionClass } from '@/utils'
|
||||||
import { checkStorageCompatibility } from '@/utils'
|
import { checkStorageCompatibility } from '@/utils'
|
||||||
|
import ChunkErrorBoundary from '@/components/core/others/ChunkErrorBoundary.vue'
|
||||||
|
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const { language } = storeToRefs(userStore)
|
const { language } = storeToRefs(userStore)
|
||||||
|
|||||||
29
src/components/core/others/ChunkErrorBoundary.vue
Normal file
29
src/components/core/others/ChunkErrorBoundary.vue
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<template>
|
||||||
|
<slot />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { onErrorCaptured } from 'vue'
|
||||||
|
|
||||||
|
onErrorCaptured((err, instance, info) => {
|
||||||
|
const message = err?.message || ''
|
||||||
|
const isChunkError =
|
||||||
|
message.includes('dynamically imported module') ||
|
||||||
|
message.includes('Failed to fetch') ||
|
||||||
|
message.includes('Loading chunk') ||
|
||||||
|
message.includes('ChunkLoadError') ||
|
||||||
|
message.includes('Unable to preload CSS')
|
||||||
|
|
||||||
|
if (isChunkError) {
|
||||||
|
const key = '__chunk_reload__'
|
||||||
|
if (!sessionStorage.getItem(key)) {
|
||||||
|
sessionStorage.setItem(key, '1')
|
||||||
|
window.location.reload()
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.error('[ChunkErrorBoundary]', err, info)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
</script>
|
||||||
10
src/main.ts
10
src/main.ts
@@ -34,5 +34,15 @@ app.use(language)
|
|||||||
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
|
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
|
||||||
app.component(key, component)
|
app.component(key, component)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.addEventListener('vite:preloadError', event => {
|
||||||
|
event.preventDefault()
|
||||||
|
const key = '__chunk_reload__'
|
||||||
|
if (!sessionStorage.getItem(key)) {
|
||||||
|
sessionStorage.setItem(key, '1')
|
||||||
|
window.location.reload()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
app.mount('#app')
|
app.mount('#app')
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user