feat(ssr): 真 SSR 收尾——干净 hydration 与浏览器原生滚动恢复
- 修复 onRenderClient 引入 serverClient 导致浏览器 process is not defined: 抽出双端安全的 ssr/feedSeed.ts 作为唯一数据播种入口,serverClient 加 SSR 守卫 - 修复 React 19 Fizz Suspense Outlining:Suspense 边界从布局 Outlet 下移到 各懒加载路由,SSR 输出不再出现 <!--$?--> / $RB / template 探针标记 - 修复窄屏 React #418 hydration 致命错误:useMediaQuery 首帧恒 false, useLayoutEffect 绘制前同步真实值;主题改 cookie 存储供 SSR 直出, head 内联防闪烁/缩放脚本移除(缩放锁改为客户端 zoomGuard 模块) - 清理假 SSR 残留:删除 StaticFeedList 镜像组件、SSR 图标生成脚本、 探针与死代码;列表接口裁剪正文,仅下发 excerpt/first_image - Feed 与帖子详情改为窗口滚动(app-shell--doc-scroll):删除虚拟列表、 自研滚动快照与全局滚轮 hack;F5/前进后退滚动位置全部交给浏览器原生 历史恢复,HTML 响应头 no-cache 配合;锚点/楼层用 scrollIntoView + scroll-margin-top 适配 sticky 顶栏
This commit is contained in:
@@ -64,12 +64,16 @@ for (const prefix of GO_PROXY_PREFIXES) {
|
||||
);
|
||||
}
|
||||
|
||||
// 前端静态资源:dist/client(含 /assets 与 /stickers),assets 带 contenthash → immutable
|
||||
// 前端静态资源:dist/client(含 /assets 与 /stickers),assets 带 contenthash → immutable;
|
||||
// HTML 用 no-cache(每次协商),避免 no-store/max-age=0 导致浏览器丢弃历史滚动状态(F5 不恢复位置)
|
||||
app.use(
|
||||
express.static(distClient, {
|
||||
cacheControl: false, // 关闭 send 自动写入的 Cache-Control,统一由 setHeaders 决定
|
||||
setHeaders(res, filePath) {
|
||||
if (filePath.includes(`${path.sep}assets${path.sep}`)) {
|
||||
res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
|
||||
} else {
|
||||
res.setHeader('Cache-Control', 'no-cache');
|
||||
}
|
||||
},
|
||||
}),
|
||||
@@ -88,6 +92,9 @@ app.use(async (req, res, next) => {
|
||||
const { statusCode, headers, body } = httpResponse;
|
||||
res.statusCode = statusCode;
|
||||
for (const [name, value] of headers) res.setHeader(name, value);
|
||||
// Vike 默认对 HTML 发 no-store:会使浏览器丢弃该历史条目的滚动恢复状态(F5 回到顶部)。
|
||||
// 改为 no-cache:文档仍每次重新验证/渲染,但保留浏览器原生 scroll restoration。
|
||||
res.setHeader('Cache-Control', 'no-cache');
|
||||
if (typeof body === 'string') {
|
||||
res.send(body);
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user