diff --git a/.github/vale/Vocab/Backstage/accept.txt b/.github/vale/Vocab/Backstage/accept.txt index d557434d78..dc0b74b98c 100644 --- a/.github/vale/Vocab/Backstage/accept.txt +++ b/.github/vale/Vocab/Backstage/accept.txt @@ -312,6 +312,8 @@ rebase rebasing Recharts Redash +renderer +renderers replicasets repo Repo @@ -463,4 +465,4 @@ zod Zolotusky zoomable zsh -scrollable \ No newline at end of file +scrollable diff --git a/docs/frontend-system/architecture/05-extension-overrides.md b/docs/frontend-system/architecture/05-extension-overrides.md index e722145552..6a1037341e 100644 --- a/docs/frontend-system/architecture/05-extension-overrides.md +++ b/docs/frontend-system/architecture/05-extension-overrides.md @@ -10,38 +10,158 @@ description: Frontend extension overrides ## Introduction - +In order to override an app extension, you must create a new extension and add it to the list of overridden features. The steps are: create your extension overrides and use them in Backstage. -## Creating a Extension Override +### Example - +Now we are able to use the overrides in a Backstage app: -## Overriding Existing Extensions +```tsx title="packages/app/src/App.tsx" +import { createApp } from '@backstage/frontend-app-api'; +import themeOverrides from './themes'; - +## Override Plugin Extensions + +To override an extension that is provided by a plugin, you need to provide a new extension that has the same ID as the existing extension. That is, all kind, namespace, and name options must match the extension you want to replace. This means that you typically need to provide an explicit `namespace` when overriding extensions from a plugin. + +:::info +We recommend that plugin developers share the extension IDs in their plugin documentation, but usually you can infer the ID by following the [naming patterns](./08-naming-patterns.md) documentation. +::: + +### Example + +Imagine you have a plugin with the ID `'search'`, and the plugin provides a page extension that you want to fully override with your own custom component. To do so, you need to create your page extension with an explicit `namespace` option that matches that of the plugin that you want to override, in this case `'search'`. If the existing extension also has an explicit `name` you'd need to set the `name` of your override extension to the same value as well. + +```tsx title="packages/app/src/search.ts" +import { createPageExtension } from '@backstage/frontend-plugin-api'; + +// Creating a custom search page extension +const customSearchPage = createPageExtension({ + // highlight-next-line + namespace: 'search', + // Omitting name since it is the index plugin page + defaultPath: '/search', + loader: () => import('./SearchPage').then(m => m.), +}); + +export createExtensionOverrides({ + extensions: [customSearchPage] +}); +``` + +Don't forget to configure your overrides in the `createApp` function: + +```tsx title="packages/app/src/App.tsx" +import { createApp } from '@backstage/frontend-app-api'; +import searchOverrides from './search'; + +const app = createApp({ + // highlight-next-line + features: [searchOverrides], +}); + +export default app.createRoot(); +``` + +Now let's talk about the last override case, orphan extensions. + +## Create Standalone Extensions + +Sometimes you just need to quickly create a new extension and not overwrite an app extension or plugin. You can also use overrides to create extensions, but remember that if you want to make this extension available for installation by other users, we recommend providing it via a plugin in a separate package. + +### Example + +Imagine you want to create a page that is currently only used by your application, like an Institutional page, for example. You can use overrides to extend the Backstage app to render it. To do so, simply create a page extension and pass it to the app as an override: + +```tsx title="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: [ + // highlight-start + createPageExtension({ + name: 'institutional', + defaultPath: '/institutional', + loader: () => + import('./institutional').then(m => ), + }), + // highlight-end + ], + }), + ], +}); + +export default app.createRoot(); +``` + +Note that we are omitting `namespace` when creating the page extension. When we omit `namespace`, we are telling the system the new extension is standalone and not an application or plugin extension!