feat: Vike +data 服务端取数 / SEO Head 移植 / 404 错误页 / 服务端 DOM 模拟
- feedData.ts 聚合首页/板块/帖子详情数据,缺失内容 throw render(404) - Go 侧 spa_meta/seo 的 head 生成逻辑移植到 src/ssr/head.ts - _error 页复用站点壳渲染 404,+data 从 abortReason 恢复壳层数据 - linkedom 模拟服务端 DOM,DOMPurify 封装为 SSR 透传的 sanitizeHtml - 新增 /api/home-boot 聚合端点(handler/home_boot.go)供 SSR 冷启动灌缓存
This commit is contained in:
@@ -2,10 +2,15 @@ import type { ComponentType, ReactElement } from 'react';
|
||||
import { renderToReadableStream } from 'react-dom/server';
|
||||
import { escapeInject, dangerouslySkipEscape } from 'vike/server';
|
||||
import type { PageContextServer } from 'vike/types';
|
||||
import App from '../src/App';
|
||||
import { createHomeStore } from '../src/store/homeStore';
|
||||
import { createRequestScope } from '../src/ssr/scopeTypes';
|
||||
import { runWithScope } from '../src/ssr/scope';
|
||||
import { seedFeedData, type FeedData } from '../src/ssr/feedData';
|
||||
import { renderHeadTags } from '../src/ssr/head';
|
||||
import { installServerDom } from '../src/ssr/serverDom';
|
||||
|
||||
// 服务端 DOM polyfill:内容处理依赖 DOMParser/document,须在渲染前安装
|
||||
installServerDom();
|
||||
|
||||
export { onRenderHtml };
|
||||
|
||||
@@ -32,6 +37,7 @@ async function renderPageToString(element: ReactElement): Promise<string> {
|
||||
|
||||
async function onRenderHtml(pageContext: PageContextServer) {
|
||||
const Page = pageContext.Page as PageComponent | undefined;
|
||||
const data = (pageContext as { data?: FeedData }).data;
|
||||
|
||||
let pageHtml = '';
|
||||
if (Page) {
|
||||
@@ -41,20 +47,26 @@ async function onRenderHtml(pageContext: PageContextServer) {
|
||||
const { pathname, searchOriginal } = pageContext.urlParsed;
|
||||
const url = pathname + (searchOriginal ?? '');
|
||||
try {
|
||||
pageHtml = await runWithScope(scope, () => renderPageToString(<Page url={url} />));
|
||||
pageHtml = await runWithScope(scope, () => {
|
||||
// 渲染前把 +data 取回的数据 seed 进请求作用域(缓存层按 scope 隔离)
|
||||
seedFeedData(data);
|
||||
return renderPageToString(<Page url={url} />);
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('[j13] SSR 渲染失败,降级 SPA 壳:', err);
|
||||
pageHtml = '';
|
||||
}
|
||||
}
|
||||
|
||||
const headTags = renderHeadTags(data?.head);
|
||||
|
||||
// 404/301 等状态码由 Vike abort 机制(throw render/redirect)原生处理
|
||||
return escapeInject`<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<meta name="description" content="拾三一隅,自在交流" />
|
||||
<title>姜十三论坛 - 拾三一隅,自在交流</title>
|
||||
${dangerouslySkipEscape(headTags)}
|
||||
<script>${dangerouslySkipEscape(THEME_INIT_SCRIPT)}</script>
|
||||
<script>${dangerouslySkipEscape(ZOOM_BLOCK_SCRIPT)}</script>
|
||||
</head>
|
||||
|
||||
Reference in New Issue
Block a user