Skip to main content

前台扩展重写

**注意:新的前台系统处于alpha阶段,只有少数插件支持。

简介

扩展覆盖是前台系统的一个构件,允许您在应用程序的任何位置以编程方式覆盖应用程序或插件扩展。 由于整个应用程序主要是由扩展自下而上构建而成,因此这是一个强大的功能。 例如,您可以使用它来提供自己的应用程序根布局,用自定义 API 代替实用程序编程接口的实现,覆盖目录页面的渲染方式,等等。

一般来说,大多数功能都应具有良好的定制化水平,这样用户就不必利用扩展重载来实现共同目标。 写得好的功能通常具有以下特点配置例如搜索插件,它允许你提供结果呈现器作为输入,而不是为了调整结果显示方式而全盘替换结果页面。 采用者应尽可能利用这些功能,只有在需要完全替换扩展时才使用扩展重载。 请查阅相应的扩展文档以获得指导。

覆盖应用程序扩展

要覆盖应用程序扩展,必须创建一个新扩展,并将其添加到覆盖功能列表中。 步骤是:创建扩展覆盖功能,并在Backstage使用。

示例

在下面的示例中,我们创建了一个文件,为应用程序的lightdark主题

packages/app/src/themes.ts
import {
createThemeExtension,
createExtensionOverrides
} from '@backstage/frontend-plugin-api';
import { apertureThemes } from './themes';
import { ApertureLightIcon, ApertureDarkIcon } from './icons';

// Creating a light theme extension
const apertureLightTheme = createThemeExtension({
namespace: 'app',
name: 'light',
title: 'Aperture Light Theme',
variant: 'light',
icon: <ApertureLightIcon />,
Provider: ({ children }) => (
<UnifiedThemeProvider theme={apertureThemes.light} children={children} />
),
});

// Creating a dark theme extension
const apertureDarkTheme = createThemeExtension({
namespace: 'app',
name: 'dark',
title: 'Aperture Dark Theme',
variant: 'dark',
icon: <ApertureDarkIcon />,
Provider: ({ children }) => (
<UnifiedThemeProvider theme={apertureThemes.dark} children={children} />
),
});

// Creating an extension overrides preset
export createExtensionOverrides({
extensions: [apertureLightTheme, apertureDarkTheme]
});

请注意,我们声明namespace作为'app'在创建主题时,系统会知道我们在覆盖应用程序扩展。 此外,要特别覆盖lightdark主题扩展,我们将name选项lightdark因此,要覆盖应用程序主题扩展,我们要确保扩展的namespacename与默认应用主题扩展定义相匹配。

现在,我们可以在 Backstage 应用程序中使用覆盖:

packages/app/src/App.tsx
import { createApp } from '@backstage/frontend-app-api';
import themeOverrides from './themes';

const app = createApp({
features: [themeOverrides],
});

export default app.createRoot().

如果您要更改的插件是公司内部的,或者您只是想替换应用程序的一个核心扩展,您可以决定将覆盖代码直接存储在应用程序软件包中,或者将其提取到一个单独的软件包中。

请注意,在大型项目中,将重写拆分成不同的包仍然是个好主意。 但如何将扩展分组为扩展重写,则由您自己决定。

覆盖插件扩展

要覆盖插件提供的扩展,您需要提供一个与现有扩展具有相同 ID 的新扩展。 也就是说,所有种类、命名空间和名称选项都必须与您要替换的扩展相匹配。namespace当覆盖插件的扩展时。

info
我们建议插件开发人员在其插件文档中共享扩展 ID,但通常您可以根据命名模式文件

示例

想象一下,您有一个 ID 为'search'要做到这一点,您需要在创建页面扩展时使用明确的namespace选项与要覆盖的插件的选项相匹配,在本例中为'search'如果现有扩展名也有明确的name您需要设置name的值也是相同的。

packages/app/src/search.ts
import { createPageExtension } from '@backstage/frontend-plugin-api';

// Creating a custom search page extension
const customSearchPage = createPageExtension({
namespace: 'search',
// Omitting name since it is the index plugin page
defaultPath: '/search',
loader: () => import('./SearchPage').then(m => m.<SearchPage/>),
});

export createExtensionOverrides({
extensions: [customSearchPage]
});

不要忘记在createApp功能:

packages/app/src/App.tsx
import { createApp } from '@backstage/frontend-app-api';
import searchOverrides from './search';

const app = createApp({
features: [searchOverrides],
});

export default app.createRoot();

现在我们来谈谈最后一种覆盖情况,即孤儿扩展。

创建独立扩展

有时,您只需快速创建一个新扩展,而无需覆盖应用程序扩展或插件。 您也可以使用覆盖来创建扩展,但请记住,如果您想让其他用户也能安装该扩展,我们建议您通过单独软件包中的插件来提供。

示例

想象一下,你想创建一个当前只有你的应用程序才能使用的页面,比如机构页面。 你可以使用覆盖来扩展 Backstage 应用程序以呈现它。 为此,只需创建一个页面扩展,并将其作为覆盖传递给应用程序即可:

packages/app/src/App.ts
import { createApp } from '@backstage/frontend-app-api';
import {
createPageExtension,
createExtensionOverrides,
} from '@backstage/frontend-plugin-api';

const app = createApp({
features: [
createExtensionOverrides({
extensions: [
createPageExtension({
name: 'institutional',
defaultPath: '/institutional',
loader: () =>
import('./institutional').then(m => <m.InstitutionalPage />),
}),
],
}),
],
});

export default app.createRoot();

请注意,我们省略了namespace当我们省略namespace我们要告诉系统,新扩展是独立的,而不是应用程序或插件扩展!