fix: 部署后 chunk 404 自动刷新,SPA index 禁止缓存
All checks were successful
Build and Deploy Front / deploy (push) Successful in 5m37s
All checks were successful
Build and Deploy Front / deploy (push) Successful in 5m37s
前端检测 lazy import 失败自动 reload;nginx @spa 回退统一 no-cache。
This commit is contained in:
parent
bdb515d366
commit
8f12a6cf65
164
nginx-k3s.conf
164
nginx-k3s.conf
@ -55,109 +55,118 @@ server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
location = /login {
|
location = /login {
|
||||||
try_files /index.html =200;
|
try_files $uri @spa;
|
||||||
}
|
}
|
||||||
location = /login/ {
|
location = /login/ {
|
||||||
try_files /index.html =200;
|
try_files $uri @spa;
|
||||||
}
|
}
|
||||||
|
|
||||||
rewrite ^/admin/?$ /index.html last;
|
rewrite ^/admin/?$ /index.html last;
|
||||||
|
|
||||||
location = /admin {
|
location = /admin {
|
||||||
try_files /index.html =200;
|
try_files $uri @spa;
|
||||||
}
|
}
|
||||||
location = /admin/ {
|
location = /admin/ {
|
||||||
try_files /index.html =200;
|
try_files $uri @spa;
|
||||||
}
|
}
|
||||||
|
|
||||||
location ~ ^/api/(upstreamInterface|upstreamInterfaceConfig|upstreamInterfaceConfigEdit|downstreamInterface(|/newPort)|appList(|/createApplication)|requestLog|callStatistics|apiDebugger|apiTest)(/|$) {
|
location ~ ^/api/(upstreamInterface|upstreamInterfaceConfig|upstreamInterfaceConfigEdit|downstreamInterface(|/newPort)|appList(|/createApplication)|requestLog|callStatistics|apiDebugger|apiTest)(/|$) {
|
||||||
try_files /index.html =200;
|
try_files $uri @spa;
|
||||||
}
|
}
|
||||||
|
|
||||||
location ^~ /xhs/startService { try_files /index.html =200; }
|
location ^~ /xhs/startService { try_files $uri @spa; }
|
||||||
location ^~ /xhs/creation { try_files /index.html =200; }
|
location ^~ /xhs/creation { try_files $uri @spa; }
|
||||||
location ^~ /xhs/publishHistory { try_files /index.html =200; }
|
location ^~ /xhs/publishHistory { try_files $uri @spa; }
|
||||||
location ^~ /xhs/skills { try_files /index.html =200; }
|
location ^~ /xhs/skills { try_files $uri @spa; }
|
||||||
location ^~ /xhs/humanSettings { try_files /index.html =200; }
|
location ^~ /xhs/humanSettings { try_files $uri @spa; }
|
||||||
location ^~ /xhs/agentPair { try_files /index.html =200; }
|
location ^~ /xhs/agentPair { try_files $uri @spa; }
|
||||||
location = /xhs/analysis { try_files /index.html =200; }
|
location = /xhs/analysis { try_files $uri @spa; }
|
||||||
location = /xhs/analysis/ { try_files /index.html =200; }
|
location = /xhs/analysis/ { try_files $uri @spa; }
|
||||||
|
|
||||||
location ^~ /wechat/register { try_files /index.html =200; }
|
location ^~ /wechat/register { try_files $uri @spa; }
|
||||||
location ^~ /wechat/bind { try_files /index.html =200; }
|
location ^~ /wechat/bind { try_files $uri @spa; }
|
||||||
location ^~ /h5 { try_files /index.html =200; }
|
location ^~ /h5 { try_files $uri @spa; }
|
||||||
location ^~ /track/query { try_files /index.html =200; }
|
location ^~ /track/query { try_files $uri @spa; }
|
||||||
location ^~ /operation/inboundScan { try_files /index.html =200; }
|
location ^~ /operation/inboundScan { try_files $uri @spa; }
|
||||||
location ^~ /operation/outboundScan { try_files /index.html =200; }
|
location ^~ /operation/outboundScan { try_files $uri @spa; }
|
||||||
location ^~ /operation/printLabel { try_files /index.html =200; }
|
location ^~ /operation/printLabel { try_files $uri @spa; }
|
||||||
location ^~ /operation/parcelArrival { try_files /index.html =200; }
|
location ^~ /operation/parcelArrival { try_files $uri @spa; }
|
||||||
location ^~ /operation/fulfillPack { try_files /index.html =200; }
|
location ^~ /operation/fulfillPack { try_files $uri @spa; }
|
||||||
|
|
||||||
# 订单前端路由(^~ 须比下方 /order/ API 正则代理更优先)
|
# 订单前端路由(^~ 须比下方 /order/ API 正则代理更优先)
|
||||||
location ^~ /order/priceCheck { try_files /index.html =200; }
|
location ^~ /order/priceCheck { try_files $uri @spa; }
|
||||||
location ^~ /order/placeOrder { try_files /index.html =200; }
|
location ^~ /order/placeOrder { try_files $uri @spa; }
|
||||||
location ^~ /order/myOrders { try_files /index.html =200; }
|
location ^~ /order/myOrders { try_files $uri @spa; }
|
||||||
location ^~ /order/fulfillOrders { try_files /index.html =200; }
|
location ^~ /order/fulfillOrders { try_files $uri @spa; }
|
||||||
location ^~ /order/waybillManage { try_files /index.html =200; }
|
location ^~ /order/waybillManage { try_files $uri @spa; }
|
||||||
location ^~ /order/pickupOrder { try_files /index.html =200; }
|
location ^~ /order/pickupOrder { try_files $uri @spa; }
|
||||||
location ^~ /order/customs9610Order { try_files /index.html =200; }
|
location ^~ /order/customs9610Order { try_files $uri @spa; }
|
||||||
location ^~ /order/batchJobs { try_files /index.html =200; }
|
location ^~ /order/batchJobs { try_files $uri @spa; }
|
||||||
location ^~ /order/templateMapping { try_files /index.html =200; }
|
location ^~ /order/templateMapping { try_files $uri @spa; }
|
||||||
location ^~ /order/platformStore { try_files /index.html =200; }
|
location ^~ /order/platformStore { try_files $uri @spa; }
|
||||||
location ^~ /order/platformStoreOrder { try_files /index.html =200; }
|
location ^~ /order/platformStoreOrder { try_files $uri @spa; }
|
||||||
|
|
||||||
# 知识库前端路由(^~ 须比下方 /kb/ API 代理更优先)
|
# 知识库前端路由(^~ 须比下方 /kb/ API 代理更优先)
|
||||||
location ^~ /kb/category { try_files /index.html =200; }
|
location ^~ /kb/category { try_files $uri @spa; }
|
||||||
location ^~ /kb/article { try_files /index.html =200; }
|
location ^~ /kb/article { try_files $uri @spa; }
|
||||||
|
|
||||||
location = /warehouse/parcel { try_files /index.html =200; }
|
location = /warehouse/parcel { try_files $uri @spa; }
|
||||||
location = /warehouse/inventory { try_files /index.html =200; }
|
location = /warehouse/inventory { try_files $uri @spa; }
|
||||||
location = /warehouse/sku { try_files /index.html =200; }
|
location = /warehouse/sku { try_files $uri @spa; }
|
||||||
location = /warehouse/binLocation { try_files /index.html =200; }
|
location = /warehouse/binLocation { try_files $uri @spa; }
|
||||||
location ^~ /warehouse/inboundNotice { try_files /index.html =200; }
|
location ^~ /warehouse/inboundNotice { try_files $uri @spa; }
|
||||||
location ^~ /Plugin/ { try_files /index.html =200; }
|
location ^~ /Plugin/ { try_files $uri @spa; }
|
||||||
|
|
||||||
location ^~ /channel/salesProducts { try_files /index.html =200; }
|
location ^~ /channel/salesProducts { try_files $uri @spa; }
|
||||||
location ^~ /channel/serviceChannels { try_files /index.html =200; }
|
location ^~ /channel/serviceChannels { try_files $uri @spa; }
|
||||||
location ^~ /channel/priceArea { try_files /index.html =200; }
|
location ^~ /channel/priceArea { try_files $uri @spa; }
|
||||||
location ^~ /channel/blacklist { try_files /index.html =200; }
|
location ^~ /channel/blacklist { try_files $uri @spa; }
|
||||||
location ^~ /channel/remoteZones { try_files /index.html =200; }
|
location ^~ /channel/remoteZones { try_files $uri @spa; }
|
||||||
location ^~ /channel/weightRules { try_files /index.html =200; }
|
location ^~ /channel/weightRules { try_files $uri @spa; }
|
||||||
location ^~ /channel/weightRounding { try_files /index.html =200; }
|
location ^~ /channel/weightRounding { try_files $uri @spa; }
|
||||||
location ^~ /channel/autoTrigger { try_files /index.html =200; }
|
location ^~ /channel/autoTrigger { try_files $uri @spa; }
|
||||||
location ^~ /channel/issueTemplate { try_files /index.html =200; }
|
location ^~ /channel/issueTemplate { try_files $uri @spa; }
|
||||||
location ^~ /channel/labelDesign { try_files /index.html =200; }
|
location ^~ /channel/labelDesign { try_files $uri @spa; }
|
||||||
|
|
||||||
# 营销前端路由(^~ 须比下方 /marketing/ API 正则代理更优先)
|
# 营销前端路由(^~ 须比下方 /marketing/ API 正则代理更优先)
|
||||||
location ^~ /marketing/memberLevel { try_files /index.html =200; }
|
location ^~ /marketing/memberLevel { try_files $uri @spa; }
|
||||||
location ^~ /marketing/pointsRule { try_files /index.html =200; }
|
location ^~ /marketing/pointsRule { try_files $uri @spa; }
|
||||||
location ^~ /marketing/pointsFlow { try_files /index.html =200; }
|
location ^~ /marketing/pointsFlow { try_files $uri @spa; }
|
||||||
location ^~ /marketing/couponTemplate { try_files /index.html =200; }
|
location ^~ /marketing/couponTemplate { try_files $uri @spa; }
|
||||||
location ^~ /marketing/couponGrant { try_files /index.html =200; }
|
location ^~ /marketing/couponGrant { try_files $uri @spa; }
|
||||||
location ^~ /marketing/commissionRule { try_files /index.html =200; }
|
location ^~ /marketing/commissionRule { try_files $uri @spa; }
|
||||||
location ^~ /marketing/commissionDetail { try_files /index.html =200; }
|
location ^~ /marketing/commissionDetail { try_files $uri @spa; }
|
||||||
location ^~ /marketing/commissionWithdraw { try_files /index.html =200; }
|
location ^~ /marketing/commissionWithdraw { try_files $uri @spa; }
|
||||||
location ^~ /marketing/referralTree { try_files /index.html =200; }
|
location ^~ /marketing/referralTree { try_files $uri @spa; }
|
||||||
|
|
||||||
# 系统管理前端路由(^~ 须比下方 /system/ API 正则代理更优先)
|
# 系统管理前端路由(^~ 须比下方 /system/ API 正则代理更优先)
|
||||||
location = /system/dict { try_files /index.html =200; }
|
location = /system/dict { try_files $uri @spa; }
|
||||||
location = /system/warehouseAddress { try_files /index.html =200; }
|
location = /system/warehouseAddress { try_files $uri @spa; }
|
||||||
location = /system/announcement { try_files /index.html =200; }
|
location = /system/announcement { try_files $uri @spa; }
|
||||||
location ^~ /system/users { try_files /index.html =200; }
|
location ^~ /system/users { try_files $uri @spa; }
|
||||||
location ^~ /system/roles { try_files /index.html =200; }
|
location ^~ /system/roles { try_files $uri @spa; }
|
||||||
location ^~ /system/menus { try_files /index.html =200; }
|
location ^~ /system/menus { try_files $uri @spa; }
|
||||||
location ^~ /system/organizations { try_files /index.html =200; }
|
location ^~ /system/organizations { try_files $uri @spa; }
|
||||||
location ^~ /system/batchEmail { try_files /index.html =200; }
|
location ^~ /system/batchEmail { try_files $uri @spa; }
|
||||||
location ^~ /system/otherConfig { try_files /index.html =200; }
|
location ^~ /system/otherConfig { try_files $uri @spa; }
|
||||||
location ^~ /system/aiAssistant { try_files /index.html =200; }
|
location ^~ /system/aiAssistant { try_files $uri @spa; }
|
||||||
location ^~ /system/aiSkills { try_files /index.html =200; }
|
location ^~ /system/aiSkills { try_files $uri @spa; }
|
||||||
location ^~ /system/mcpTools { try_files /index.html =200; }
|
location ^~ /system/mcpTools { try_files $uri @spa; }
|
||||||
location ^~ /system/dataPerm/ { try_files /index.html =200; }
|
location ^~ /system/dataPerm/ { try_files $uri @spa; }
|
||||||
|
|
||||||
|
# SPA 回退:try_files $uri @spa 统一带 no-cache,避免部署后浏览器缓存旧 index.html
|
||||||
|
location @spa {
|
||||||
|
add_header Cache-Control "no-cache, no-store, must-revalidate" always;
|
||||||
|
add_header Pragma "no-cache" always;
|
||||||
|
add_header Expires "0" always;
|
||||||
|
try_files /index.html =404;
|
||||||
|
}
|
||||||
|
|
||||||
location = /index.html {
|
location = /index.html {
|
||||||
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
add_header Cache-Control "no-cache, no-store, must-revalidate" always;
|
||||||
add_header Pragma "no-cache";
|
add_header Pragma "no-cache" always;
|
||||||
add_header Expires "0";
|
add_header Expires "0" always;
|
||||||
|
try_files /index.html =404;
|
||||||
}
|
}
|
||||||
|
|
||||||
# 微信 JS 安全域名校验:原样返回 txt,禁止 SPA 回落 index.html
|
# 微信 JS 安全域名校验:原样返回 txt,禁止 SPA 回落 index.html
|
||||||
@ -176,7 +185,6 @@ server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
index index.html;
|
try_files $uri @spa;
|
||||||
try_files $uri /index.html;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import {
|
|||||||
} from './plugins/heavy-plugins';
|
} from './plugins/heavy-plugins';
|
||||||
import { initAuthKeepAlive } from '@/utils/auth-keepalive';
|
import { initAuthKeepAlive } from '@/utils/auth-keepalive';
|
||||||
import { installWeChatH5HistoryGuard } from '@/utils/device';
|
import { installWeChatH5HistoryGuard } from '@/utils/device';
|
||||||
|
import { installChunkReloadHandlers, reloadOnChunkLoadError } from '@/utils/chunkReload';
|
||||||
import { setAuthToken } from './api/rbac';
|
import { setAuthToken } from './api/rbac';
|
||||||
import { useRbacUserStore } from '@/store/modules/rbac-user';
|
import { useRbacUserStore } from '@/store/modules/rbac-user';
|
||||||
import { applyRbacUserToUserStore } from '@/utils/enter-system';
|
import { applyRbacUserToUserStore } from '@/utils/enter-system';
|
||||||
@ -75,6 +76,11 @@ const app = createApp(App);
|
|||||||
app.use(ArcoVue, {});
|
app.use(ArcoVue, {});
|
||||||
app.use(ArcoVueIcon);
|
app.use(ArcoVueIcon);
|
||||||
app.use(router);
|
app.use(router);
|
||||||
|
installChunkReloadHandlers();
|
||||||
|
router.onError((error) => {
|
||||||
|
if (reloadOnChunkLoadError(error)) return;
|
||||||
|
throw error;
|
||||||
|
});
|
||||||
app.use(store);
|
app.use(store);
|
||||||
useAppStore().hydrateTheme();
|
useAppStore().hydrateTheme();
|
||||||
app.use(i18n);
|
app.use(i18n);
|
||||||
|
|||||||
42
src/utils/chunkReload.ts
Normal file
42
src/utils/chunkReload.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/** 部署后旧 chunk 404 时自动刷新,避免 lazy route 白屏 */
|
||||||
|
|
||||||
|
const RELOAD_KEY = 'oms_chunk_reload_ts';
|
||||||
|
const RELOAD_COOLDOWN_MS = 15_000;
|
||||||
|
|
||||||
|
export function isChunkLoadError(error: unknown): boolean {
|
||||||
|
const msg = error instanceof Error ? error.message : String(error ?? '');
|
||||||
|
return (
|
||||||
|
/Failed to fetch dynamically imported module/i.test(msg) ||
|
||||||
|
/Importing a module script failed/i.test(msg) ||
|
||||||
|
/Loading chunk [\da-zA-Z_-]+ failed/i.test(msg) ||
|
||||||
|
/ChunkLoadError/i.test(msg)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 检测到 chunk 加载失败则刷新页面;10s 内仅刷新一次,防止死循环 */
|
||||||
|
export function reloadOnChunkLoadError(error: unknown): boolean {
|
||||||
|
if (typeof window === 'undefined' || !isChunkLoadError(error)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const last = Number(sessionStorage.getItem(RELOAD_KEY) || 0);
|
||||||
|
const now = Date.now();
|
||||||
|
if (now - last < RELOAD_COOLDOWN_MS) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
sessionStorage.setItem(RELOAD_KEY, String(now));
|
||||||
|
} catch {
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
|
window.location.reload();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function installChunkReloadHandlers(): void {
|
||||||
|
if (typeof window === 'undefined') return;
|
||||||
|
window.addEventListener('unhandledrejection', (event) => {
|
||||||
|
if (reloadOnChunkLoadError(event.reason)) {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user