diff --git a/docs/frontend-system/architecture/05-extension-overrides.md b/docs/frontend-system/architecture/05-extension-overrides.md index 6317783347..17daef6b6c 100644 --- a/docs/frontend-system/architecture/05-extension-overrides.md +++ b/docs/frontend-system/architecture/05-extension-overrides.md @@ -14,38 +14,63 @@ An extension override is a building block of the Frontend System that allows you Note that in general, most features should have a good level of customizability built into themselves, so that users do not have to leverage extension overrides to achieve common goals. A well written feature often has app-config settings, or uses extension inputs for extensibility where applicable. An example of this is the search plugin which allows you to provide result renderers as inputs rather than replacing the result page wholesale just to tweak how results are shown. Adopters should be taken advantage of those when possible, and only use extension overrides when it's necessary to entirely replace the extension. Check the respective extension documentation if available for guidance. -## Creating an Extension Override +## Overriding App Extensions -The following steps should be followed to override extensions: +If you want to override an app extension, you will need to create a new extension to replace the existing one and add it to the list of overridden features. The steps are: + +1. Create your extension overrides + +In this example below, we are going to create custom extensions for the app light and dark themes: ```tsx -// plugins/aperture-overrides/src/overrides.ts +// packages/app/src/themes.ts import { - createThemeApi, + createThemeExtension, createExtensionOverrides } from '@backstage/frontend-plugin-api'; +import { apertureThemes } from './themes'; +import { ApertureLightIcon, ApertureDarkIcon } from './icons'; // Creating a light theme extension; -const apertureLightTheme = createThemeApi({ … }); +const apertureLightTheme = createThemeExtension({ + namespace: 'app', + name: 'light', + title: 'Aperture Light Theme', + variant: 'light', + icon: , + Provider: ({ children }) => ( + + ), +}); // Creating a dark theme extension; -const apertureDarkTheme = createThemeApi({ … }); +const apertureDarkTheme = createThemeExtension({ + namespace: 'app', + name: 'dark', + title: 'Aperture Dark Theme', + variant: 'dark', + icon: , + Provider: ({ children }) => ( + + ), +}); // Creating an extension overrides preset export createExtensionOverrides({ extensions: [apertureLightTheme, apertureDarkTheme] }); - -// plugins/aperture-overrides/src/index.ts -export { default } from './overrides'; ``` -For this example, we are creating overrides for the light and dark theme extensions and exporting the overrides from the plugin index file. Now we are able to use the overrides in a Backstage app: +We exported the overrides for the light and dark app theme extensions from a separate file in the code snippet above. To override the default app's light and dark theme extensions, we must ensure that the extension namespace and name match the ones in the default app themes extension definitions. + +2. Use the overrides in your Backstage App + +Now we are able to use the overrides in a Backstage app: ```tsx // packages/app/src/App.tsx import { createApp } from '@backstage/frontend-app-api'; -import apertureOverrides from ‘@backstage/plugin-aperture-overrides’ +import apertureOverrides from '@backstage/plugin-aperture-overrides' const app = createApp({ features: [ apertureOverrides ], @@ -54,43 +79,13 @@ const app = createApp({ export default app.createRoot(). ``` -If the plugin you want to change is internal to your company or you just want to replace one of the application's core extensions, you can decide to create replacements directly in the application for local replacements. See an example below: - -```tsx -// packages/app/src/themes.ts -import { createExtensionOverrides } from from '@backstage/frontend-plugin-api'; - -// Creating the light theme extension; -export const apertureLightTheme = createThemeApi({ … }); - -// Creating the light theme extension; -const apertureDarkTheme = createThemeApi({ … }); - -// Exporting your custom extensions -export default [apertureLightTheme, apertureDarkTheme]; - -// packages/app/src/App.tsx -import { createApp } from '@backstage/frontend-app-api'; -import themes from ‘./themes’ - -const app = createApp({ - features: [ - createExtensionOverrides({ - extensions: [ - ...themes, - ], - }), - ], -}); - -export default app.createRoot(); -``` +If the plugin you want to change is internal to your company or you just want to replace one of the application's core extensions, you can decide to store the overrides code directly in the app package or extract them to a separate package. Note that it can still be a good idea to split your overrides out into separate packages in large projects. But it's up to you to decide how to group the extensions into extension overrides. -## Overriding Existing Extensions +## Overriding Plugin Extensions -To override an existing extension (which is already provided by a plugin), you need to provide an extension that has the same ID as the existing extension. That is, all kind, namespaces, and name 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. +To override an extension that is provided by a plugin, you need to provide an 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. 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. @@ -98,9 +93,9 @@ Imagine you have a plugin with the ID `'search'`, and the plugin provides a page // packages/app/src/search.ts const customSearchPage = createPageExtension({ namespace: 'search', - // Omitting name since it is the root plugin page - defaultPath: 'search' - loader: async () =>
My custom search page + // Omitting name since it is the index plugin page + defaultPath: 'search', + loader: () => Promise.resolve(
My custom search page
), }); ```