refactor: apply more review suggestions
Signed-off-by: Camila Belo <camilaibs@gmail.com>
This commit is contained in:
@@ -14,19 +14,19 @@ A Backstage App is a monorepo setup that includes everything you need to run Bac
|
||||
|
||||
## Creating a new app
|
||||
|
||||
To create a Backstage app, you will need to have Node.js Active LTS Release installed.
|
||||
To create a new Backstage app we recommend using the `@backstage/create-app` command line, and the easiest way to run this package is with `npx`:
|
||||
|
||||
The easiest way to run the create app package is with `npx`:
|
||||
:::note
|
||||
The create-app CLI requires Node.js Active LTS Release.
|
||||
:::
|
||||
|
||||
```sh
|
||||
# The command bellow creates a Backstage App inside the current folder.
|
||||
# The name of the app-folder is the name that was provided when prompted.
|
||||
npx @backstage/create-app@latest
|
||||
```
|
||||
|
||||
This will create a new Backstage App inside the current folder. The name of the app-folder is the name that was provided when prompted.
|
||||
|
||||
:::note
|
||||
The created app will currently be templated for use in the legacy frontend system, and you will need to replace the existing app wiring code.
|
||||
:::
|
||||
The created-app is currently templated for legacy frontend system applications, so the app wiring code it creates needs to be migrated, see [the app instance](#the-app-instance) section for an example.
|
||||
|
||||
## The app instance
|
||||
|
||||
@@ -37,6 +37,7 @@ This is how to create a minimal app:
|
||||
```tsx title="in src/index.ts"
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import { createApp } from '@backstage/frontend-app-api';
|
||||
import catalogPlugin from '@backstage/plugin-catalog/alpha';
|
||||
|
||||
// Create your app instance
|
||||
const app = createApp({
|
||||
@@ -49,31 +50,41 @@ const root = app.createRoot();
|
||||
|
||||
// Just like any other React we need a root element. No server side rendering is used.
|
||||
const rootEl = document.getElementById('root')!;
|
||||
|
||||
ReactDOM.createRoot(rootEl).render(root);
|
||||
```
|
||||
|
||||
Note that the `createRoot` exports an element instead of a component and it no longer accepts a custom root element as parameter, so this is the reason you can pass the returned element directly to React `createRoot`. See [customizing your root app element](#app-root) for more details on how to do it with extensions.
|
||||
Note that `createRoot` returns the root element that is rendered by React. The above example is installing a catalog plugin and using default settings for the app, as no options other than the `features` array are passed to the `createApp` function.
|
||||
|
||||
Visit the [built-in extensions](#customize-or-override-built-in-extensions) section to see what is installed by default in a Backstage application.
|
||||
|
||||
## Configure your app
|
||||
|
||||
### Enable features discovering
|
||||
### Bind external routes
|
||||
|
||||
This is how you enable the experimental feature discovering when building your app with the `@backstage/cli`, check out [here](https://backstage.io/docs/frontend-system/architecture/app#feature-discovery) for more details.
|
||||
Linking routes from different plugins requires this configuration. You can do this either through a configuration file or by coding, visit [this](https://backstage.io/docs/frontend-system/architecture/routes#binding-external-route-references) page for instructions.
|
||||
|
||||
### Enable feature discovery
|
||||
|
||||
Use this setting to enable experimental feature discovery when building your app with `@backstage/cli`. With this configuration your application tries to discover and install package extensions automatically, check [here](../architecture/02-app.md#feature-discovery) for more details.
|
||||
|
||||
:::warning
|
||||
Remember that package extensions that are not auto-discovered must be manually added to the application when creating an app. See [features](#install-features-manually) for more details.
|
||||
:::
|
||||
|
||||
### Bind external routes
|
||||
### Configure extensions individually
|
||||
|
||||
This is the configuration you do when you want to associate an external plugin route ref with a regular one. There are two ways of doing it: via configuration file or through code. Access [this](https://backstage.io/docs/frontend-system/architecture/routes#binding-external-route-references) page for learning both ways.
|
||||
It is possible to enable, disable and configure extensions individually in the `app-config.yaml` config file. To get familiar with what is available for app extensions personalization, go to the [built-in extensions](./02-built-in-extensions.md) documentation. For plugin customizations, we recommend that you read the instructions in each plugin's README file.
|
||||
|
||||
## Customize individual extensions
|
||||
### Customize or override built-in extensions
|
||||
|
||||
It possible to enable, disable, order and configure extensions individually in the `app-config.yaml` config file. To get familiar with what is available for app extensions, go to the [built-in extensions](./02-built-in-extensions.md) documentation. For plugins customizations, we recommend you checking their read files instructions.
|
||||
Previously you would customize the application route, components, apis, sidebar, etc. through the code in `App.tsx`. Now we want you to write less code and install more extensions to customize your Backstage instance. See [here](../building-plugins/03-extension-types.md) which types of extensions are available for you to customize your application.
|
||||
|
||||
## Install features manually
|
||||
## Use code to customize the app at a more granular level
|
||||
|
||||
A manual installation is required if your packages are not discovered automatically, either because you are not using `@backstage/cli` to build your application or because the features are defined in local modules in the app package. For manually install a feature you have to import your it and pass it to the `createApp` function:
|
||||
### Install features manually
|
||||
|
||||
A manual installation is required if your packages are not discovered automatically, either because you are not using `@backstage/cli` to build your application or because the features are defined in local modules in the app package. In order to manually install a feature, you must import it and pass it to the `createApp` function:
|
||||
|
||||
```tsx title="packages/app/src/App.tsx"
|
||||
import { createApp } from '@backstage/frontend-app-api';
|
||||
@@ -91,34 +102,47 @@ export default app.createRoot();
|
||||
You can also pass overrides to the features array, for more details, please read the [extension overrides](../architecture/05-extension-overrides.md) documentation.
|
||||
:::
|
||||
|
||||
If for some reason you need to perform asynchronous operations before passing features to the `createApp` function, you can use an async function as `features` option and this should return a features array promise:
|
||||
### Using an async features loader
|
||||
|
||||
In case you need to perform asynchronous operations before passing features to the `createApp` function, define a [feature loader](https://backstage.io/docs/reference/frontend-app-api.createappfeatureloader/) object and pass it to the `features` option:
|
||||
|
||||
```tsx title="packages/app/src/App.tsx"
|
||||
import { createApp } from '@backstage/frontend-app-api';
|
||||
|
||||
const app = createApp({
|
||||
// Lazy loading the plugin feature
|
||||
features: import('./plugins/MyPlugin').then(m => [m.default]),
|
||||
features: {
|
||||
getLoaderName: () => '<your-custom-features-loader-name>',
|
||||
// there is a reference to the config api in the options param
|
||||
load: async _options => {
|
||||
// returning a lazy loaded plugins and overrides array
|
||||
// could be util for module federation
|
||||
return import('./features').then(m => m.default);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export default app.createRoot();
|
||||
```
|
||||
|
||||
## Lazy load your configuration file
|
||||
### Lazy load your configuration file
|
||||
|
||||
In some cases we want to load our configuration from a backend server or we just want to override the default app configuration loader. If you want to do it, you can pass an async callback to the `createApp` function and it should return a promise of the config object:
|
||||
In some cases we want to load our configuration from a backend server and to do so, you can pass an callback to the `configLoader` option when calling the `createApp` function, the callback should return a promise of an object with the config object:
|
||||
|
||||
```tsx title="packages/app/src/App.tsx"
|
||||
import { createApp } from '@backstage/frontend-app-api';
|
||||
import { getConfigFromServer } from './utils';
|
||||
|
||||
// Example lazy loading the app configuration
|
||||
const app = createApp({
|
||||
// Lazy loading the plugin feature
|
||||
features: import('./plugins/MyPlugin').then(m => [m.default]),
|
||||
// Returns Promise<{ config: ConfigApi }>
|
||||
configLoader: async () => {
|
||||
// Calls an async utility method that fetches the config object from the server
|
||||
const config = await getConfigFromServer();
|
||||
// Feel free to manipulate the config object before returning it
|
||||
// A common example is conditionally modify the config based on the running enviroment
|
||||
return { config };
|
||||
},
|
||||
});
|
||||
|
||||
export default app.createRoot();
|
||||
```
|
||||
|
||||
## Customize or override built-in extensions
|
||||
|
||||
Previously you would customize the application route, components, apis, sidebar, etc. through the code in `App.tsx`. Now we want you to write less code and install more extensions to customize your Backstage instance. See [here](../building-plugins/03-extension-types.md) which types of extensions are available for you to customize your application.
|
||||
|
||||
@@ -38,13 +38,13 @@ This extension is the first extension attached to the extension tree. It is resp
|
||||
|
||||
#### Inputs
|
||||
|
||||
| Name | Description | Type | Optional | Default | Extension creator |
|
||||
| ------------ | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | -------- | ------------------------------------------------ | ---------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
|
||||
| root | The app root element. | [coreExtensionData.reactElement](https://backstage.io/docs/reference/frontend-plugin-api.coreextensiondata) | false | The [`App/Root`](#app-root) extension output. | No creator available, configure or override the [`App/Root`](#app-root) extension. |
|
||||
| apis | The app apis factories. | [createApiExtension.factoryDataRef](https://backstage.io/docs/reference/frontend-plugin-api.createapiextension.factorydataref) | false | See [default apis](#default-apis-extensions). | [createApiExtension](https://backstage.io/docs/reference/frontend-plugin-api.createapiextension) |
|
||||
| themes | The app themes list. | [createThemeExtension.themeDataRef](https://backstage.io/docs/reference/frontend-plugin-api.createthemeextension.themedataref) | false | See [default themes](#default-theme-extensions). | [createThemeExtension](https://backstage.io/docs/reference/frontend-plugin-api.createthemeextension) |
|
||||
| components | The app components list. | [createComponentExtension.componentDataRef](https://backstage.io/docs/reference/frontend-plugin-api.createcomponentextension.componentdataref) | - | false | See [default components](#defaults-components-extensions). | [createComponentExtension](https://backstage.io/docs/reference/frontend-plugin-api.createcomponentextension) |
|
||||
| translations | The app translations list. | [createTranslationExtension.translationDataRef](https://backstage.io/docs/reference/frontend-plugin-api.createtranslationextension.translationdataref) | - | false | - | [createTranslationExtension](https://backstage.io/docs/reference/frontend-plugin-api.createtranslationextension) |
|
||||
| Name | Description | Type | Optional | Default | Extension creator |
|
||||
| ------------ | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | -------- | --------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
|
||||
| root | The app root element. | [coreExtensionData.reactElement](https://backstage.io/docs/reference/frontend-plugin-api.coreextensiondata) | false | The [`App/Root`](#app-root) extension output. | No creator available, configure or override the [`App/Root`](#app-root) extension. |
|
||||
| apis | The app apis factories. | [createApiExtension.factoryDataRef](https://backstage.io/docs/reference/frontend-plugin-api.createapiextension.factorydataref) | false | See [default apis](#default-apis-extensions). | [createApiExtension](https://backstage.io/docs/reference/frontend-plugin-api.createapiextension) |
|
||||
| themes | The app themes list. | [createThemeExtension.themeDataRef](https://backstage.io/docs/reference/frontend-plugin-api.createthemeextension.themedataref) | false | See [default themes](#default-theme-extensions). | [createThemeExtension](https://backstage.io/docs/reference/frontend-plugin-api.createthemeextension) |
|
||||
| components | The app components list. | [createComponentExtension.componentDataRef](https://backstage.io/docs/reference/frontend-plugin-api.createcomponentextension.componentdataref) | false | See [default components](#default-components-extensions). | [createComponentExtension](https://backstage.io/docs/reference/frontend-plugin-api.createcomponentextension) |
|
||||
| translations | The app translations list. | [createTranslationExtension.translationDataRef](https://backstage.io/docs/reference/frontend-plugin-api.createtranslationextension.translationdataref) | false | - | [createTranslationExtension](https://backstage.io/docs/reference/frontend-plugin-api.createtranslationextension) |
|
||||
|
||||
#### Default theme extensions
|
||||
|
||||
@@ -59,11 +59,11 @@ Extensions that provides default theme inputs for the `App` extension.
|
||||
|
||||
Extensions that provides default components inputs for the `App` extension.
|
||||
|
||||
| kind | namespace | name | id |
|
||||
| :--------: | :-------: | :-----------------------------------: | :--------------------: |
|
||||
| components | app | core.components.progress | `components:app/light` |
|
||||
| components | app | core.components.notFoundErrorPage | `components:app/dark` |
|
||||
| components | app | core.components.errorBoundaryFallback | `components:app/dark` |
|
||||
| kind | namespace | name | id |
|
||||
| :--------: | :-------: | :-----------------------------------: | :----------------------------------------------------: |
|
||||
| components | app | core.components.progress | `components:app/core.components.progress` |
|
||||
| components | app | core.components.notFoundErrorPage | `components:app/core.components.notFoundErrorPage` |
|
||||
| components | app | core.components.errorBoundaryFallback | `components:app/core.components.errorBoundaryFallback` |
|
||||
|
||||
#### Default apis extensions
|
||||
|
||||
@@ -91,7 +91,7 @@ Extensions that provides default apis inputs for the `App` extension.
|
||||
|
||||
### App root
|
||||
|
||||
This is the extension that creates the app root element, so it renders root level components such as app router, layout.
|
||||
This is the extension that creates the app root element, so it renders root level components such as app router and layout.
|
||||
|
||||
#### Inputs
|
||||
|
||||
@@ -115,10 +115,10 @@ An app root element extension that displays messages posted via the [`AlertApi`]
|
||||
|
||||
###### Configurations
|
||||
|
||||
| Key | Type | Default value | Description |
|
||||
| -------------------- | -------------------------------------------------------------------------- | ----------------------------------------- | ---------------------------------------------------------------- |
|
||||
| `transientTimeoutMs` | number | 5000 | Time in milliseconds to wait before displaying messages |
|
||||
| `anchorOrigin` | { vertical: 'top' \| 'bottom', horizontal: 'left' \| 'center' \| 'right' } | { vertical: 'top', horizontal: 'center' } | Position on the screen where the message alert will be displayed |
|
||||
| Key | Type | Default value | Description |
|
||||
| -------------------- | -------------------------------------------------------------------------- | ----------------------------------------- | ----------------------------------------------------------------- |
|
||||
| `transientTimeoutMs` | number | 5000 | Time in milliseconds to wait before displaying messages. |
|
||||
| `anchorOrigin` | { vertical: 'top' \| 'bottom', horizontal: 'left' \| 'center' \| 'right' } | { vertical: 'top', horizontal: 'center' } | Position on the screen where the message alert will be displayed. |
|
||||
|
||||
###### Override or disable the extension
|
||||
|
||||
@@ -178,10 +178,10 @@ Renders a route element for each route received as input and a `NotFoundErrorPag
|
||||
|
||||
Be careful when overriding this extension, as to do so correctly you must consider these implementation requirements:
|
||||
|
||||
- The routing system is managed by more than one extension, and they all use 'react-router' behind the scenes and there are also some utilities that are based on the same library like `useRouteRefParams`. Therefore, you cannot use a different library without causing side effects in these other extensions and helper utilities;
|
||||
- Don't remove configs or inputs, just extend these things yourself with optional new options, otherwise it will cause breaking changes for extensions like `createPageExtension` that depend on this type of entry, for example;
|
||||
- Remember to user the route refs for getting paths dynamically, otherwise if an adopter modifies a path through configuration, the route is not going to point to the configured path.
|
||||
- Adopter expects to be able to customize the `NotFoundErrorPage` component via Components API, you should render this component for routes not configured.
|
||||
- The routing system is managed by more than one extension, and they all use `react-router` behind the scenes. There are also some utilities that are based on the same `routing` library like `useRouteRefParams`. Therefore, you cannot use a different library without causing side effects in these other extensions and helper utilities;
|
||||
- Don't remove configs or inputs, just extend these things yourself with optional new options, otherwise it will cause breaking changes for extensions like `createPageExtension` that depend on this type of inputs;
|
||||
- Remember to user the route refs for getting paths dynamically, otherwise if an adopter modifies a path through configuration, the route is not going to point to the configured path;
|
||||
- Adopters expect to be able to customize the `NotFoundErrorPage` component via Components API, you should render this component for routes not configured.
|
||||
|
||||
#### Inputs
|
||||
|
||||
|
||||
Reference in New Issue
Block a user