用途
该技能用于为 Backstage 的目录实体页面(catalog entity page)创建扩展。典型场景包括:
- 在目录实体的 Overview 标签页中添加一张卡片,例如在关联 Jira 项目的 Component 上展示 Jira 项目信息。
- 为目录实体页面添加一个完整的标签页(带独立 URL 路径的内容面板),例如在 Component 上添加 /incidents 标签页,列出该组件的故障事件。
- 根据实体 kind、spec type、注解是否存在或任意自定义谓词,控制扩展何时出现。
这是脚手架生成 frontend-plugin-module 最常见的原因。所编写的插件通过这些蓝图扩展宿主应用的 catalog 插件。
主要能力
该技能提供两种蓝图模式:
- 实体 Overview 标签页上的卡片:使用
EntityCardBlueprint.make({ name, params: { loader, filter?, type? } }),参考 references/card.md。 - 实体页面上的完整标签页(带独立 URL 路径):使用
EntityContentBlueprint.make({ name, params: { path, title, loader, filter?, group?, icon? } }),参考 references/content.md。
两种蓝图均来自 @backstage/plugin-catalog-react/alpha,共享以下特性:
- 一个 loader:
() => Promise<JSX.Element>,用于对渲染组件进行代码分割。 - 一个 filter 参数,用于控制扩展何时出现。
组件在 catalog 实体上下文中渲染,可通过 @backstage/plugin-catalog-react 的 useEntity() 读取当前实体。
使用方式
该技能有两种调用模式:
- 独立模式:编辑一个以 catalog 为目标的现有 frontend-plugin-module,选择合适的参考(card 或 content)并添加扩展。
- 脚手架后模式(由 creating-backstage-plugin 针对以 catalog 为目标的 frontend-plugin-module 模板调用):根据用户描述脚手架生成扩展及其渲染的组件。
实体过滤
两种蓝图上的 filter 参数决定扩展适用于哪些实体,接受三种形式:
- 字符串(最常见):
'kind:component'、'kind:component,spec.type:service'、'metadata.annotations.acme.com/jira-project'。逗号分隔表示 AND,同一键的多种形式表示 OR。 - FilterPredicate(结构化):经 Zod 校验的对象形式,用于更丰富的逻辑。需对照
../backstage/packages/filter-predicates/src/核实确切结构。 - 函数:
(entity: Entity) => boolean,完全程序化控制。应谨慎使用——字符串过滤器与上游的配置覆盖系统组合得更好。
如果省略 filter,扩展会出现在所有实体 kind 上。这几乎总是错误的——即使只是 'kind:component',也应设置过滤器。
适用场景
- 需要向 Backstage 目录实体的概览页添加信息卡片。
- 需要为目录实体页面新增带独立路由的标签页。
- 需要按实体属性(kind、spec type、注解等)精确控制扩展的显示范围。
- 正在编写以 catalog 插件为扩展目标的 frontend-plugin-module。
限制与注意事项
- 蓝图来自
@backstage/plugin-catalog-react/alpha(当前为 @alpha)。需对照../backstage/plugins/catalog-react/src/alpha/blueprints/跟踪导入路径。 - 组件本身从
@backstage/plugin-catalog-react(主入口,而非 /alpha)导入useEntity。该 hook 返回{ entity },类型为 Entity——使用@backstage/catalog-model的目录实体模型对 metadata、spec 等进行类型化访问。 useEntity只能在这些蓝图渲染的组件内部使用——在 catalog 实体上下文之外调用会抛出异常。- 必须使用
loader: () => Promise<JSX.Element>形式以实现代码分割。不要传入同步组件导入——应使用() => import('./MyCard').then(m => <m.MyCard />)。 - 对于实体特定的数据获取,将
useEntity与 using-backstage-frontend-system 中的数据 hook 约定结合使用(一个围绕fetchApi.fetch包装useAsync的 hook)。将entity.metadata.name或某个注解作为缓存键。 - 宿主应用的 catalog 插件拥有路由
entity-content:catalog/overview(卡片挂载处)和page:catalog/entity(内容标签页挂载处)。模块安装到与 catalog 插件相同的后端——采用者通过backend.add(...)和app.installPlugin(...)安装,无需其他操作。