From 55f994321b556b340c7f3c828e5ee3d8cbff6845 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 14 Aug 2024 21:22:16 +0200 Subject: [PATCH 1/4] docs/frontend-system: add initial core migration docs Signed-off-by: Patrik Oldsberg --- .../architecture/60-migrations.md | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 docs/frontend-system/architecture/60-migrations.md diff --git a/docs/frontend-system/architecture/60-migrations.md b/docs/frontend-system/architecture/60-migrations.md new file mode 100644 index 0000000000..6ba3c73f0e --- /dev/null +++ b/docs/frontend-system/architecture/60-migrations.md @@ -0,0 +1,74 @@ +--- +id: migrations +title: Frontend System Migrations +sidebar_label: Migrations +# prettier-ignore +description: Migration documentation for different versions of the frontend system core APIs. +--- + +> **NOTE: The new frontend system is in alpha and is only supported by a small number of plugins.** + +## Introduction + +This section provides migration guides for different versions of the frontend system core APIs. Each guide will provide a summary of the changes that have been made for a particular Backstage release, and how to update your usage of the core APIs. + +This guide is intended for app and plugin authors who have already migrated their code to the new frontend system, and are looking to keep it up to date with the latest changes. These guides do not cover trivial migrations that can be explained in a deprecation message, such as a renamed export. + +## 1.30 + +### Reworked extension inputs and outputs + +In previous versions of the frontend system you would define extension inputs and outputs as an "data map" where each named property corresponded to a piece of data that could be accessed via the same name in the extension factory. In order to better support extension overrides and blueprints, as well as reduce the risk of confusion, these data maps have been replaced by an array of data references. + +For example, an extension previously declared like this: + +```tsx +createExtension({ + name: 'example', + attachTo: { id: 'some-extension', input: 'content' }, + inputs: { + header: createExtensionInput( + { element: coreExtensionData.reactElement }, + { + optional: true, + singleton: true, + }, + ), + }, + output: { element: coreExtensionData.reactElement }, + factory({ inputs }) { + return { + element: , + }; + }, +}); +``` + +Would now look like this: + +```tsx +createExtension({ + name: 'example', + attachTo: { id: 'some-extension', input: 'content' }, + inputs: { + header: createExtensionInput([coreExtensionData.reactElement], { + optional: true, + singleton: true, + }), + }, + output: [coreExtensionData.reactElement], + factory({ inputs }) { + return [ + coreExtensionData.reactElement( + , + ), + ]; + }, +}); +``` + +Note the changes to the `inputs` and `output` declarations, as well as how these are used in the factory. Both the `inputs` and `output` now declare their expected data using an array, without names tied to each piece of data. The `get` method on the input object is used to access the input data, and accept a data reference matching the data that was declared for that input. + +The biggest change in practice is how the extension factories output their data. Instead of returning an object with the data values, you instead use each extension data reference to encapsulate a value and return a collection of these encapsulated values from the factory. From 232eea92e6c1160664278bd099889139835ea39b Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 15 Aug 2024 10:18:22 +0200 Subject: [PATCH 2/4] docs/frontend-system: migration docs for extension creators Signed-off-by: Patrik Oldsberg --- docs/frontend-system/architecture/20-extensions.md | 4 ---- docs/frontend-system/architecture/60-migrations.md | 8 ++++++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/frontend-system/architecture/20-extensions.md b/docs/frontend-system/architecture/20-extensions.md index d1024d5e17..b43be74dbc 100644 --- a/docs/frontend-system/architecture/20-extensions.md +++ b/docs/frontend-system/architecture/20-extensions.md @@ -338,7 +338,3 @@ export function createSomeExtension< }); } ``` - -### Extension Creators (Deprecated) - -Previous iterations of the frontend system used an "extension creator" pattern, where `createExtension` was wrapped up in a function for creating specific extension kinds. This pattern was similar to [blueprints](./23-extension-blueprints.md), but much harder to implement and maintain. It has been deprecated in favor of the new blueprints API. For example, `createPageExtension` was the extension creator equivalent of `PageBlueprint`. diff --git a/docs/frontend-system/architecture/60-migrations.md b/docs/frontend-system/architecture/60-migrations.md index 6ba3c73f0e..1c1e61e4d7 100644 --- a/docs/frontend-system/architecture/60-migrations.md +++ b/docs/frontend-system/architecture/60-migrations.md @@ -72,3 +72,11 @@ createExtension({ Note the changes to the `inputs` and `output` declarations, as well as how these are used in the factory. Both the `inputs` and `output` now declare their expected data using an array, without names tied to each piece of data. The `get` method on the input object is used to access the input data, and accept a data reference matching the data that was declared for that input. The biggest change in practice is how the extension factories output their data. Instead of returning an object with the data values, you instead use each extension data reference to encapsulate a value and return a collection of these encapsulated values from the factory. + +### Blueprints instead of extension creators + +The "extension creator" pattern where `createExtension` was wrapped up in a function for creating specific kind of extensions has been replaced by [extension blueprints](./23-extension-blueprints.md). Extension creators were hard to implement and to maintain, with blueprints providing a much more consistent and powerful API surface for both plugin builders and integrators. For example, `createPageExtension` was the extension creator equivalent of `PageBlueprint`. + +Replace all existing usages of extension creators in your plugin or app with the corresponding blueprint. For a given extension creator `createExtension`, the blueprint equivalent is `Blueprint`. There might be slight differences in the API between the two, but most often you just need to move the kind-specific options of the extension creator to be passed as parameters to the blueprint. Note that if your extension declared any additional inputs or config you'll need to use the [`.makeWithOverrides`](./23-extension-blueprints.md#creating-an-extension-from-a-blueprint-with-overrides) method of the blueprint. + +If your plugin exports and extension creators, these should be migrated to blueprints instead. From d4076c7d08365037b235fa491f6ff9af0f9f8441 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 15 Aug 2024 10:24:19 +0200 Subject: [PATCH 3/4] docs/frontend-system: migration docs for extension tester Signed-off-by: Patrik Oldsberg --- docs/frontend-system/architecture/60-migrations.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/frontend-system/architecture/60-migrations.md b/docs/frontend-system/architecture/60-migrations.md index 1c1e61e4d7..0d6ef39209 100644 --- a/docs/frontend-system/architecture/60-migrations.md +++ b/docs/frontend-system/architecture/60-migrations.md @@ -80,3 +80,9 @@ The "extension creator" pattern where `createExtension` was wrapped up in a func Replace all existing usages of extension creators in your plugin or app with the corresponding blueprint. For a given extension creator `createExtension`, the blueprint equivalent is `Blueprint`. There might be slight differences in the API between the two, but most often you just need to move the kind-specific options of the extension creator to be passed as parameters to the blueprint. Note that if your extension declared any additional inputs or config you'll need to use the [`.makeWithOverrides`](./23-extension-blueprints.md#creating-an-extension-from-a-blueprint-with-overrides) method of the blueprint. If your plugin exports and extension creators, these should be migrated to blueprints instead. + +### Extension tester rework + +The `createExtensionTester` from the `@backstage/frontend-test-utils` package has been reworked to better support testing of extensions. The new API allows access to extension output directly using the new `.get(ref)` method, and also provides access to all tested extensions through the new `.query(id/extension)` method. + +The `.render()` method that used to render the test subject in a test app has been deprecated. The extension tester no longer constructs a full app tree, but instead only instantiates the tree for the extensions under test. If you want to test the rendering of an extension that outputs in an app, you can instead use the `renderInTestApp` utility in combination with the new `.reactElement()` method of the extension tester: `renderInTestApp(tester.reactElement())`. From 160c55181a62f76c8722d5886a5bc3ed8c89e45a Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 15 Aug 2024 10:27:11 +0200 Subject: [PATCH 4/4] docs/frontend-system: migration docs for extension data refs Signed-off-by: Patrik Oldsberg --- .../architecture/60-migrations.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/frontend-system/architecture/60-migrations.md b/docs/frontend-system/architecture/60-migrations.md index 0d6ef39209..a1ab0197f7 100644 --- a/docs/frontend-system/architecture/60-migrations.md +++ b/docs/frontend-system/architecture/60-migrations.md @@ -86,3 +86,19 @@ If your plugin exports and extension creators, these should be migrated to bluep The `createExtensionTester` from the `@backstage/frontend-test-utils` package has been reworked to better support testing of extensions. The new API allows access to extension output directly using the new `.get(ref)` method, and also provides access to all tested extensions through the new `.query(id/extension)` method. The `.render()` method that used to render the test subject in a test app has been deprecated. The extension tester no longer constructs a full app tree, but instead only instantiates the tree for the extensions under test. If you want to test the rendering of an extension that outputs in an app, you can instead use the `renderInTestApp` utility in combination with the new `.reactElement()` method of the extension tester: `renderInTestApp(tester.reactElement())`. + +### Extension data references update + +The way that extension data references are declared has been changed to allow for type inference of the ID. This requires the declaration to be split into two separate function calls, one to supply the type and the other to infer any options. For example, a reference that was previously declared like this: + +```ts +export const myExtension = createExtensionDataRef('my-plugin.my-data'); +``` + +Should be updated to the following: + +```ts +export const myExtension = createExtensionDataRef().with({ + id: 'my-plugin.my-data', +}); +```