Definition API
definition.ts 的字段语义、写法、缓存声明与约束
definition.ts 是区块声明入口。
它定义区块类型、schema 加载方式、组件加载方式、运行能力与缓存标签声明。
1. 类型定义
见:apps/web/src/blocks/core/definition.ts
export interface BlockCacheTagResolverParams<TContent = unknown> {
block: RuntimeBlockInput<TContent>;
content: TContent;
context: BlockRuntimeContext;
}
export type BlockCacheTagResolver<TContent = unknown> =
| readonly string[]
| ((params: BlockCacheTagResolverParams<TContent>) => readonly string[]);
export interface BlockCacheConfig<TContent = unknown> {
tags: BlockCacheTagResolver<TContent>;
}
export interface BlockDefinition<TContent = unknown, TBusiness = unknown> {
type: string;
schema: () => Promise<BlockFormConfig>;
component: () => Promise<
ComponentType<BlockComponentProps<TContent, TBusiness>>
>;
cache?: BlockCacheConfig<TContent>;
capabilities: {
context: "inherit" | "none";
placeholders?: {
enabled: boolean;
source: "content";
withContext: boolean;
};
media?: Array<{
path: string;
kind: "image" | "imageArray";
output?: string;
}>;
};
}2. 字段说明
type
- 区块唯一标识。
- 必须与
schema.blockType一致。 - 建议使用短横线风格,例如
multi-row-layout。
schema
返回该区块的表单配置。
推荐懒加载写法:
schema: () =>
import("./schema").then((m) => m.FEATURE_BLOCK_FORM_CONFIG),component
返回区块组件。
推荐懒加载写法:
component: () =>
import("./index").then((m) => m.default),cache
用于声明该 block 的缓存依赖标签。
你可以在 block 自己的 definition 中注册标签,不需要中心化配置。
支持两种值类型:
- 固定数组:
["posts", "tags"] - 动态函数:根据 block content/context 返回标签
cache: {
tags: ({ content, context }) => {
const tags = ["gallery/list"];
if (content?.authorUid) tags.push(`users/${content.authorUid}`);
if (context.slug) tags.push(`posts/${context.slug}`);
return tags;
},
},capabilities.context
inherit:可接收页面上下文(slug/page/url/pageSize)。none:不接收上下文。
其中,url 在每个页面都可用,slug / page 仅在当前页面有url参数(:slug、:page)时可用。
例如,如果当前页面是 /posts/my-first-post,页面url模式是 /posts/:slug,则 slug 为 my-first-post。
capabilities.placeholders
enabled:是否启用占位符解析。source:当前固定"content"。withContext:占位符解析时是否可读上下文。
capabilities.media
告诉 pipeline 哪些字段需要统一做媒体解析。
媒体解析用于将区块中的 url(例如 /p/xxxxxxxxxxxx)转换为数据库中具有完整元信息的媒体对象,包括尺寸、模糊数据等,便于 CMSImage 等组件使用。
media: [
{ path: "logoImage", kind: "image", output: "logoImage" },
{ path: "galleryImages", kind: "imageArray", output: "galleryImages" },
];3. 缓存标签设计建议
优先细粒度标签,尽量避免全局标签导致大面积失效。
推荐:
- 实体详情:
posts/{slug}、projects/{slug}、photos/{slug}、users/{uid}。 - 配置项:
config/{key}(例如config/site.shiki.theme)。 - 明确列表:
gallery/list、friend-links/list。
谨慎使用:
posts、projects、photos、config这类全局标签。
4. 与 Server Action 的配合(必须)
仅声明 cache.tags 不够。
数据发生变更时,需要在对应 server action 中 updateTag(...) 精准失效。
// 文章更新
updateTag(`posts/${slug}`);
// 文章 slug 变更要同时失效旧/新
updateTag(`posts/${oldSlug}`);
updateTag(`posts/${newSlug}`);
// 配置更新(按 key)
updateTag(`config/${settingKey}`);
// 图库列表
updateTag("gallery/list");如果你的页面有“上一篇/下一篇”这类邻接数据,也要在写操作里额外失效受影响邻居的标签。
5. 推荐模板
import { createBlockDefinition } from "@/blocks/core/definition";
export const featureBlockDefinition = createBlockDefinition({
type: "feature",
schema: () => import("./schema").then((m) => m.FEATURE_BLOCK_FORM_CONFIG),
component: () => import("./index").then((m) => m.default),
cache: {
tags: ["feature/list"],
},
capabilities: {
context: "inherit",
placeholders: {
enabled: true,
source: "content",
withContext: true,
},
media: [],
},
});6. 约束与反模式
必须做
type唯一。schema与component都使用懒加载。- 对能力进行最小声明(只开启你真的需要的能力)。
- 缓存标签按需、细粒度设计,并在写操作中配套
updateTag。
禁止做
- 在
definition.ts中直接import "./fetcher"。 - 在
componentloader 里混入业务请求逻辑。 - 让
type与schema.blockType不一致。 - 把全站数据都挂在单个全局标签上(例如所有场景都用
posts)。