Merge pull request #26052 from backstage/mob/force-lazy

Introduce `ExtensionBoundary.lazy`
This commit is contained in:
Fredrik Adelöw
2024-08-16 15:18:45 +02:00
committed by GitHub
9 changed files with 44 additions and 44 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/frontend-plugin-api': patch
---
Add an `ExtensionBoundary.lazy` function to create properly wrapped lazy-loading enabled elements, suitable for use with `coreExtensionData.reactElement`. The page blueprint now automatically leverages this.
+10 -1
View File
@@ -1362,6 +1362,15 @@ export function ExtensionBoundary(
props: ExtensionBoundaryProps,
): React_2.JSX.Element;
// @public (undocumented)
export namespace ExtensionBoundary {
// (undocumented)
export function lazy(
appNode: AppNode,
lazyElement: () => Promise<JSX.Element>,
): JSX.Element;
}
// @public (undocumented)
export interface ExtensionBoundaryProps {
// (undocumented)
@@ -1840,7 +1849,7 @@ export const PageBlueprint: ExtensionBlueprint<
loader: () => Promise<JSX.Element>;
routeRef?: RouteRef<AnyRouteRefParams> | undefined;
},
| ConfigurableExtensionDataRef<React_2.JSX.Element, 'core.reactElement', {}>
| ConfigurableExtensionDataRef<JSX_2.Element, 'core.reactElement', {}>
| ConfigurableExtensionDataRef<string, 'core.routing.path', {}>
| ConfigurableExtensionDataRef<
RouteRef<AnyRouteRefParams>,
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React, { lazy } from 'react';
import { RouteRef } from '../routing';
import { coreExtensionData, createExtensionBlueprint } from '../wiring';
import { ExtensionBoundary } from '../components';
@@ -48,17 +48,8 @@ export const PageBlueprint = createExtensionBlueprint({
},
{ config, node },
) {
const ExtensionComponent = lazy(() =>
loader().then(element => ({ default: () => element })),
);
yield coreExtensionData.routePath(config.path ?? defaultPath);
yield coreExtensionData.reactElement(
<ExtensionBoundary node={node}>
<ExtensionComponent />
</ExtensionBoundary>,
);
yield coreExtensionData.reactElement(ExtensionBoundary.lazy(node, loader));
if (routeRef) {
yield coreExtensionData.routeRef(routeRef);
}
@@ -19,6 +19,7 @@ import React, {
ReactNode,
Suspense,
useEffect,
lazy as reactLazy,
} from 'react';
import { AnalyticsContext, useAnalytics } from '@backstage/core-plugin-api';
import { ErrorBoundary } from './ErrorBoundary';
@@ -90,3 +91,20 @@ export function ExtensionBoundary(props: ExtensionBoundaryProps) {
</Suspense>
);
}
/** @public */
export namespace ExtensionBoundary {
export function lazy(
appNode: AppNode,
lazyElement: () => Promise<JSX.Element>,
): JSX.Element {
const ExtensionComponent = reactLazy(() =>
lazyElement().then(element => ({ default: () => element })),
);
return (
<ExtensionBoundary node={appNode}>
<ExtensionComponent />
</ExtensionBoundary>
);
}
}
+3 -3
View File
@@ -11,8 +11,8 @@ import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api';
import { Entity } from '@backstage/catalog-model';
import { ExtensionBlueprint } from '@backstage/frontend-plugin-api';
import { ExtensionDefinition } from '@backstage/frontend-plugin-api';
import { JSX as JSX_2 } from 'react';
import { PortableSchema } from '@backstage/frontend-plugin-api';
import { default as React_2 } from 'react';
import { ResolvedExtensionInputs } from '@backstage/frontend-plugin-api';
import { ResourcePermission } from '@backstage/plugin-permission-common';
import { RouteRef } from '@backstage/frontend-plugin-api';
@@ -182,7 +182,7 @@ export const EntityCardBlueprint: ExtensionBlueprint<
loader: () => Promise<JSX.Element>;
filter?: string | ((entity: Entity) => boolean) | undefined;
},
| ConfigurableExtensionDataRef<React_2.JSX.Element, 'core.reactElement', {}>
| ConfigurableExtensionDataRef<JSX_2.Element, 'core.reactElement', {}>
| ConfigurableExtensionDataRef<
(entity: Entity) => boolean,
'catalog.entity-filter-function',
@@ -232,7 +232,7 @@ export const EntityContentBlueprint: ExtensionBlueprint<
routeRef?: RouteRef<AnyRouteRefParams> | undefined;
filter?: string | ((entity: Entity) => boolean) | undefined;
},
| ConfigurableExtensionDataRef<React_2.JSX.Element, 'core.reactElement', {}>
| ConfigurableExtensionDataRef<JSX_2.Element, 'core.reactElement', {}>
| ConfigurableExtensionDataRef<string, 'core.routing.path', {}>
| ConfigurableExtensionDataRef<
RouteRef<AnyRouteRefParams>,
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React, { lazy } from 'react';
import {
ExtensionBoundary,
coreExtensionData,
@@ -54,15 +54,7 @@ export const EntityCardBlueprint = createExtensionBlueprint({
},
{ node, config },
) {
const ExtensionComponent = lazy(() =>
loader().then(element => ({ default: () => element })),
);
yield coreExtensionData.reactElement(
<ExtensionBoundary node={node}>
<ExtensionComponent />
</ExtensionBoundary>,
);
yield coreExtensionData.reactElement(ExtensionBoundary.lazy(node, loader));
if (config.filter) {
yield catalogExtensionData.entityFilterExpression(config.filter);
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React, { lazy } from 'react';
import {
coreExtensionData,
createExtensionBlueprint,
@@ -70,15 +70,7 @@ export const EntityContentBlueprint = createExtensionBlueprint({
const path = config.path ?? defaultPath;
const title = config.title ?? defaultTitle;
const ExtensionComponent = lazy(() =>
loader().then(element => ({ default: () => element })),
);
yield coreExtensionData.reactElement(
<ExtensionBoundary node={node}>
<ExtensionComponent />
</ExtensionBoundary>,
);
yield coreExtensionData.reactElement(ExtensionBoundary.lazy(node, loader));
yield coreExtensionData.routePath(path);
+1 -2
View File
@@ -19,7 +19,6 @@ import { ExternalRouteRef } from '@backstage/frontend-plugin-api';
import { IconComponent } from '@backstage/core-plugin-api';
import { JSX as JSX_2 } from 'react';
import { PortableSchema } from '@backstage/frontend-plugin-api';
import { default as React_2 } from 'react';
import { RouteRef } from '@backstage/frontend-plugin-api';
import { SearchResultItemExtensionComponent } from '@backstage/plugin-search-react/alpha';
import { SearchResultItemExtensionPredicate } from '@backstage/plugin-search-react/alpha';
@@ -35,7 +34,7 @@ export const CatalogFilterBlueprint: ExtensionBlueprint<
{
loader: () => Promise<JSX.Element>;
},
ConfigurableExtensionDataRef<React_2.JSX.Element, 'core.reactElement', {}>,
ConfigurableExtensionDataRef<JSX_2.Element, 'core.reactElement', {}>,
{},
{},
{},
@@ -14,7 +14,6 @@
* limitations under the License.
*/
import React, { lazy } from 'react';
import {
ExtensionBoundary,
coreExtensionData,
@@ -30,14 +29,9 @@ export const CatalogFilterBlueprint = createExtensionBlueprint({
attachTo: { id: 'page:catalog', input: 'filters' },
output: [coreExtensionData.reactElement],
factory(params: { loader: () => Promise<JSX.Element> }, { node }) {
const ExtensionComponent = lazy(() =>
params.loader().then(element => ({ default: () => element })),
);
return [
coreExtensionData.reactElement(
<ExtensionBoundary node={node}>
<ExtensionComponent />
</ExtensionBoundary>,
ExtensionBoundary.lazy(node, params.loader),
),
];
},