diff --git a/docs/architecture.drawio b/docs/architecture.drawio new file mode 100644 index 0000000000000..dbe2a5f6fa534 --- /dev/null +++ b/docs/architecture.drawio @@ -0,0 +1 @@ +7VpLc6M4EP41PiaFBLbh6LxmLlubSqZ2Z+amBQVUBYgScmzPrx9hJIMQGJzEhtTOxUaNnp++bnU3mtm3yfYLQ1n0Fw1wPINWsJ3ZdzMIAfQ88VdIdqXEs2EpCBkJZKVK8Ex+YSm0pHRNApxrFTmlMSeZLvRpmmKfazLEGN3o1V5orI+aoRAbgmcfxab0XxLwqJS6cFnJv2ISRmpksJALTpCqLFeSRyigm5rIvp/Zt4xSXj4l21scF+ApXMp2Dx1vDxNjOOVDGvwk7Nv6n4erTfLNgzcr9/HvH5sru+zlFcVrueBVlsn58p0CId+QJEapKN3I+phxvO2cCDgsT/AC0wRzthNVZANXAiIZARayvKnwPdSJathCRwqR3NPw0HW1bPEgV34CCs4gFBhdpwEu+rEEEJuIcPycIb94uxHkF7KIJ2LcOzAUp+4t6QQP6uA5JnZt0J0NOduEzsAtFMBlnXhIxUX/qerWqXxyFv2EsuFFCQVNvbrfcpzmhKb5aMRyjsPo6CgCZ1xqKSbVMHyia46f8MtEEQSuDqEzNoLgsyPYRkLQpsrnw9CA8IHRVKhyIKSP8Tok6buPy7cgBVtsnHVRG2eSqwOOC1ELfqZz05ucZh6HDyygjh8cFz8wPdPWB+C0COga+I3voPRosM5AAMamoNUN4UQRbPjJYGQOgoWBoAGcOGhXRRgvSn6M8pz4OlYByqM9rhVwODBC+iGwiWHpmvl4wJZzxEJ8rMOOgKUG9LwFaCVjOEacvOqLaENfjvBIiVjeYZu9xjZbjf0rlykbwVrCQPWjGtqNhuWyjYb7vT+s8h10WL6fDmKf2e67VLN94UdRuIZzVb7b1t/e7VRpS/h31Yl4rjcTxapVUVCNzs63oXQblW9LnW/eqXRTNs7R+3EvzD7zRJy6R9F/IF42VgKmV1uciCxF8dSh7D8ZLxx2ms7F6baw1aQdt2iFLXuWQ1DGIxpSsXv3lbTTwvYZ2MnYSm9MW3lg1k63ne81lmA+zFoKwqBdrVpWVMiPzLcxzsI6bVq2Vl88lBP4UMsNB+Sga2px+A5j1d3HooBiEqaFNglGYiYEhaUhPopX8kVCgmCvBKKPrOg52YbFZ6/r8ksTLP+LbhXr9x/CgH0t8L1JKfcjKX+JSfb1zFbtqunvt+SMnBaqw7MZtXnr+TDpoLORj3THTumaIdPkIWy4Ke7IcTs0w4xVRibrmzSV2DWV+LLwfb7MEVhMTYvbHeVpYzgxNbZND1mo8QPyOZW9TxDDiemybWbRDeSGRhkqlBgSZczOHAsobvQGA+VZMFqizr2eL4ED3fJ3sdTY8eY8SiMfA5r0OXMiRV3w+rCs7ttj0jdm/ZafI+tnW7MRydtkWTNqGErXnuzhR8WxDTdq2RPHNr0u7wJxrG1eGjIU508cW23GaHEs+N9uVNellJ1uWj5+Y2bFtRt1U7ZUuOq+sX3/Gw== \ No newline at end of file diff --git a/docs/plugins/plugin-development.md b/docs/plugins/plugin-development.md index 109f6ed6ba90b..bfeed58c8fd2f 100644 --- a/docs/plugins/plugin-development.md +++ b/docs/plugins/plugin-development.md @@ -23,35 +23,60 @@ browser APIs or by depending on external modules to do the work. ### Routing -Each plugin is responsible for registering its components to corresponding -routes in the app. +Each plugin can export routable extensions, which are then imported into the app +and mounted at a path. -The app will call the `createPlugin` method on each plugin, passing in a -`router` object with a set of methods on it. +First you will need a `RouteRef` instance to serve as the mount point of your +extensions. This can be used within your own plugin to create a link to the +extension page using `useRouteRef`, as well as for other plugins to link to your +extension. -```jsx -import { createPlugin, createRouteRef } from '@backstage/core'; -import ExampleComponent from './components/ExampleComponent'; +It is best to place these in a separate top-level `src/routes.ts` file, in order +to avoid import cycles, for example like this: + +```tsx +/* src/routes.ts */ +import { createRouteRef } from '@backstage/core'; +// Note: This route ref is for internal use only, don't export it from the plugin export const rootRouteRef = createRouteRef({ - path: '/new-plugin', - title: 'New plugin', + title: 'Example Page', }); +``` + +Now that we have a `RouteRef`, we import it into `src/plugin.ts`, create our +plugin instance with `createPlugin`, as well as create and wrap our routable +extension using `createRoutableExtension` from `@backstage/core`: -export const plugin = createPlugin({ - id: 'new-plugin', - register({ router }) { - router.addRoute(rootRouteRef, ExampleComponent); +```tsx +/* src/plugin.ts */ +import { createPlugin, createRouteRef } from '@backstage/core'; +import ExampleComponent from './components/ExampleComponent'; + +// Create a plugin instance and export this from your plugin package +export const examplePlugin = createPlugin({ + id: 'example', + routes: { + root: rootRouteRef, // This is where the route ref should be exported for usage in the app }, }); + +// This creates a routable extension, which are typically full pages of content. +// Each extension should also be exported from your plugin package. +export const ExamplePage = examplePlugin.provide( + createRoutableExtension({ + // The component needs to be lazy-loaded. It's what will actually be rendered in the end. + component: () => + import('./components/ExampleComponent').then(m => m.ExampleComponent), + // This binds the extension to this route ref, which allows for routing within and across plugin extensions + mountPoint: rootRouteRef, + }), +); ``` -#### `router` API +This extension can then be imported and used in the app as follow, typically +placed within the top-level ``: -```typescript -addRoute( - target: RouteRef, - Component: ComponentType, - options?: RouteOptions, -): void; +```tsx +} /> ``` diff --git a/docs/plugins/structure-of-a-plugin.md b/docs/plugins/structure-of-a-plugin.md index 3f631a9a46383..2aacd02cf2504 100644 --- a/docs/plugins/structure-of-a-plugin.md +++ b/docs/plugins/structure-of-a-plugin.md @@ -28,6 +28,7 @@ new-plugin/ index.ts plugin.test.ts plugin.ts + routes.ts jest.config.js jest.setup.ts package.json @@ -56,26 +57,30 @@ package.json to declare the plugin dependencies, metadata and scripts. In the `src` folder we get to the interesting bits. Check out the `plugin.ts`: ```jsx -import { createPlugin, createRouteRef } from '@backstage/core'; -import ExampleComponent from './components/ExampleComponent'; +import { createPlugin, createRoutableExtension } from '@backstage/core'; -export const rootRouteRef = createRouteRef({ - path: '/new-plugin', - title: 'New plugin', -}); +import { rootRouteRef } from './routes'; -export const plugin = createPlugin({ - id: 'new-plugin', - register({ router }) { - router.addRoute(rootRouteRef, ExampleComponent); +export const examplePlugin = createPlugin({ + id: 'example', + routes: { + root: rootRouteRef, }, }); + +export const ExamplePage = examplePlugin.provide( + createRoutableExtension({ + component: () => + import('./components/ExampleComponent').then(m => m.ExampleComponent), + mountPoint: rootRouteRef, + }), +); ``` -This is where the plugin is created and where it hooks into the app by declaring -what component should be shown on what URL. See reference docs for -[createPlugin](../reference/createPlugin.md) or -[router](../reference/createPlugin-router.md). +This is where the plugin is created and where it creates and exports extensions +that can be imported and used the app. See reference docs for +[createPlugin](../reference/createPlugin.md) or introduction to the new +[Composability System](./composability.md). ## Components @@ -91,12 +96,15 @@ You may tweak these components, rename them and/or replace them completely. ## Connecting the plugin to the Backstage app -There are two things needed for a Backstage app to start making use of a plugin. +There are three things needed for a Backstage app to start making use of a +plugin. 1. Add plugin as dependency in `app/package.json` 2. `import` plugin in `app/src/plugins.ts` +3. Import and use one or more plugin extensions, for example in + `app/src/App.tsx`. -Luckily these two steps happen automatically when you create a plugin with the +Luckily these three steps happen automatically when you create a plugin with the Backstage CLI. ## Talking to the outside world diff --git a/docs/reference/createPlugin-router.md b/docs/reference/createPlugin-router.md deleted file mode 100644 index 0ef5bdbd0fd06..0000000000000 --- a/docs/reference/createPlugin-router.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -id: createPlugin-router -title: createPlugin - router -description: Documentation on createPlugin - router ---- - -The router that is passed to the `register` function makes it possible for -plugins to hook into routing of the Backstage app and provide the end users with -new views to navigate to. This is done by utilising the following methods on the -`router`: - -```typescript -addRoute( - target: RouteRef, - Component: ComponentType, - options?: RouteOptions, -): void; -``` - -## RouteRef - -`addRoute` method is using mutable RouteRefs, which can be created as following: - -```ts -import { createRouteRef } from '@backstage/core'; - -const myPluginRouteRef = createRouteRef({ - path: '/my-plugin', - title: 'My Plugin', -}); -``` diff --git a/docs/reference/createPlugin.md b/docs/reference/createPlugin.md index 4a58a5ecdc3df..e3df66fa12d97 100644 --- a/docs/reference/createPlugin.md +++ b/docs/reference/createPlugin.md @@ -17,32 +17,24 @@ type PluginConfig = { }; type PluginHooks = { - router: RouterHooks; + featureFlags: FeatureFlagsHooks; }; ``` -- [Read more about the router here](createPlugin-router.md) - [Read more about feature flags here](createPlugin-feature-flags.md) ## Example Uses ### Creating a basic plugin -Showcasing adding a route and a feature flag. +Showcasing adding a feature flag. ```jsx -import { createPlugin, createRouteRef } from '@backstage/core'; -import ExampleComponent from './components/ExampleComponent'; - -export const rootRouteRef = createRouteRef({ - path: '/new-plugin', - title: 'New Plugin', -}); +import { createPlugin } from '@backstage/core'; export default createPlugin({ id: 'new-plugin', register({ router, featureFlags }) { - router.addRoute(rootRouteRef, ExampleComponent); featureFlags.register('enable-example-component'); }, });