diff --git a/packages/app-next/src/examples/graphiqlPlugin.tsx b/packages/app-next/src/examples/graphiqlPlugin.tsx
index c40b78fc97..d6c0d71fe7 100644
--- a/packages/app-next/src/examples/graphiqlPlugin.tsx
+++ b/packages/app-next/src/examples/graphiqlPlugin.tsx
@@ -15,25 +15,15 @@
*/
import {
- createExtension,
+ createPageExtension,
createPlugin,
- coreExtensionData,
- createSchemaFromZod,
} from '@backstage/frontend-plugin-api';
-import { Router as GraphiQLPage } from '@backstage/plugin-graphiql';
+import React from 'react';
-export const GraphiqlPageExtension = createExtension({
- output: {
- component: coreExtensionData.reactComponent,
- path: coreExtensionData.routePath,
- },
- configSchema: createSchemaFromZod(z =>
- z.object({ path: z.string().default('/graphiql') }),
- ),
- factory({ bind, config }) {
- bind.component(GraphiQLPage);
- bind.path(config.path);
- },
+export const GraphiqlPage = createPageExtension({
+ defaultPath: '/graphiql',
+ component: () =>
+ import('@backstage/plugin-graphiql').then(({ Router }) => ),
});
export const graphiqlPlugin = createPlugin({
@@ -42,7 +32,7 @@ export const graphiqlPlugin = createPlugin({
{
id: 'graphiql.page',
at: 'core.router/routes',
- extension: GraphiqlPageExtension,
+ extension: GraphiqlPage,
},
],
});
diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md
index a86597d7bd..34ca6fdb5a 100644
--- a/packages/frontend-plugin-api/api-report.md
+++ b/packages/frontend-plugin-api/api-report.md
@@ -3,6 +3,8 @@
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
+///
+
import { ComponentType } from 'react';
import { JsonObject } from '@backstage/types';
import { z } from 'zod';
@@ -77,6 +79,38 @@ export interface CreateExtensionOptions<
output: TData;
}
+// @public
+export function createPageExtension<
+ TConfig extends {
+ path: string;
+ },
+ TInputs extends Record<
+ string,
+ {
+ extensionData: AnyExtensionDataMap;
+ }
+ >,
+>(
+ options: (
+ | {
+ defaultPath: string;
+ }
+ | {
+ configSchema: PortableSchema;
+ }
+ ) & {
+ inputs?: TInputs;
+ component: (props: {
+ config: TConfig;
+ inputs: {
+ [pointName in keyof TInputs]: ExtensionDataValue<
+ TInputs[pointName]['extensionData']
+ >[];
+ };
+ }) => Promise;
+ },
+): Extension;
+
// @public (undocumented)
export function createPlugin(options: BackstagePluginOptions): BackstagePlugin;
diff --git a/packages/frontend-plugin-api/src/createPageExtension.tsx b/packages/frontend-plugin-api/src/createPageExtension.tsx
new file mode 100644
index 0000000000..78674282a3
--- /dev/null
+++ b/packages/frontend-plugin-api/src/createPageExtension.tsx
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2023 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React from 'react';
+import { createSchemaFromZod, PortableSchema } from './createSchemaFromZod';
+import {
+ AnyExtensionDataMap,
+ coreExtensionData,
+ createExtension,
+ Extension,
+ ExtensionDataValue,
+} from './types';
+
+/**
+ * Helper for creating extensions for a routable React page component.
+ *
+ * @public
+ */
+export function createPageExtension<
+ TConfig extends { path: string },
+ TInputs extends Record,
+>(
+ options: (
+ | {
+ defaultPath: string;
+ }
+ | {
+ configSchema: PortableSchema;
+ }
+ ) & {
+ inputs?: TInputs;
+ component: (props: {
+ config: TConfig;
+ inputs: {
+ [pointName in keyof TInputs]: ExtensionDataValue<
+ TInputs[pointName]['extensionData']
+ >[];
+ };
+ }) => Promise;
+ },
+): Extension {
+ const configSchema =
+ 'configSchema' in options
+ ? options.configSchema
+ : (createSchemaFromZod(z =>
+ z.object({ path: z.string().default(options.defaultPath) }),
+ ) as PortableSchema);
+
+ return createExtension({
+ output: {
+ component: coreExtensionData.reactComponent,
+ path: coreExtensionData.routePath,
+ },
+ inputs: options.inputs,
+ configSchema,
+ factory({ bind, config, inputs }) {
+ const LazyComponent = React.lazy(() =>
+ options
+ .component({ config, inputs })
+ .then(element => ({ default: () => element })),
+ );
+ bind.path(config.path);
+ bind.component(() => (
+
+
+
+ ));
+ },
+ });
+}
diff --git a/packages/frontend-plugin-api/src/index.ts b/packages/frontend-plugin-api/src/index.ts
index f70c77abcc..46ff503121 100644
--- a/packages/frontend-plugin-api/src/index.ts
+++ b/packages/frontend-plugin-api/src/index.ts
@@ -20,21 +20,22 @@
* @packageDocumentation
*/
-export {
- createExtension,
- coreExtensionData,
- createPlugin,
- type ExtensionInstanceParameters,
- type BackstagePlugin,
- type Extension,
- type AnyExtensionDataMap,
- type BackstagePluginOptions,
- type CreateExtensionOptions,
- type ExtensionDataBind,
- type ExtensionDataRef,
- type ExtensionDataValue,
-} from './types';
+export { createPageExtension } from './createPageExtension';
export {
createSchemaFromZod,
type PortableSchema,
} from './createSchemaFromZod';
+export {
+ coreExtensionData,
+ createExtension,
+ createPlugin,
+ type AnyExtensionDataMap,
+ type BackstagePlugin,
+ type BackstagePluginOptions,
+ type CreateExtensionOptions,
+ type Extension,
+ type ExtensionDataBind,
+ type ExtensionDataRef,
+ type ExtensionDataValue,
+ type ExtensionInstanceParameters,
+} from './types';