Repository navigation
Frontend Finders
Finder 是前端包的类型化数据源机制。页面通过 data 字段绑定 Finder,平台在渲染前执行 Finder 获取数据并注入组件。
在前端清单的 finders 数组中声明 Finder 名称:
{
"finders": ["blogList", "blogPost", "categories"]
}页面通过 data 字段绑定 Finder,data 是一个 FrontendPageDataRequirement 数组:
{
"path": "/blog/:slug",
"component": "BlogPostPage",
"data": [{ "finder": "blogPost", "as": "post" }]
}每个绑定声明:
-
finder— Finder 名称(必须在finders列表中声明) -
as— 注入到组件 props 的键名 -
input— 可选,传给 Finder 的额外参数 -
permission— 可选,Finder 执行前检查的权限
渲染页面时,平台:
- 解析路径参数(如
:slug→hello-world) - 对
data数组中的每个绑定,调用对应 Finder,传入路径参数、设置和input - 将每个返回值以
as声明的键名注入组件 props
GET /blog/hello-world
→ 路径参数: { slug: "hello-world" }
→ Finder: blogPost({ slug: "hello-world" }, ctx) → 返回文章对象
→ 数据注入: <BlogPostPage post={finderResult} params={pathParams} />
FinderContext 提供 params(路径参数)、settings(前端设置)、api(ApiClient)和 session(会话信息)。
平台把 data[].input 解析成传给 handler(input, ctx) 的第一个参数,规则如下:
input 值 |
解析结果 |
|---|---|
":param"(以 : 开头) |
替换为路径参数,如 { id: ":slug" } → { id: "hello-world" }
|
| 任意字面量(字符串/数字/布尔) | 原样传入 |
键为 $query
|
注入整份 URL query(Record<string, string | string[] | undefined>),用于服务端分页/筛选 |
| 其它键遇到同名 query 参数 |
URL query 覆盖声明的默认值(如 ?page=2 覆盖 { page: 1 }) |
因此「声明的默认值」可被 URL 覆盖,这是实现服务端分页的推荐方式。
管理后台路由的
data绑定不做 query 覆盖,只解析字面量与:param。
Finder 是前端包导出的 FinderProvider,通过 handler 函数提供数据:
interface FinderProvider<Result = unknown> {
handler(input: Record<string, unknown>, ctx: FinderContext): Promise<Result>;
}
interface FinderContext {
params: Record<string, string>;
settings: FrontendSettings;
api: ApiClient;
session?: FinderSession | null;
}示例:
// frontend/src/index.tsx
export const blogPost: FinderProvider<Post> = {
async handler(input, ctx) {
// ctx.params 包含路径参数,ctx.api 是 ApiClient
return ctx.api.get(`/my-plugin/posts/${ctx.params.slug}`, postSchema);
},
};
export function BlogPostPage({ post, params }: { post: Post; params: { slug: string } }) {
return (
<article>
<h1>{post.title}</h1>
<p>{post.content}</p>
</article>
);
}Finder 在前端包的 FrontendPackage.finders 中以名称为键导出,平台通过 data 绑定中的 finder 字段查找对应实现。
Finder 抛出的异常会被平台 try/catch 吞掉,并以 null 作为该绑定的值注入。也就是说 Finder 失败时页面不会报错,只是 props.data.<as> 变成 undefined。调试时可在 Finder 内临时打印,或先确认 ctx.api 请求路径与响应 schema 正确。
- 公开页面:先注册主题的 Finder,再注册插件的;同名 Finder 主题优先,插件不能覆盖主题的。
- 管理后台路由:合并所有已启用插件的 Finder(因此 store 的 admin 页可以读取 catalog 提供的 Finder)。
Finder 调用会写入审计日志:
| action | 说明 |
|---|---|
frontend.finder.call |
Finder 数据调用 |
通过 POST /frontend/audit 端点记录:顶层 pluginId、resourceId(Finder 名)与 meta(含 status:ok / error)。注意:只有插件提供的 Finder 会记审计——主题 Finder 没有 pluginId,不会上报(apps/web/src/lib/pages.ts)。
- Finder 名称在
finders数组中必须唯一 -
finders在编译产物中始终存在,可为空数组[](schema 默认[])
建议使用 camelCase,语义化命名:
| Finder | 说明 |
|---|---|
blogList |
博客列表 |
blogPost |
博客文章 |
categories |
分类列表 |
products |
商品列表 |
productDetail |
商品详情 |
开始
- 核心开发
构建内核扩展
- 插件
- 主题与前端包
AI 与自动化
- 内核 Agent
- MCP
对接平台
- Open Platform API
- Partner API