Backstage 1.31.0-next.1 变更深度解析:Backend System 1.0 收尾与前端系统重构迁移指南
【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstage
本篇技术指南基于 Backstage 1.31.0-next.1 的官方发布说明,系统梳理该版本在后端系统(Backend System)1.0 收尾工作、前端系统(Frontend System)createApp迁移与createFrontendModule取代createExtensionOverrides三大主线上的破坏性变更、关键修复与迁移要点,并结合本仓库源码逐一印证底层实现,帮助你评估升级影响并完成平滑迁移。
该版本为预发布版本(
next.1),版本号后缀-next表示尚未发布为正式稳定版,用于验证与先行体验。仓库内对应正式版变更记录可在 docs/releases/v1.31.0-changelog.md 查阅。
版本定位与升级路径
1.31.0-next.1 是 Backstage 1.31 系列的第二个预发布版本。整个变更的核心语境是Backend System 1.0:后端基础包大量移除废弃 API、简化返回值类型;同时前端系统持续推进 "默认应用结构" 的封装迁移。所有破坏性变更都标注为BREAKING,升级时建议逐包核对。
- 使用 Upgrade Helper 可按目标版本自动计算依赖升级路径(输入目标版本
1.31.0-next.1即可)。 - 本仓库根目录 package.json 与 yarn.lock 记录了当前各包的实际依赖解析版本,可作为升级前后比对的基线。
后端系统 1.0 收尾:backend-common 与 backend-defaults 的破坏性变更
host discovery 不再支持basePath
@backstage/backend-common@0.25.0-next.1与@backstage/backend-defaults@0.5.0-next.1同时移除了 host discovery 实现中的basePath选项:
BREAKING: 你不能再向 host discovery 实现提供
basePath选项。在新后端系统中,插件路由层本身已不再允许选择该路径。
在新后端系统中,插件的路由挂载路径由系统统一管理,basePath这一"每个插件自定义子路径前缀"的能力在架构上已被移除。若你的自定义代码中仍向HostDiscovery或等价实现传入basePath,需要删除该参数并改用插件自身的router路径约定。
dropDatabase等废弃 API 移除
作为 Backend System 1.0 清理工作的一部分(commit988c145/055b75b),一批废弃 API 被彻底删除,无替代实现:
@backstage/backend-common中废弃的dropDatabase函数被移除;@backstage/backend-defaults的/database子路径导出中,LegacyRootDatabaseService类型被移除;create-app相关模板中引用的@backstage/backend-tasks引用也被清理(见下文 CLI 章节)。
dropDatabase原本用于测试场景中清空数据库,其能力在新后端系统的生命周期管理与测试工具链中已被更规范的方式取代。
DatabaseManager.forPlugin直接返回DatabaseService
这是@backstage/backend-defaults/database子路径最值得注意的简化:
DatabaseManager.forPlugin的返回值类型现在是DatabaseService本身,而不是此前间接的管理器对象;forPlugin现在必须传入deps参数(logger与lifecycle服务)。
仓库源码 packages/backend-defaults/src/entrypoints/database/DatabaseManager.ts 中的实现印证了这一点:
forPlugin( pluginId: string, deps: { logger: LoggerService; lifecycle: LifecycleService; }, ): DatabaseService { const client = this.getClientType(pluginId).client; const connector = this.connectors[client]; if (!connector) { throw new Error( `Unsupported database client type '${client}' specified for plugin '${pluginId}'`, ); } const getClient = () => this.getDatabase(pluginId, connector, deps); const skip = this.options?.migrations?.skip ?? this.config.getOptionalBoolean(`plugin.${pluginId}.skipMigrations`) ?? this.config.getOptionalBoolean('skipMigrations') ?? false; return { getClient, migrations: { skip } }; }从源码结构可以推断,forPlugin返回的DatabaseService包含两个核心成员:
getClient:按需懒加载(并缓存)该插件的 Knex 客户端连接,databaseCache以pluginId为键;migrations.skip:迁移跳过开关,优先级从插件级plugin.<pluginId>.skipMigrations到全局skipMigrations,均未配置时默认为false。
同时,DatabaseManager通过plugin.<pluginId>配置块实现"每个插件独立数据库客户端"的覆盖能力(见 DatabaseManager.ts 的getClientType:插件级client配置优先,否则回退到基础client)。
在真正的新后端系统集成点中,databaseServiceFactory(packages/backend-defaults/src/entrypoints/database/databaseServiceFactory.ts)负责把这一切接入coreServices.database:
async createRootContext({ config, rootLifecycle, rootLogger }) { return config.getOptional('backend.database') ? DatabaseManager.fromConfig(config, { rootLifecycle, rootLogger }) : DatabaseManager.fromConfig( new ConfigReader({ backend: { database: { client: 'better-sqlite3', connection: ':memory:' }, }, }), { rootLifecycle, rootLogger }, ); }, async factory({ pluginMetadata, lifecycle, logger }, databaseManager) { return databaseManager.forPlugin(pluginMetadata.getId(), { lifecycle, logger, }); },注意:当未配置backend.database时,工厂会回退到内存版better-sqlite3(connection: ':memory:'),这在本地开发与测试中很有用,但生产环境仍需显式配置数据库。
缓存 API 简化:PluginCacheManager移除
/cache子路径同样走向直接返回服务:
PluginCacheManager类型被移除(仍可从@backstage/backend-common导入,但在那里已标记废弃,官方建议完全迁移到新后端系统后离开该包);- 相应地,
CacheManager.forPlugin立即返回CacheService,不再需要额外的.getClient()调用。
源码 packages/backend-defaults/src/entrypoints/cache/CacheManager.ts 印证了这一点——forPlugin现在直接构造并返回DefaultCacheClient:
forPlugin(pluginId: string): CacheService { const clientFactory = (options: CacheServiceOptions) => { const ttl = options.defaultTtl ?? this.defaultTtl; return this.getClientWithTtl( pluginId, ttl !== undefined ? ttlToMilliseconds(ttl) : undefined, ); }; return new DefaultCacheClient(clientFactory({}), clientFactory, {}); }从 CacheManager.ts 的storeFactories可以看到当前支持的后端缓存存储类型:redis、valkey、memcache、memory、infinispan。未配置backend.cache.store时默认使用memory内存缓存。CacheManager.forPlugin会以pluginId作为 Keyv 命名空间,保证不同插件的缓存键互不冲突。
对应集成点 cacheServiceFactory.ts 同样直接消费该返回值:
async createRootContext({ config, logger }) { return CacheManager.fromConfig(config, { logger }); }, async factory({ plugin }, manager) { return manager.forPlugin(plugin.getId()); },迁移影响:如果你还在用老写法cacheManager.forPlugin(id).getClient(),升级后需要删掉.getClient();如果你还依赖PluginCacheManager类型,请改为直接使用CacheService类型(来自@backstage/backend-plugin-api)。
配置服务化与其他工程化调整
@backstage/backend-defaults@0.5.0-next.1还包含若干非破坏性但值得注意的调整:
- discovery 配置下沉到根配置(commit
622360e):host discovery 相关配置位置调整到配置根节点; - 构造器/工厂改为接受
ConfigService而非Config(commitfe6fd8c):与后端系统"一切皆服务"的方向一致; - 定时任务纳入 OpenTelemetry 追踪(commit
5705424):scheduler 核心服务调度的任务现在会被包装为 OpenTelemetry span,方便观测任务执行链路; - config schema 缩进规范化(commit
b2a329d)。
此外@backstage/backend-app-api@0.10.0-next.1改进了缺失服务依赖的错误提示:现在错误信息会包含插件 ID 与模块 ID(commitc246372),排障时能更快定位是哪个插件/模块缺少服务声明。
前端系统重构:frontend-defaults诞生与createApp迁移
createSpecializedApp回归"裸应用"
@backstage/frontend-app-api@0.9.0-next.1有一处重要的破坏性变更:
BREAKING:
createSpecializedApp现在创建一个不带任何默认应用结构或 API的裸应用。如果需要恢复原行为,可以安装@backstage/plugin-app提供的app插件。
同时,createApp与CreateAppFeatureLoader导出被标记为废弃,它们正在迁移到@backstage/frontend-defaults。
@backstage/frontend-defaults@0.1.0-next.0初始发布
这是本版本新增的包(初始发布,版本0.1.0-next.0),其定位是:
- 通过
createApp提供默认应用装配,取代原来@backstage/frontend-app-api中的createApp; - 新增
CreateAppOptions类型用于createApp的选项; - 新增
createPublicSignInApp,用于创建公开入口点的应用(如登录页)。
仓库中该包的源码 packages/frontend-defaults/src/createApp.tsx 展示了新createApp的实现轮廓:它会在应用加载时合并discoverAvailableFeatures(从配置中发现特性)与options.features传入的特性,并将@backstage/plugin-app的appPlugin作为基础插件注入prepareSpecializedApp。CreateAppOptions支持:
export interface CreateAppOptions { features?: (FrontendFeature | FrontendFeatureLoader)[]; bindRoutes?(context: { bind: CreateAppRouteBinder }): void; advanced?: { configLoader?: () => Promise<{ config: ConfigApi }>; extensionFactoryMiddleware?: | ExtensionFactoryMiddleware | ExtensionFactoryMiddleware[]; loadingElement?: ReactNode; pluginInfoResolver?: FrontendPluginInfoResolver; }; }迁移建议:如果你仍从@backstage/frontend-app-api导入createApp,升级后应改为从@backstage/frontend-defaults导入。只有当确实需要自行搭建完全定制的应用结构时,才考虑createSpecializedApp+ 手动安装app插件。
createFrontendModule取代createExtensionOverrides
@backstage/frontend-plugin-api@0.8.0-next.1引入createFrontendModule作为createExtensionOverrides的替代(后者被标记废弃),并同时废弃BackstagePlugin、FrontendFeature类型,改用@backstage/frontend-app-api中的FrontendPlugin、FrontendFeature。
源码 packages/frontend-plugin-api/src/wiring/createFrontendModule.ts 中CreateFrontendModuleOptions定义如下:
export interface CreateFrontendModuleOptions< TPluginId extends string, TExtensions extends readonly ExtensionDefinition[], > { pluginId: TPluginId; extensions?: TExtensions; featureFlags?: FeatureFlagConfig[]; if?: FilterPredicate; }其核心语义:模块用于为某个已存在的插件添加或覆盖扩展,模块提供的扩展与插件提供的扩展 ID 相同时,模块版本始终优先;若对应插件未安装,该模块会被忽略。createFrontendModule内部会将extensions以pluginId作为命名空间解析(resolveExtensionDefinitions(options.extensions ?? [], { namespace: pluginId, featureType: 'Module' }))。
官方给出的迁移示例(原文档完整代码):
// Before createExtensionOverrides({ extensions: [ createExtension({ name: 'my-extension', namespace: 'my-namespace', kind: 'test', ... }) ], }); // After createFrontendModule({ pluginId: 'my-namespace', extensions: [ createExtension({ name: 'my-extension', kind: 'test', ... }) ], });namespace统一收敛为pluginId
配合上述改动,整个前端系统在统一命名空间概念:
@backstage/core-compat-api@0.3.0-next.1:API 的namespace参数现在默认取发现的pluginId。如果你此前用 ID 直接覆盖 API,其 ID 可能已变化为包含插件 ID 的形式;@backstage/frontend-plugin-api@0.8.0-next.1:createExtensionBlueprint、createExtension的namespace选项被废弃,不再必需,默认取pluginId;@backstage/frontend-app-api@0.9.0-next.1同步移除了废弃的namespace参数(commit948d431),全面改用pluginId。
命名约定上,模块变量建议命名为<pluginId>Module<ModuleName>形式。
平台与工具链更新
@backstage/cli@0.27.1-next.1
config.d.ts纳入 tsconfig:config.d.ts文件被加入tsconfig.json的包含文件列表,使 ESLint 能检测其中的问题或废弃用法(commitd2d2313);- 模板不再引用 backend-common:脚手架模板更新,新生成的后端代码不再依赖
@backstage/backend-common(commit97422b0),与后端系统 1.0 的"迁移离开旧包"方向一致; - esbuild 升级到
^0.23.0(commitf865103); - 修复 CSS/SVG 混用导入问题:此前如果单个模块同时导入
.css与.svg文件,发布后的前端包会生成无效的 import 结构,此版本修复(commit569c3f0)。
@backstage/create-app@0.5.19-next.1
- 与 CLI 同步支持
config.d.ts纳入 tsconfig; - 模板移除对
backend-common的引用; - 清理
@backstage/backend-tasks引用(该包已废弃)。
@backstage/backend-test-utils@0.6.0-next.1
- 新增缺失的
mockServices.rootConfig.mock服务 mock; - 修复
mockServices.rootHttpRouter.factory定义中重复回调的问题(commit710f621)。
@backstage/catalog-client@1.6.7-next.0:排序下沉到数据库
getEntities的排序逻辑从 catalog client迁移到数据库查询层(commit1882cfe)。官方明确指出:
请注意,最新版
@backstage/catalog-client不会再以与之前相同的方式对实体排序,因为排序现在在数据库查询中完成,而非客户端。如果你依赖实体顺序,可能需要更新后端插件或代码。
这是一个行为变更:同样的请求在升级后可能得到不同顺序的结果。@backstage/plugin-catalog-backend@1.25.3-next.1同步应用了该变更。
@backstage/core-components@0.14.11-next.0
SignInPage组件新增titleComponentprop(commit06b8206),允许用任意ReactNode进一步定制标题显示,适合品牌化登录页。
各插件生态修复与适配亮点
除基础包外,本版本对多个官方插件做了适配新后端系统与修复问题的工作,列举与升级相关度较高的几项:
| 插件 | 变更要点 |
|---|---|
@backstage/plugin-notifications-backend@0.4.0-next.1 | 创建新通知时校验通知链接(commitf195972);改用注入式 catalog client |
@backstage/plugin-notifications-backend-module-email@0.3.0-next.1 | 改用注入式 catalog client(commit5edd344) |
@backstage/plugin-catalog-backend-module-github@0.7.3-next.1 | 重构为在新后端系统中使用注入的 catalog client(commit5edd344) |
@backstage/plugin-catalog-graph@0.4.9-next.1 | 修复CatalogGraphPage中点击节点后按返回键导航失效的问题(commitda91078),此前该问题在不同浏览器下表现各异 |
@backstage/plugin-kubernetes-backend@0.18.6-next.1 | 缺少适当配置时跳过启动(commitca96b66),避免启动即失败 |
@backstage/plugin-auth-backend-module-aws-alb-provider@0.2.0-next.1 | claims 中缺少 email 时抛出正确错误(commit8d1fb8d) |
@backstage/plugin-auth-node@0.5.2-next.1 | 扩展 "unable to resolve user identity" 错误信息(commitc46eb0f),便于定位身份解析失败原因 |
@backstage/plugin-signals@0.0.10-next.1 | 为SignalsDisplay组件扩展命名(commit3e9b1a4) |
@backstage/plugin-catalog-unprocessed-entities@0.2.8-next.0 | DevTools 未处理实体表格增加 Location 路径、上次发现时间与下次刷新时间等附加信息(commit4f08c85) |
此外@backstage/plugin-catalog-backend-module-gitlab@0.4.2-next.1内部改用新的 cache manager(commit53b24d9),@backstage/plugin-scaffolder-react@1.12.0-next.1将use-immer升级到^0.10.0,@backstage/codemods@0.1.50-next.0升级jscodeshift到^0.16.0,@backstage/repo-tools@0.9.7-next.1升级@useoptic/openapi-utilities。
升级检查清单
综合以上变更,升级到 1.31.0-next.1(及随后的 1.31 正式版)时建议按以下清单核对:
后端代码:
- 全局搜索
dropDatabase、LegacyRootDatabaseService、PluginCacheManager,确认无残留引用; - 检查
CacheManager.forPlugin(...)调用链,删除多余的.getClient(); - 检查
DatabaseManager.forPlugin(...)调用,补上deps(logger、lifecycle),并按新的DatabaseService返回类型调整消费代码; - 检查 host discovery 相关代码是否传入了
basePath,如有则移除; - 检查后端插件构造函数/工厂中直接使用
Config的地方,考虑迁移为ConfigService; - 确认依赖实体排序结果的应用是否受影响(catalog
getEntities排序已移至数据库)。
- 全局搜索
前端代码:
- 将
@backstage/frontend-app-api的createApp导入迁移到@backstage/frontend-defaults; - 将
createExtensionOverrides迁移为createFrontendModule(提供pluginId); - 检查
createExtension/createExtensionBlueprint/ API 覆盖中的namespace参数,移除后按pluginId语义调整; - 如使用
createSpecializedApp,确认是否需要手动安装@backstage/plugin-app的app插件。
- 将
工程配置:
- 运行
yarn install更新依赖后,用yarn tsc与yarn lint检查config.d.ts相关的类型/ESLint 告警; - 若使用 CLI 模板新建插件,新生成代码将不再引用
backend-common与backend-tasks。
- 运行
本变更记录对应的完整正式版发布说明见 docs/releases/v1.31.0.md,各包详细 API 演进可对照仓库中packages/*/CHANGELOG.md与report*.api.md文件交叉验证。
【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstage
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考