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');
},
});