feat: SSR 安全防卫与缓存作用域化(branding/limits/pages/auth/session)
theme/useTheme 服务端防卫 window/document;branding/limits/pages 缓存读请求作用域、seed 只写作用域;homeBoot 拆出 seedHomeBoot 与帖子详情快照构建器供 prefetchRoute 复用;getHomeStoreState 改返回 state 修复命令式访问
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { api } from '../api/client';
|
||||
import type { SiteBranding } from '../api/types';
|
||||
import { getScope } from '../ssr/scope';
|
||||
|
||||
export const DEFAULT_BRANDING: SiteBranding = {
|
||||
name: '姜十三论坛',
|
||||
@@ -30,8 +31,8 @@ export function siteMetaDescription(brand: SiteBranding): string {
|
||||
return brand.slogan?.trim() ?? '';
|
||||
}
|
||||
|
||||
/** 从服务端注入的 boot 数据同步初始化,避免首屏闪默认站名 */
|
||||
function readBootBranding(): SiteBranding | null {
|
||||
if (typeof window === 'undefined') return null;
|
||||
try {
|
||||
const boot = window.__J13_BRANDING__;
|
||||
if (!boot || typeof boot !== 'object') return null;
|
||||
@@ -50,6 +51,11 @@ let cacheEpoch = 0;
|
||||
let preferCacheOnce = false;
|
||||
const listeners = new Set<() => void>();
|
||||
|
||||
/** 当前生效的品牌配置:SSR 读请求作用域,客户端读模块缓存 */
|
||||
function currentBranding(): SiteBranding | null {
|
||||
return getScope()?.branding ?? cached;
|
||||
}
|
||||
|
||||
function fetchBranding(): Promise<SiteBranding> {
|
||||
if (preferCacheOnce && cached) {
|
||||
preferCacheOnce = false;
|
||||
@@ -96,13 +102,13 @@ function applyDocumentBrand(brand: SiteBranding) {
|
||||
|
||||
/** 同步读取已缓存的品牌配置(供 SEO 等非 hook 场景) */
|
||||
export function getCachedSiteBranding(): SiteBranding {
|
||||
return cached ?? DEFAULT_BRANDING;
|
||||
return currentBranding() ?? DEFAULT_BRANDING;
|
||||
}
|
||||
|
||||
/** 获取站点品牌配置(名称、Logo 等) */
|
||||
export function useSiteBranding() {
|
||||
const [branding, setBranding] = useState<SiteBranding>(cached ?? DEFAULT_BRANDING);
|
||||
const [loading, setLoading] = useState(!cached);
|
||||
const [branding, setBranding] = useState<SiteBranding>(currentBranding() ?? DEFAULT_BRANDING);
|
||||
const [loading, setLoading] = useState(!currentBranding());
|
||||
const [epoch, setEpoch] = useState(cacheEpoch);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -160,9 +166,15 @@ export function invalidateSiteBrandingCache() {
|
||||
listeners.forEach(fn => fn());
|
||||
}
|
||||
|
||||
/** 用管理端刚保存的值立即更新缓存与文档标题 */
|
||||
/** 用管理端刚保存的值立即更新缓存与文档标题(SSR 时只写请求作用域) */
|
||||
export function seedSiteBrandingCache(brand: SiteBranding) {
|
||||
cached = { ...DEFAULT_BRANDING, ...brand };
|
||||
const merged: SiteBranding = { ...DEFAULT_BRANDING, ...brand };
|
||||
const scope = getScope();
|
||||
if (scope) {
|
||||
scope.branding = merged;
|
||||
return;
|
||||
}
|
||||
cached = merged;
|
||||
applyDocumentBrand(cached);
|
||||
cacheEpoch += 1;
|
||||
listeners.forEach(fn => fn());
|
||||
|
||||
Reference in New Issue
Block a user