修复发帖长文布局与手机下拉刷新,发版后自动重载失效 chunk,并整理站务文案。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
34
frontend/src/utils/chunkLoad.ts
Normal file
34
frontend/src/utils/chunkLoad.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
/** sessionStorage:短时内只自动刷新一次,避免死循环 */
|
||||
const RELOAD_AT_KEY = 'j13:chunk-reload-at';
|
||||
const RELOAD_COOLDOWN_MS = 15_000;
|
||||
|
||||
/** 判断是否为「发版后旧 JS chunk 失效」类错误 */
|
||||
export function isChunkLoadError(error: unknown): boolean {
|
||||
const msg = error instanceof Error
|
||||
? `${error.name} ${error.message}`
|
||||
: String(error ?? '');
|
||||
return /Failed to fetch dynamically imported module/i.test(msg)
|
||||
|| /error loading dynamically imported module/i.test(msg)
|
||||
|| /Importing a module script failed/i.test(msg)
|
||||
|| /Loading chunk [\w-]+ failed/i.test(msg)
|
||||
|| /ChunkLoadError/i.test(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发版后旧页面仍引用已删除的 hashed chunk 时,整页刷新以拉取新 index.html。
|
||||
* @returns 是否已触发刷新(调用方应暂停渲染)
|
||||
*/
|
||||
export function reloadForStaleChunk(): boolean {
|
||||
try {
|
||||
const prev = Number(sessionStorage.getItem(RELOAD_AT_KEY) || 0);
|
||||
const now = Date.now();
|
||||
if (now - prev < RELOAD_COOLDOWN_MS) {
|
||||
return false;
|
||||
}
|
||||
sessionStorage.setItem(RELOAD_AT_KEY, String(now));
|
||||
} catch {
|
||||
// sessionStorage 不可用时仍尝试刷新一次
|
||||
}
|
||||
window.location.reload();
|
||||
return true;
|
||||
}
|
||||
25
frontend/src/utils/lazyWithRetry.ts
Normal file
25
frontend/src/utils/lazyWithRetry.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { lazy, type ComponentType, type LazyExoticComponent } from 'react';
|
||||
import { isChunkLoadError, reloadForStaleChunk } from './chunkLoad';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
type AnyComponent = ComponentType<any>;
|
||||
|
||||
/**
|
||||
* 带发版容错的 React.lazy:动态 import 失败时自动整页刷新一次。
|
||||
* (部署后 hashed chunk 更名,旧标签页点到懒加载路由时常见)
|
||||
*/
|
||||
export function lazyWithRetry<T extends AnyComponent>(
|
||||
factory: () => Promise<{ default: T }>,
|
||||
): LazyExoticComponent<T> {
|
||||
return lazy(async () => {
|
||||
try {
|
||||
return await factory();
|
||||
} catch (err) {
|
||||
if (isChunkLoadError(err) && reloadForStaleChunk()) {
|
||||
// 刷新进行中,挂起 Promise,避免再抛到错误页闪一下
|
||||
return new Promise<{ default: T }>(() => {});
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user