Merge pull request #30819 from backstage/rugvip/tsdocs

frontend-plugin-api: add TsDoc for some of the most important API surface
This commit is contained in:
Patrik Oldsberg
2025-08-08 17:02:40 +02:00
committed by GitHub
6 changed files with 164 additions and 9 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/frontend-plugin-api': patch
---
Added inline documentation for `createExtension`, `createExtensionBlueprint`, `createFrontendPlugin`, and `createFrontendModule`.
+3 -3
View File
@@ -393,7 +393,7 @@ export { createApiFactory };
export { createApiRef };
// @public (undocumented)
// @public
export function createExtension<
UOutput extends ExtensionDataRef,
TInputs extends {
@@ -688,7 +688,7 @@ export interface CreateFrontendFeatureLoaderOptions {
>;
}
// @public (undocumented)
// @public
export function createFrontendModule<
TId extends string,
TExtensions extends readonly ExtensionDefinition[] = [],
@@ -707,7 +707,7 @@ export interface CreateFrontendModuleOptions<
pluginId: TPluginId;
}
// @public (undocumented)
// @public
export function createFrontendPlugin<
TId extends string,
TRoutes extends {
@@ -27,7 +27,12 @@ import { z } from 'zod';
import { createSchemaFromZod } from '../schema/createSchemaFromZod';
import { OpaqueExtensionDefinition } from '@internal/frontend';
import { ExtensionDataContainer } from './types';
import { ExtensionBlueprintDefineParams } from './createExtensionBlueprint';
import {
ExtensionBlueprint,
ExtensionBlueprintDefineParams,
} from './createExtensionBlueprint';
import { FrontendPlugin } from './createFrontendPlugin';
import { FrontendModule } from './createFrontendModule';
/**
* This symbol is used to pass parameter overrides from the extension override to the blueprint factory
@@ -281,7 +286,41 @@ export type ExtensionDefinition<
}>;
};
/** @public */
/**
* Creates a new extension definition for installation in a Backstage app.
*
* @remarks
*
* This is a low-level function for creation of extensions with arbitrary inputs
* and outputs and is typically only intended to be used for advanced overrides
* or framework-level extensions. For most extension creation needs, it is
* recommended to use existing {@link ExtensionBlueprint}s instead. You can find
* blueprints both in the `@backstage/frontend-plugin-api` package as well as
* other plugin libraries. There is also a list of
* {@link https://backstage.io/docs/frontend-system/building-plugins/common-extension-blueprints | commonly used blueprints}
* in the frontend system documentation.
*
* Extension definitions that are created with this function can be installed in
* a Backstage app via a {@link FrontendPlugin} or {@link FrontendModule}.
*
* For more details on how extensions work, see the
* {@link https://backstage.io/docs/frontend-system/architecture/extensions | documentation for extensions}.
*
* @example
*
* ```ts
* const myExtension = createExtension({
* name: 'example',
* attachTo: { id: 'app', input: 'root' },
* output: [coreExtensionData.reactElement],
* factory() {
* return [coreExtensionData.reactElement(<h1>Hello, world!</h1>)];
* },
* });
* ```
*
* @public
*/
export function createExtension<
UOutput extends ExtensionDataRef,
TInputs extends {
@@ -34,6 +34,7 @@ import {
resolveInputOverrides,
} from './resolveInputOverrides';
import { ExtensionDataContainer } from './types';
import { PageBlueprint } from '../blueprints/PageBlueprint';
/**
* A function used to define a parameter mapping function in order to facilitate
@@ -403,9 +404,52 @@ function unwrapParams<TParams extends object>(
}
/**
* A simpler replacement for wrapping up `createExtension` inside a kind or type. This allows for a cleaner API for creating
* types and instances of those types.
* Creates a new extension blueprint that encapsulates the creation of
* extensions of particular kinds.
*
* @remarks
*
* For details on how blueprints work, see the
* {@link https://backstage.io/docs/frontend-system/architecture/extension-blueprints | documentation for extension blueprints}
* in the frontend system documentation.
*
* Extension blueprints make it much easier for users to create new extensions
* for your plugin. Rather than letting them use {@link createExtension}
* directly, you can define a set of parameters and default factory for your
* blueprint, removing a lot of the boilerplate and complexity that is otherwise
* needed to create an extension.
*
* Each blueprint has its own `kind` that helps identify and group the
* extensions that have been created with it. For example the
* {@link PageBlueprint} has the kind `'page'`, and extensions created with it
* will be given the ID `'page:<plugin-id>[/<name>]'`. Blueprints should always
* be exported as `<PascalCaseKind>Blueprint`.
*
* When creating a blueprint the type of the parameters are inferred from the
* `factory` function that you provide. The exception to that is when you need
* your blueprint to include inferred type parameters, in which case you need to
* use the `defineParams` option. See the documentation for the `defineParams`
* option for more details on how that works.
*
* @example
* ```tsx
* // In your plugin library
* export const GreetingBlueprint = createExtensionBlueprint({
* kind: 'greeting',
* attachTo: { id: 'example', input: 'greetings' },
* output: [coreExtensionData.reactElement],
* factory(params: { greeting: string }) {
* return [coreExtensionData.reactElement(<h1>{params.greeting}</h1>)];
* },
* });
*
* // Someone using your blueprint in their plugin
* const exampleGreeting = GreetingBlueprint.make({
* params: {
* greeting: 'Hello, world!',
* },
* });
* ```
* @public
*/
export function createExtensionBlueprint<
@@ -45,7 +45,45 @@ export interface InternalFrontendModule extends FrontendModule {
readonly featureFlags: FeatureFlagConfig[];
}
/** @public */
/**
* Creates a new module that can be installed in a Backstage app.
*
* @remarks
*
* Modules are used to add or override extensions for an existing plugin. If a
* module provides an extension with the same ID as one provided by the plugin,
* the extension provided by the module will always take precedence.
*
* Every module is created for a specific plugin by providing the
* unique ID of the plugin that the module should be installed for. If that
* plugin is not present in the app, the module will be ignored and have no
* effect.
*
* For more information on how modules work, see the
* {@link https://backstage.io/docs/frontend-system/architecture/extension-overrides#creating-a-frontend-module | documentation for modules}
* in the frontend system documentation.
*
* It is recommended to name the module variable of the form `<pluginId>Module<ModuleName>`.
*
* @example
*
* ```tsx
* import { createFrontendModule } from '@backstage/frontend-plugin-api';
*
* export const exampleModuleCustomPage = createFrontendModule({
* pluginId: 'example',
* extensions: [
* // Overrides the default page for the 'example' plugin
* PageBlueprint.make({
* path: '/example',
* loader: () => import('./CustomPage').then(m => <m.CustomPage />),
* }),
* ],
* });
* ```
*
* @public
*/
export function createFrontendModule<
TId extends string,
TExtensions extends readonly ExtensionDefinition[] = [],
@@ -135,7 +135,36 @@ export interface PluginOptions<
info?: FrontendPluginInfoOptions;
}
/** @public */
/**
* Creates a new plugin that can be installed in a Backstage app.
*
* @remarks
*
* Every plugin is created with a unique ID and a set of extensions
* that are installed as part of the plugin.
*
* For more information on how plugins work, see the
* {@link https://backstage.io/docs/frontend-system/building-plugins/index | documentation for plugins}
* in the frontend system documentation.
*
* @example
*
* ```tsx
* import { createFrontendPlugin } from '@backstage/frontend-plugin-api';
*
* export const examplePlugin = createFrontendPlugin({
* pluginId: 'example',
* extensions: [
* PageBlueprint.make({
* path: '/example',
* loader: () => import('./ExamplePage').then(m => <m.ExamplePage />),
* }),
* ],
* });
* ```
*
* @public
*/
export function createFrontendPlugin<
TId extends string,
TRoutes extends { [name in string]: RouteRef | SubRouteRef } = {},