Backstage v1.40.0 版本解读:Scaffolder 2.0 迁移指南、后端限流与前端 Blueprint 生态演进
【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstage
本篇文章围绕 Backstage v1.40.0 的官方变更日志(docs/releases/v1.40.0-changelog.md)展开,聚焦本版本最核心的三条主线:plugin-scaffolder-backend迈入 2.0 大版本(伴随多组破坏性变更与 Zod Schema 迁移)、backend-defaults新增可配置的请求限流中间件、以及新前端系统下EntityIconLinkBlueprint与插件info元数据机制的落地。读完本文,你将掌握如何迁移到 Scaffolder 2.0、如何在app-config.yaml中启用全局/插件级限流、如何自定义 Catalog About 卡片图标链接,并了解新引入的 Kafka 事件模块与 MCP Actions 后端等增量能力。
一、版本概览与升级路径
v1.40.0 是一个横跨前后端、CLI 与多个插件的大版本,其中值得重点关注的包有:
| 包名 | 新版本 | 变化级别 |
|---|---|---|
@backstage/plugin-scaffolder-backend | 2.0.0 | Major(多组破坏性变更) |
@backstage/backend-defaults | 0.11.0 | Minor(新增限流、Actions 服务默认实现) |
@backstage/backend-plugin-api | 1.4.0 | Minor(新增实验性 actions 服务) |
@backstage/plugin-catalog-react | 1.19.0 | Minor(新增EntityIconLinkBlueprint) |
@backstage/plugin-catalog | 1.31.0 | Minor(About 卡片图标链接扩展) |
@backstage/plugin-events-backend-module-kafka | 0.1.0 | 全新模块 |
@backstage/plugin-mcp-actions-backend | 0.1.0 | 全新后端 |
@backstage/cli | 0.33.0 | Minor(模块化 CLI 入口转正) |
升级时建议使用官方 Upgrade Helper 工具定位到1.40.0目标版本,逐项核对本文列出的破坏性变更;对于自建 Backstage 应用,执行backstage-cli versions:bump前请先确认packages/backend与packages/app中相关依赖的锁定版本与变更日志中的依赖升级清单(例如@backstage/backend-defaults@0.11.0、@backstage/plugin-scaffolder-node@0.9.0)保持一致。
二、Scaffolder Backend 2.0.0:破坏性变更全解与迁移步骤
@backstage/plugin-scaffolder-backend在此版本发布 2.0.0,包含了四组BREAKING CHANGES和一批弃用声明,是本次升级工作量最大的部分。仓库中对应的实现位于 plugins/scaffolder-backend,相关的类型与工具函数则集中在 plugins/scaffolder-node。
2.1 清理长期存在的重导出(re-exports)
第一组破坏性变更移除了从scaffolder-backend插件包中"转手"导出的一批函数。它们已被分拆到各自的集成模块中,迁移映射如下:
| 原导入来源(已移除) | 迁移后的正确导入来源 |
|---|---|
createPublishAzureAction | @backstage/plugin-scaffolder-backend-module-azure |
createPublishBitbucketCloudAction | @backstage/plugin-scaffolder-backend-module-bitbucket-cloud |
createPublishBitbucketServerAction、createPublishBitbucketServerPullRequestAction | @backstage/plugin-scaffolder-backend-module-bitbucket-server |
createPublishBitbucketAction | @backstage/plugin-scaffolder-backend-module-bitbucket |
createPublishGerritAction、createPublishGerritReviewAction | @backstage/plugin-scaffolder-backend-module-gerrit |
createGithubActionsDispatchAction、createGithubDeployKeyAction、createGithubEnvironmentAction、createGithubIssuesLabelAction、CreateGithubPullRequestActionOptions、createGithubRepoCreateAction、createGithubRepoPushAction、createGithubWebhookAction、createPublishGithubAction | @backstage/plugin-scaffolder-backend-module-github |
createPublishGitlabAction | @backstage/plugin-scaffolder-backend-module-gitlab |
ActionContext、createTemplateAction、executeShellCommand、ExecuteShellCommandOptions、fetchContents、TaskSecrets、TemplateAction | @backstage/plugin-scaffolder-node |
此外还有两组类型与实现需要迁移:
SerializedTask、SerializedTaskEvent、TaskBroker、TaskBrokerDispatchOptions、TaskBrokerDispatchResult、TaskCompletionState、TaskContext、TaskEventType、TaskStatus、TemplateFilter、TemplateGlobal应从@backstage/plugin-scaffolder-node导入;ScaffolderEntitiesProcessor应改为从@backstage/plugin-catalog-backend-module-scaffolder-entity-model导入(该处理器用于将 Scaffolder 生成的实体注册进 Catalog,相关实体模型定义见 plugins/catalog-backend-module-scaffolder-entity-model)。
与此同时,fetch:template动作中已弃用的copyWithoutRender选项被彻底移除,请统一改名为copyWithoutTemplating。
2.2/alpha导出移除与旧后端系统createRouter退役
第二组破坏性变更涉及两件事:
@backstage/plugin-scaffolder-backend/alpha不再导出插件本身,请直接使用import('@backstage/plugin-scaffolder-backend');- 旧后端系统使用的
createRouter函数及其RouterOptions类型被移除。
这意味着仍在用旧后端系统(createRouter+RouterOptions方式)组装 Scaffolder 的应用必须迁移到新后端系统(createBackend+ 插件实例化),否则升级后无法编译。
2.3createBuiltinActions移除与 Catalog 动作的依赖重构
第三组破坏性变更:
createBuiltinActions方法被移除。它在旧后端系统中仅用于"再次传入默认动作列表",而新后端系统默认会合并所有动作,因此不再需要;createCatalogRegisterAction与createFetchCatalogEntityAction不再依赖AuthService,且参数由CatalogClient换成CatalogService。
如果你是通过scaffolderActionsExtensionPoint自定义覆盖默认动作并因此遇到类型错误,可参考下面的迁移写法(源码层面与此对应的扩展点声明位于 plugins/scaffolder-node/src/alpha):
import { catalogServiceRef } from '@backstage/plugin-catalog-node'; import { scaffolderActionsExtensionPoint } from '@backstage/plugin-scaffolder-node/alpha'; export const myModule = createBackendModule({ pluginId: 'scaffolder', moduleId: 'test', register({ registerInit }) { registerInit({ deps: { scaffolder: scaffolderActionsExtensionPoint, catalog: catalogServiceRef, }, async init({ scaffolder, catalog }) { scaffolder.addActions( createCatalogRegisterAction({ catalog, }), createFetchCatalogEntityAction({ catalog, integrations, }), ); }, }); }, });无独有偶,plugin-scaffolder-backend-module-github的createGithubEnvironmentAction也做了同样的依赖替换(AuthService→CatalogService、CatalogClient→CatalogService),迁移模式与此处完全一致。这一系列的改动表明:Scaffolder 动作正在全面收敛到「通过CatalogService访问目录、通过scaffolderActionsExtensionPoint注册动作」的新范式。
2.4 一大批 Task/TaskStore 相关类型弃用
v1.40.0 同时声明了一批弃用类型,包括CreateWorkerOptions、DatabaseTaskStore、DatabaseTaskStoreOptions、TaskManager、TaskStoreCreateTaskOptions、TaskStoreCreateTaskResult、TaskStoreEmitOptions、TaskStoreListEventsOptions、TaskStoreRecoverTaskOptions、TaskStoreShutDownTaskOptions。
变更日志明确说明:目前没有直接的替代路径,这些类型将被移除并重新设计,以在新后端系统中提供更优雅的 worker 定义方式。这意味着依赖这些内部类型做深度定制的团队需要提前关注后续版本的替代方案。
2.5 动作 Schema 迁移到 Zod 原生写法
@backstage/plugin-scaffolder-node@0.9.0将定义createTemplateAction输入/输出 Schema 的旧方式替换为原生的 Zod 方式。三阶段写法对照如下:
// 1) 最老的 JSON Schema 写法(已不推荐) createTemplateAction<{ repoUrl: string }, { repoOutput: string }>({ id: 'test', schema: { input: { type: 'object' required: ['repoUrl'] properties: { repoUrl: { type: 'string', description: 'repository url description' } } } } }); // 2) 旧的 Zod 写法(已不推荐) createTemplateAction({ id: 'test' schema: { input: { repoUrl: z.string({ description: 'repository url description' }) } } }) // 3) 新的 Zod 函数式写法(推荐) createTemplateAction({ id: 'test', schema: { input: { repoUrl: z => z.string({ description: 'repository url description' }) } } }) // 或对更复杂的联合类型使用整体函数式写法 createTemplateAction({ id: 'test', schema: { input: z => z.object({ repoUrl: z.string({ description: 'repository url description' }) }) } })新写法把 schema 定义从"值"升级为"函数",使得 schema 可以延迟求值并复用zod的全部类型能力(联合、交叉、条件等)。scaffolder-backend-module-*系列模块(azure、bitbucket、bitbucket-cloud、bitbucket-server、gerrit、gitea、gitlab、confluence-to-markdown、cookiecutter、rails、sentry、yeoman 等)都在本版本统一迁移到新格式。
重要附带变更:logStream已从ActionsContext中彻底移除,ctx.logger现在直接是LoggerService实现。没有官方替代方案;若仍需使用 logStream,官方建议自建一个写入ctx.logger的流。相应地,plugin-scaffolder-node-test-utils的createMockActionContext也移除了logStream参数。
2.6 模板each步骤支持 Secrets
一个很实用的新能力:each步骤中可以直接引用${{ secrets.xxx }}。例如:
each: [ { name: "Service1", token: "${{ secrets.token1 }}" }, { name: "Service2", token: "${{ secrets.token2 }}" }, ]这意味着在软件模板的循环步骤中按元素注入机密(例如批量创建带凭据的服务)不再需要外部拼接。另外,本版本为 Scaffolder 补充了更多测试(e92e481),可参考 plugins/scaffolder-backend 中的测试目录了解动作行为的既有约定。
三、backend-defaults 0.11.0:全局与插件级请求限流
@backstage/backend-defaults@0.11.0引入了基于express-rate-limit的限流中间件。其实现位于 packages/backend-defaults/src/lib/rateLimitMiddleware.ts,并在 packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.ts 的applyDefaults()中通过app.use(middleware.rateLimit())挂载到根 HTTP 路由。对应的单元测试见 packages/backend-defaults/src/lib/rateLimitMiddleware.test.ts 与 packages/backend-defaults/src/lib/RateLimitStoreFactory.test.ts。
3.1 开启全局限流
在app-config.yaml中增加如下配置即可开启:
backend: rateLimit: window: 6s incomingRequestLimit: 100window:时间窗口,支持时长字符串(如6s),源码内部通过readDurationFromConfig解析并转为毫秒;incomingRequestLimit:窗口内允许的最大请求数,超限返回429。
从源码看,该中间件还支持以下可选配置项(均可写入backend.rateLimit):
| 配置键 | 作用 |
|---|---|
ipAllowList | 放行 IP 列表,默认值为['127.0.0.1', '0:0:0:0:0:0:0:1', '::1'](本机地址默认放行) |
skipSuccessfulRequests | 成功请求不计入限流 |
skipFailedRequests | 失败请求不计入限流 |
passOnStoreError | 存储层报错时是否放行(容错) |
此外,限流键生成使用ipKeyGenerator对 IPv6 地址做规范化,避免客户端通过轮换块内地址绕过限制;validate.trustProxy被置为false,在配置backend.trustProxy时需注意代理场景下的 IP 语义。
3.2 插件级限流
若只想限制某个插件的流量,可关闭全局限流并为指定插件单独配置:
backend: rateLimit: global: false # 关闭全局限流 plugin: catalog: window: 6s incomingRequestLimit: 100global: false关闭全局兜底,plugin.catalog则为 catalog 插件单独设定窗口与上限,适合对高频但易被打爆的插件接口做精细化保护。
3.3 自定义configure回调的兼容提醒
变更日志特别提醒:如果你在 root HTTP router 服务的configure回调中自定义配置且没有调用applyDefaults(),需要把限流中间件(以及其他默认中间件)自行合入你的自定义配置,否则升级后不会自动获得限流能力。建议直接调用applyDefaults()并在其后追加自定义逻辑。
四、实验性 Actions 服务:跨插件注册与调用动作
@backstage/backend-plugin-api@1.4.0在/alpha导出中新增了两个实验性服务:actionsRegistry(注册分布式动作)与actions(调用动作),并提供了默认实现(c999c25,落在backend-defaults中)。典型用法:
import { actionsRegistryServiceRef, actionsServiceRef, } from '@backstage/backend-plugin-api/alpha'; createBackendPlugin({ pluginId: 'test-plugin', register({ registerInit }) { registerInit({ deps: { actions: actionsServiceRef, actionsRegistry: actionsRegistryServiceRef, }, async init({ actions, actionsRegistry }) { actionsRegistry.register({ ..., }); await actions.invoke(...); }, }); }, });与之配套,@backstage/plugin-catalog-backend@2.1.0已用ActionsRegistry实现了get-catalog-entity动作(2e7adf0),而backend-test-utils@1.6.0也新增了对应的 mock 工具,便于为动作编写单元测试:
import { actionsRegistryServiceMock } from '@backstage/backend-test-utils/alpha'; const mockActionsRegistry = actionsRegistryServiceMock(); const mockCatalog = catalogServiceMock({ entities: [ ... ], }); createGetCatalogEntityAction({ catalog: mockCatalog, actionsRegistry: mockActionsRegistry, }); await expect( mockActionsRegistry.invoke({ id: 'test:get-catalog-entity', input: { name: 'test' }, }), ).resolves.toEqual(...)五、Catalog 新前端系统:EntityIconLinkBlueprint 与 About 卡片自定义
@backstage/plugin-catalog-react@1.19.0引入EntityIconLinkBlueprint,用于自定义 Catalog 实体页 About 卡片上的图标链接。其 Blueprint 定义位于 plugins/catalog-react/src/alpha/blueprints/EntityIconLinkBlueprint.tsx:它挂载在entity-card:catalog/about扩展点的iconLinks输入上,通过useProps数据 ref 输出图标链接属性,并支持filter(按实体过滤)与label/title配置覆盖。
5.1useProps返回的属性表
useProps钩子返回以下属性(将透传给图标链接组件):
| 名称 | 描述 | 类型 | 默认值 |
|---|---|---|---|
icon | 要显示的图标 | JSX.Element | 无 |
label | 元素的标签 | string | 无 |
title | 元素的标题 | string | 无 |
disabled | 是否禁用该元素 | boolean | false |
href | 点击后跳转的 URL | string | 无 |
onClick | 点击回调函数 | () => void | 无 |
5.2 使用示例
import { EntityIconLinkBlueprint } from '@backstage/plugin-catalog-react/alpha'; //... EntityIconLinkBlueprint.make({ name: 'my-icon-link', params: { useProps() { const { t } = useTranslationRef(myIconLinkTranslationRef); return { label: t('myIconLink.label'), icon: <MyIconLinkIcon />, href: '/my-plugin', }; }, }, });5.3 通过 app-config 覆盖 label 与 title
还可以在app-config.yaml中用app.extensions覆盖默认图标链接的label与title:
app: extensions: - entity-icon-link:my-plugin/my-icon-link: config: label: 'My Custom Icon Link label'注意:当没有任何图标链接扩展被启用时,About 卡片头部会被整体隐藏(适合把链接独立展示在别的卡片上的场景)。
5.4 与 About 卡片默认链接的拆分
@backstage/plugin-catalog@1.31.0中,原本内置于 Catalog About 卡片链接的「Scaffolder 启动模板」与「TechDocs 阅读文档」两个图标链接被抽取出来,改由Scaffolder与TechDocs插件分别提供。这意味着:未安装 TechDocs/Scaffolder 插件时,对应图标将不再出现;如果你为这两个链接标题配置了非默认翻译,需要改用 Scaffolder/TechDocs 各自的 translation reference(翻译键保持不变:aboutCard.viewTechdocs与aboutCard.launchTemplate)。
六、事件系统:全新 Kafka 消费模块
@backstage/plugin-events-backend-module-kafka@0.1.0是全新的事件后端模块,位于 plugins/events-backend-module-kafka。它提供两个核心件:
KafkaConsumerClient:基于 KafkaJS 建立消费连接;KafkaConsumingEventPublisher:订阅配置的 Kafka topic,并把收到的消息发布到 Backstage 事件服务(Event Service)。
从配置解析实现(plugins/events-backend-module-kafka/src/KafkaConsumingEventPublisher/config.ts)可以看出,它支持多实例配置(events.modules.kafka.kafkaConsumingEventPublisher下的每个键视为一个 publisher),每个 publisher 可配置topics数组,其中kafka.groupId、kafka.topics、kafka.fromBeginning为消费组与订阅主题的核心参数,kafka.sessionTimeout、kafka.rebalanceTimeout、kafka.heartbeatInterval、kafka.metadataMaxAge、kafka.maxBytesPerPartition、kafka.minBytes、kafka.maxBytes、kafka.maxWaitTime等可控制消费行为,kafka.autoCommit(默认true)与kafka.pauseOnError(默认false)分别控制手动提交与出错暂停策略。模块测试见 plugins/events-backend-module-kafka/src/KafkaConsumingEventPublisher/module.test.ts。
同时,@backstage/plugin-events-backend-module-google-pubsub@0.1.1新增了EventConsumingGooglePubSubPublisher,用于把 Backstage 事件推送回 Google Pub/Sub。
七、通知系统:广播与保留期策略
@backstage/plugin-notifications-backend@0.5.7带来两个值得注意的行为变化:
默认自动删除一年前的通知:新增的定时任务每 24 小时运行一次,删除超过 1 年的通知。可通过
app-config.yaml配置保留期:notifications: retention: 1y若将
retention设为false,则禁用自动清理。广播通知的用户字段:通知 API 对广播(broadcast)通知始终返回
user: null,避免误导性地暴露发送者身份。
此外,通知与 Scaffolder 通知模块(plugin-scaffolder-backend-module-notifications)都支持了"在某个来源(origin)内按 topic 开关通知"的用户级能力(1fb5f06)。
八、前端系统:插件info元数据与useAppNode
@backstage/frontend-plugin-api@0.10.3为createFrontendPlugin增加了可选的info选项,用于提供插件元数据加载器,有两种形式:
// 方式一:加载插件自身的 package.json(推荐给发布到包仓库的插件) export default createFrontendPlugin({ pluginId: '...', info: { packageJson: () => import('../package.json'), }, }); // 方式二:加载不透明 manifest(仅限组织内使用,禁止用于公开发布的插件) export default createFrontendPlugin({ pluginId: '...', info: { manifest: () => import('../catalog-info.yaml'), }, });packageJson:指向插件包内的package.json,适合任何在独立包中定义、尤其是发布到公共包仓库的插件;manifest:仅限在单一组织内部使用的插件,可携带额外内部元数据;默认 manifest 解析器能解析标准catalog-info.yaml格式及spec.owner等内置字段。
配套能力包括:frontend-app-api为createSpecializedApp支持了pluginInfoResolver选项,并新增静态配置键app.pluginOverrides;@backstage/plugin-catalog等插件实例新增info.packageJson选项;同时新增了useAppNode钩子,可从最近的ExtensionBoundary获取AppNode引用。本版本大量插件(catalog、techdocs、home、org、notifications、search、signals、user-settings、api-docs、devtools、kubernetes、catalog-import、catalog-graph、app-visualizer 等)都同步接入了info.packageJson。
九、CLI 与工具链更新
@backstage/cli@0.33.0与@backstage/create-app@0.7.0的变化集中在开发者体验:
BACKSTAGE_CLI_EXPERIMENTAL_BUILD_CACHE标志已移除,改用EXPERIMENTAL_RSPACK;- 实验性的
FORCE_REACT_DEVELOPMENT标志已移除; - Rspack 构建改用
@module-federation/enhanced/rspack的ModuleFederationPlugin; - 仅在
frontend包上启用缓存型 Jest 模块加载器,避免破坏真实 ESM 导入; backstage new生成的插件包模板默认在package.json中加入backstage.pluginId字段;- 打开配置文档命令增加了浏览器打开失败时的回退提示(
d07fe35); create-app在 gitignore 中补充了.cache目录。
@backstage/eslint-plugin@0.1.11新增@backstage/no-mixed-plugin-imports规则,禁止插件之间混用前后端/公共架构导入:不允许前端插件导入后端插件或其他前端插件、不允许后端插件导入前端插件或其他后端插件、不允许公共插件导入前端或后端插件。当前推荐配置下该规则给出 warning,未来将升级为 error,建议提前调整工作区导入结构。
十、其他值得关注的变更
- LDAP 模块(
plugin-catalog-backend-module-ldap):可将用户memberOf或组members的映射设为null,从而只保留单向(或完全禁用)成员关系,规避 LDAP 中两侧属性漂移导致的 Catalog 异常状态;示例配置见变更日志,配置项落在catalog.providers.ldapOrg.default下。 - GitLab 模块(
plugin-catalog-backend-module-gitlab):User/Group 发现默认会摄取指定根组下所有子组的用户,可通过模块配置中的restrictUsersToGroup: true关闭;同时为 GitLab API 调用增加了限流重试。 - Bitbucket Server 模块(
plugin-catalog-backend-module-bitbucket-server):新增validateLocationsExist选项,避免为源仓库中不存在的catalog-info.yaml生成 location。 - Bitbucket Cloud 模块(
plugin-catalog-backend-module-bitbucket-cloud):BitbucketCloudEntityProvider构造参数由CatalogApi换成CatalogService。 - GitHub 组织模块(
plugin-catalog-backend-module-github):处理事件时组织名匹配改为大小写不敏感。 - 权限规则(
plugin-catalog-backend):HAS_LABEL权限规则现在可像HAS_ANNOTATION一样指定可选值。 - TechDocs:引入
backstage.io/techdocs-entity-path注解,可配合backstage.io/techdocs-entity深度链接到其他实体的 TechDocs 页面;同时改善了键盘可访问性(9dde3ba)。 - Canon 组件库(
@backstage/canon@0.5.0):Button/IconButton默认尺寸改为 small,Heading/Text用asprop 取代 render prop,TextField基于 React Aria 重构并新增FieldLabel,Grid 根组件改名为<Grid.Root />,并新增Switch组件。 - mcp-actions 后端(
@backstage/plugin-mcp-actions-backend@0.1.0):MCP Actions 后端的初始实现,详见 plugins/mcp-actions-backend。 - auditor 服务(
backend-defaults):错误处理增强,将错误作为对象传递,并统一了WinstonRootAuditorService与默认工厂的错误处理行为。 - catalog-backend 数据库:
refresh_state_references.id更新为 bigint 类型(4654a78),涉及数据库迁移的团队需留意。 - search-backend-module-techdocs:导出默认文档 collator,便于在搜索索引阶段做文档变换。
- yarn-plugin-backstage:新增/更新依赖时保持
backstage:^版本占位符。
十一、升级建议与风险清单
- 优先处理 Scaffolder 相关破坏性变更:检查自定义动作与后端模块的所有导入来源,对照本文 2.1 节的映射表逐一修正;将动作 Schema 迁移到 Zod 函数式写法;移除对
createBuiltinActions、createRouter、logStream的使用。 - 确认是否使用了被弃用的 Task/TaskStore 类型:
DatabaseTaskStore等一批类型已标记弃用且暂无替代,深度定制的团队需为后续重构预留时间。 - 限流默认关闭,按需开启:限流是可选能力,未配置
backend.rateLimit时行为不变;若自定义了 root HTTP router 的configure,务必合并applyDefaults()。 - 新前端系统下检查 About 卡片:若未安装 TechDocs/Scaffolder 插件,对应图标链接会消失;有自定义翻译的需迁移到对应插件翻译引用。
- 关注实验性 API:
actionsRegistry/actions服务与info.packageJson/info.manifest均为/alpha或实验性能力,接口后续可能调整。 - 升级顺序:建议先在测试环境按依赖图(
backend-defaults→plugin-scaffolder-node→ 各scaffolder-backend-module-*→plugin-scaffolder-backend)逐层验证,再通过 Upgrade Helper 对比目标版本,最后执行全量versions:bump并跑通backstage-cli repo lint、tsc与测试套件。
综上,v1.40.0 的核心信号是:Scaffolder 彻底完成向新后端系统的收敛(模块化动作、Zod Schema、服务化 Catalog 访问),同时后端基础设施(限流、Actions 服务)与前端定制体系(Blueprint、插件元数据)同步走向成熟,是值得认真规划的一次大版本升级。
【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstage
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考