运行时与渲染链路
从 resolve 到 BlockRenderer 的全过程
本文讲区块是怎么显示出来的。
1. 页面级入口
页面拿到 pageConfig 后会调用:
resolveBlockData(pageConfig, pageContext)- 内部转到
resolveBlocks(批量)或resolveSingleBlock(单个)
核心文件:apps/web/src/lib/server/block-data-resolver.ts
2. 单区块解析流程
核心文件:apps/web/src/blocks/core/runtime/pipeline.ts
单区块流程:
- 读取 definition。
- 处理 content(统一标准化)。
- 处理 placeholders。
- 处理 media。
- 调用业务 fetcher。
- 组装
ResolvedBlock。
3. ResolvedBlock 长什么样
interface ResolvedBlock<TContent = unknown, TBusiness = unknown> {
id: number | string;
block: string;
description?: string;
content: TContent;
runtime: {
context: Record<string, unknown>;
placeholders: Record<string, unknown>;
media: Record<string, unknown>;
business: TBusiness;
meta: {
status: "ok" | "error";
errors?: Array<{ code: string; message: string }>;
};
};
}4. 组件层如何读取运行时数据
所有区块组件都使用:
import { getBlockRuntimeData } from "@/blocks/core/runtime/envelope";该方法会把 context + placeholders + media + business 合并成一个对象,
方便统一读取多来源运行时数据。
示例:
const data = getBlockRuntimeData<{ posts?: Array<{ title: string }> }>(
block.runtime,
);
const posts = data.posts || [];5. 渲染器职责边界
渲染器只做两件事:
- 根据
block.block加载组件。 - 传递
{ block, mode }。
不做:
- 业务数据请求。
- placeholder/media 解析。
- 手工拼接
config.data。
6. 编辑器与前台为什么一致
因为两条链路都走同一个 resolver/pipeline,
解析逻辑、能力开关、业务 fetcher 都完全一致。
渲染时仅通过组件入参 mode 区分页面态与编辑态,因此能接近“所见即所得”。
7. 单块预览接口
编辑器 BlockLibrary 预览会调用 fetchBlockData(Server Action),内部同样走 resolveSingleBlockData。
所以你新增区块后,只要链路接通,预览和前台都能拿到同一套 runtime 结果。
8. 错误与降级
pipeline 里有统一错误阶段标记:
definitioncontentplaceholdersmediabusiness
开发环境便于直接暴露错误定位,生产环境会尽量单块降级,避免整页中断。