Backstage @backstage/app-defaults 公共 API 详解:用 createApp 一行代码装配标准 Backstage 应用 📅 发布时间:2026/9/13 17:15:26 👁 浏览次数: Backstage backstage/app-defaults 公共 API 详解用 createApp 一行代码装配标准 Backstage 应用【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstagebackstage/app-defaults是 Backstage 前端体系中的默认装配器它导出的 createApp 函数把一整套开箱即用的图标、主题、页面组件和 API 工厂预置好让你免去手写样板代码就能启动一个标准 Backstage 应用。本文以该包的 API 报告文件 为骨架逐字段解读其公共 API 契约createApp与OptionalAppOptions并结合 源码实现 深入说明每一组默认值的来源、覆盖语义以及底层装配流程帮助你在定制 Backstage 前端时准确判断哪些选项可以不传、哪些传了会整体替换默认值。report.api.md包的公共 API 契约是什么report.api.md 是由 API Extractor 自动生成的 API 报告文件文件头部明确标注 Do not edit this file。它的作用是把一个包对外承诺的公共接口面标注了public的符号固化成一份可 diff、可评审的类型声明快照——当公共 API 发生变化时该文件会随之变化从而在 PR 评审中显式暴露 breaking change。对于backstage/app-defaults这份报告揭示出的公共 API 面非常克制只有两个导出符号import { AppComponents } from backstage/core-app-api; import { AppIcons } from backstage/core-app-api; import { AppOptions } from backstage/core-app-api; import { AppTheme } from backstage/core-plugin-api; import { BackstageApp } from backstage/core-app-api; import { IconComponent } from backstage/core-plugin-api; // public export function createApp( options?: OmitAppOptions, keyof OptionalAppOptions OptionalAppOptions, ): BackstageApp; // public export type OptionalAppOptions { icons?: PartialAppIcons { [key in string]: IconComponent; }; themes?: (PartialAppTheme OmitAppTheme, theme)[]; components?: PartialAppComponents; };也就是说整个包的对外能力浓缩为一句话调用createApp可选项覆盖三类默认值得到一个BackstageApp实例。下面逐层拆解。createApp 的选项类型如何设计注意createApp的选项类型写法options?: OmitAppOptions, keyof OptionalAppOptions OptionalAppOptions这是一个先剔除、再替换的类型技巧OmitAppOptions, keyof OptionalAppOptions从 core-app-api 的 AppOptions 中删除icons、themes、components这三个字段 OptionalAppOptions再把这三个字段以可选Partial形式加回来。效果是AppOptions中原本必传的icons、components、themes经由createApp后全部变为可不传的可选字段——这正是OptionalAppOptions的语义源码注释称之为 The set of app options that createApp will provide defaults for if they are not passed in explicitly见 createApp.tsx。其余AppOptions字段apis、defaultApis、plugins、configLoader、bindRoutes、featureFlags等保持原样透传。OptionalAppOptions 的三个字段与覆盖语义OptionalAppOptions的三个字段覆盖语义各不相同这是使用该包时最容易踩坑的地方。逐一对应源码中的 JSDoccreateApp.tsx#L65-L94和合并实现createApp.tsx#L36-L57icons逐个图标覆盖mergeicons?: PartialAppIcons { [key in string]: IconComponent };PartialAppIcons可以只覆盖其中部分图标交叉类型{ [key in string]: IconComponent }允许传入任意字符串键从而可以追加App 之外的自定义图标例如kind:resource这类按实体 kind 匹配的图标。合并实现是浅展开{ ...icons, ...options?.icons }即按图标逐个覆盖未覆盖的图标保留默认值。components逐个组件覆盖mergecomponents?: PartialAppComponents;同样是浅展开{ ...components, ...options?.components }按组件逐个覆盖。默认AppComponents包含 5 个成员见下文你通常只需要替换其中一两个例如换掉Router或BootErrorPage。themes整组替换replacethemes?: (PartialAppTheme OmitAppTheme, theme)[];源码实现是themes: options?.themes ?? themes——只要传入了themes默认主题全部不再生效JSDoc 原文If this option is provided none of the default themes will be used。这与前两个字段的 merge 语义截然不同定制主题时若漏配了某个变体应用就不会再有该主题。默认值从哪里来深入 defaults 模块createApp的四个默认值来源都集中在 defaults 目录这也是理解不传 options 时会得到什么的关键。默认图标defaults/icons.tsxicons.tsx 用 Material-UI 图标填充了AppIcons的常用键位映射关系如下节选自源码图标键Material 图标典型用途brokenImageBrokenImage图片加载失败占位catalogMenuBook软件目录入口scaffolderCreateNewFolder软件模板入口techdocsSubject技术文档入口searchSearch搜索入口chatChat聊天入口dashboardDashboard仪表盘入口docs/email/github/help/group/user/warning同名图标导航与实体展示kind:api/kind:component/kind:domain/kind:group/kind:location/kind:system/kind:user/kind:resource/kind:template按 kind 映射目录中不同实体类型的列表图标star/unstarred/externalLinkStar/StarBorder/OpenInNew收藏与外链交互需要说明的是package.json显示该包仍依赖material-ui/iconsMUI v4 线源码中也存在mui-to-bui迁移痕迹如 scripts/mui-to-bui 目录可见默认图标层处于 MUI 向 Backstage 自有 BUI 组件库过渡的中间状态。默认主题defaults/themes.tsxthemes.tsx 提供 light / dark 两个主题均通过backstage/theme的UnifiedThemeProvider包裹export const themes: AppTheme[] [ { id: light, title: Light Theme, variant: light, icon: LightIcon /, Provider: ({ children }) ( UnifiedThemeProvider theme{builtinThemes.light} children{children} / ), }, { id: dark, /* 结构同上使用 builtinThemes.dark */ }, ];这套默认主题在 AppOptions.themes 的类型注释 中也有对应描述By default two themes are included, one light variant of the default backstage theme, and one dark。默认组件defaults/components.tsxcomponents.tsx 导出的components: AppComponents包含 5 个成员每一个都对应应用运行时的一个关键兜底场景Progress直接复用backstage/core-components的进度组件应用启动加载时展示Router: BrowserRouter生产路由方案NotFoundErrorPage404 兜底页内部是ErrorPage status404 statusMessagePAGE NOT FOUND /BootErrorPagecomponents.tsx#L42-L55启动失败页会根据step字段给出针对性提示——load-config失败提示配置加载失败需要有人查看该错误load-chunk失败提示懒加载块加载失败请尝试刷新页面并展示error.stackErrorBoundaryFallbackcomponents.tsx#L57-L73插件级错误边界渲染带Retry按钮的ErrorPanel标题为Error in 插件 ID让用户无需刷新整页即可恢复单个插件。值得注意的是同文件中的OptionallyWrapInRouter辅助组件components.tsx#L31-L36它用useInRouterContext()探测是否已存在路由上下文没有则临时套一层MemoryRouter。这保证了BootErrorPage即便在 Router 初始化失败的场景下也能正常渲染——这是一个很典型的错误页自身也要容错的设计细节。默认 API 工厂defaults/apis.tscreateApp通过defaultApis注入了一组 API 工厂apis.ts#L102-L358。作为defaultApis而非apis这组工厂不能被插件的工厂覆盖构成应用的 API 基座见 AppOptions.defaultApis 注释。按功能分组的完整清单基础设施discoveryApiRef→FrontendHostDiscovery.fromConfig基于ConfigApi的默认服务发现alertApiRef→AlertApiForwarder告警转发器analyticsApiRef→NoOpAnalyticsApi空实现的分析 API说明默认不做任何遥测需要分析时由你自己注册工厂替换errorApiRef→ErrorAlerterErrorApiForwarder并调用UnhandledErrorForwarder.forward(errorApi, { hidden: false })把未捕获错误也接入告警storageApiRef→WebStorage浏览器存储实现依赖errorApi。网络层fetchApiRef由createFetchApi构建挂载三层中间件apis.ts#L132-L153FetchMiddlewares.resolvePluginProtocol把http://backstage.io/...之类的插件协议 URL 解析为真实后端地址FetchMiddlewares.injectIdentityAuth自动注入身份认证头FetchMiddlewares.clarifyFailures在请求失败时附加可读的错误上下文。认证体系oauthRequestApiRefOAuthRequestManager以及各 Provider 的 Auth API——GoogleAuth、MicrosoftAuth、GithubAuthdefaultScopes: [read:user]、OktaAuth、GitlabAuth、OneLoginAuth、BitbucketAuthdefaultScopes: [account]、BitbucketServerAuthdefaultScopes: [REPO_READ]、AtlassianAuth、VMwareCloudAuth、OpenShiftAuth。它们全部读取configApi.getOptionalString(auth.environment)说明多环境 OAuth 配置是通过auth.environment区分环境名来切换的。权限permissionApiRef→IdentityPermissionApi.create来自backstage/plugin-permission-react即默认权限策略基于用户身份判断。Toast 桥接toastApiRef来自backstage/frontend-plugin-api没有独立实现而是把 toast 消息降级转发给alertApi内部toastStatusToSeverity把warning/danger/其他状态映射为warning/error/info三级严重度apis.ts#L89-L100并用reactNodeToString递归地把 React 节点标题转成纯文本。createApp 的装配流程合并策略与透传把上面所有默认值串起来createApp 的核心实现 只有几行export function createApp( options?: OmitAppOptions, keyof OptionalAppOptions OptionalAppOptions, ) { return createSpecializedApp({ ...options, apis: options?.apis ?? [], bindRoutes: options?.bindRoutes, components: { ...components, ...options?.components }, // merge configLoader: options?.configLoader, defaultApis: apis, // 不可被插件覆盖 icons: { ...icons, ...options?.icons }, // merge plugins: (options?.plugins as BackstagePlugin[]) ?? [], featureFlags: options?.featureFlags ?? [], themes: options?.themes ?? themes, // replace }); }由此可以读出完整的装配决策表选项不传时的行为传入时的行为icons使用默认图标集与默认图标集逐键浅合并components使用默认 5 组件与默认组件逐键浅合并themes使用 light/dark 双主题整体替换默认主题全部失效apis/plugins/featureFlags空数组原样透传给createSpecializedAppdefaultApis永远注入默认 API 工厂组不接受用户传入无此选项configLoader/bindRoutes透传undefined原样透传最终调用落在 core-app-api 的 createSpecializedApp由后者完成插件收集、路由绑定、Provider 树构建返回BackstageApp。实际使用安装与集成安装按包 README 的说明在 Backstage 仓库根目录执行# From your Backstage root directory yarn --cwd packages/app add backstage/app-defaults当前仓库中该包版本为1.7.12-next.1见 package.jsonbackstage 角色标记为web-library。典型调用形态结合类型定义与 包内测试 的用法一次最小定制通常是import { createApp } from backstage/app-defaults; import catalogPlugin from backstage/plugin-catalog; const app createApp({ plugins: [catalogPlugin], // icons / themes / components 不传全部使用默认值 // 需要时按需传入即可例如只换一个 404 页 // components: { NotFoundErrorPage: MyCustom404 }, }); export default app.createRoot();包内的 createApp.test.tsx 验证了组件覆盖路径测试传入自定义ThemeProvider等components再经createApp({ components }).getProvider()渲染断言自定义组件确实生效。测试同时展示了各默认组件需要覆盖的完整键位NotFoundErrorPage、BootErrorPage、Progress、Router、ErrorBoundaryFallback、ThemeProvider。与新版前端体系的 createApp 区分阅读仓库时容易混淆的一点本仓库的示例应用packages/app/src/App.tsx 调用的是backstage/frontend-defaults的createApp选项形如{ features: [...], advanced: {...} }而不是本文讨论的backstage/app-defaults版本。从源码结构看两套createApp对应 Backstage 的两代前端装配方式本文的backstage/app-defaults面向基于AppOptionsplugins/apis/components/icons/themes的装配模型直接调用 createSpecializedAppbackstage/frontend-defaultscreateApp.tsx面向 feature/module 装配模型其 API 报告 中createApp返回对象形态、选项结构featuresadvanced均与前者不同且 CHANGELOG 显示它经历过allowUnknownExtensionConfig移除、createPublicSignInApp迁移等 breaking 变更。如果你在维护一个使用backstage/app-defaults的既有应用请以其 API 报告为准如果是新前端体系features/modules则应参考frontend-defaults一侧的文档两者不要混用。小结如何以 report.api.md 为锚点做定制回到 report.api.md 这份契约文件本身它给出的信息量虽小但足够完整只传你需要的除plugins、apis等业务选项外icons/themes/components全部有默认值记住唯一的全量替换陷阱themes一旦传入默认 light/dark 主题即刻失效必须自行配齐所有变体默认 API 基座不可覆盖defaultApis注入的发现、fetch、存储、告警、各 Provider 认证、身份权限等工厂构成应用底层扩展方式是通过apis追加新工厂而非替换这些基座定制出错先看兜底组件启动失败看BootErrorPage的step提示插件崩溃看ErrorBoundaryFallback的 Retry 面板它们都在 defaults/components.tsx 中可查可读。【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstage创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考