For AI agents: the complete documentation index is available at /zh/llms.txt, the full documentation bundle is available at /zh/llms-full.txt, and this page is available as Markdown at /zh/guide/server-rendering.md.
  • 中文
  • 服务端与框架

    解析与准备都不依赖 React,可以在服务端、构建期或 Worker 中完成。客户端只加载 react-wikitext/view,接收并恢复渲染快照。

    两种部署方式

    方式服务端做什么客户端加载适合
    客户端渲染源码只发送源文本根入口(解析器 + React)内容量小、按需交互
    服务端准备,客户端渲染解析、准备、序列化快照/view + 恢复函数内容稳定、希望减小客户端体积

    第二种方式把解析成本留在服务端;客户端不再加载 wikiparser-node。

    服务端准备

    // server.tsx
    import { createWikiparser } from "react-wikitext/parse";
    import { prepareWikitext, serializeWikitextRenderDocument } from "react-wikitext/hast";
    
    const parser = createWikiparser();
    
    export function preparePayload(source: string, pageName: string) {
      const document = parser.parse(source, { pageName });
      const prepared = prepareWikitext(document);
      return serializeWikitextRenderDocument(prepared);
    }
    // client.tsx
    "use client";
    
    import { useMemo } from "react";
    import { restoreWikitextRenderDocument } from "react-wikitext/hast";
    import { WikitextView } from "react-wikitext/view";
    
    export function Article({ payload }: { payload: unknown }) {
      const prepared = useMemo(() => restoreWikitextRenderDocument(payload), [payload]);
      return <WikitextView document={prepared} lang="zh-CN" />;
    }

    restoreWikitextRenderDocument 会重新校验结构版本、根节点、HAST 结构与节点预算,并重新执行最终清洗。它不信任任意第三方 HAST;只恢复来自可信服务端或可信缓存的快照。

    Note

    快照同时包含语义树、HAST 与源码,体积明显大于纯 HTML。大文档应按页或按块准备,并评估传输预算。

    Next.js App Router

    根入口与 /view 在模块加载时创建 Context,并使用 React Hook,因此只能在客户端组件中运行。这两个入口的产物顶部带有 "use client" 指令,宿主不需要额外建立边界;服务端只使用 /parse、/hast。

    // app/wiki/[title]/page.tsx
    import { createWikiparser } from "react-wikitext/parse";
    import { prepareWikitext, serializeWikitextRenderDocument } from "react-wikitext/hast";
    import { ArticleView } from "./article-view";
    import { loadPageSource } from "@/lib/wiki";
    
    const parser = createWikiparser();
    
    export default async function Page({ params }: { params: Promise<{ title: string }> }) {
      const { title } = await params;
      const source = await loadPageSource(title);
      const document = parser.parse(source, { pageName: title });
      const payload = serializeWikitextRenderDocument(prepareWikitext(document));
    
      return <ArticleView payload={payload} lang="zh-CN" />;
    }
    // app/wiki/[title]/article-view.tsx
    "use client";
    
    import { useMemo } from "react";
    import { restoreWikitextRenderDocument } from "react-wikitext/hast";
    import { WikitextView } from "react-wikitext/view";
    
    export function ArticleView({ payload, lang }: { payload: unknown; lang: string }) {
      const prepared = useMemo(() => restoreWikitextRenderDocument(payload), [payload]);
      return <WikitextView document={prepared} lang={lang} />;
    }
    // app/layout.tsx
    import "react-wikitext/styles.css";
    • 服务端准备阶段只调用 /parse 与 /hast;这两个入口不加载 React。
    • 客户端组件只负责恢复与渲染,不重新解析。
    • 根入口与 /view 带 "use client",Next.js 会把它们视为客户端边界:可以在 Server Component 中直接渲染,但解析随之发生在客户端。需要服务端解析时,按上面的页面组件先准备快照。
    • 在其他 SSR 环境中,可以用 renderToStaticMarkup 渲染 WikitextView,再让客户端用同一份快照 hydrate。

    Vite 与其他 SSR

    普通 SSR 的思路相同:服务端准备快照,把它作为页面数据发送给客户端,客户端用 /view 恢复并挂载。

    // server entry
    const payload = serializeWikitextRenderDocument(prepareWikitext(document));
    const html = template.replace("__WIKITEXT__", JSON.stringify(payload).replace(/</gu, "\\u003c"));
    • 内联 JSON 时转义 <,避免 </script> 提前结束脚本。
    • 如果页面要由搜索引擎直接读取正文,可以在服务端渲染 WikitextView;此时客户端必须用同一份快照、同一棵树 hydrate。

    Hydration 与锚点

    • headingIdStrategy: "instance" 使用 useId 生成实例前缀,服务端与客户端渲染同一棵树时保持一致。
    • 如果服务端与客户端结构不同,或同一页有多个实例,显式传入 idPrefix 固定前缀。
    • 需要与宿主约定裸锚点(例如已有 #Section 链接)时,使用 headingIdStrategy: "mediawiki";它假设页面只有一个实例。
    • headingIdStrategy: "none" 不写 id,也不生成目录链接,适合不需要锚点的嵌入式展示。

    缓存

    渲染快照可以缓存,但键必须覆盖所有影响输出的输入:

    • AST_SCHEMA_VERSION、RENDER_SCHEMA_VERSION 与解析器版本。
    • 源码与 pageName。
    • 站点配置(config)。
    • prepareOptions:解析函数、插件、policy、labels、headingIdStrategy 与 handlers。

    恢复函数会拒绝版本不匹配的快照;升级库或解析器时应让缓存整体失效。解析结果的缓存策略见性能与预算。

    相关