Handle chunk loading errors
Signed-off-by: Oliver Sand <oliver.sand@sda-se.com>
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/core': patch
|
||||
'@backstage/core-api': patch
|
||||
---
|
||||
|
||||
Introduce a `load-chunk` step in the `BootErrorPage` to show make chunk loading
|
||||
errors visible to the user.
|
||||
@@ -24,7 +24,7 @@ import { AppConfig } from '@backstage/config';
|
||||
import { SubRouteRef } from '../routing/types';
|
||||
|
||||
export type BootErrorPageProps = {
|
||||
step: 'load-config';
|
||||
step: 'load-config' | 'load-chunk';
|
||||
error: Error;
|
||||
};
|
||||
|
||||
|
||||
@@ -15,9 +15,10 @@
|
||||
*/
|
||||
|
||||
import React, { lazy, Suspense } from 'react';
|
||||
import { useApp } from '../app';
|
||||
import { BackstagePlugin, Extension } from '../plugin/types';
|
||||
import { RouteRef, useRouteRef } from '../routing';
|
||||
import { attachComponentData } from './componentData';
|
||||
import { Extension, BackstagePlugin } from '../plugin/types';
|
||||
|
||||
type ComponentLoader<T> =
|
||||
| {
|
||||
@@ -40,30 +41,41 @@ export function createRoutableExtension<
|
||||
return createReactExtension({
|
||||
component: {
|
||||
lazy: () =>
|
||||
component().then(InnerComponent => {
|
||||
const RoutableExtensionWrapper: any = (props: any) => {
|
||||
// Validate that the routing is wired up correctly in the App.tsx
|
||||
try {
|
||||
useRouteRef(mountPoint);
|
||||
} catch {
|
||||
throw new Error(
|
||||
`Routable extension component with mount point ${mountPoint} was not discovered in the app element tree. ` +
|
||||
'Routable extension components may not be rendered by other components and must be ' +
|
||||
'directly available as an element within the App provider component.',
|
||||
);
|
||||
}
|
||||
return <InnerComponent {...props} />;
|
||||
};
|
||||
component().then(
|
||||
InnerComponent => {
|
||||
const RoutableExtensionWrapper: any = (props: any) => {
|
||||
// Validate that the routing is wired up correctly in the App.tsx
|
||||
try {
|
||||
useRouteRef(mountPoint);
|
||||
} catch {
|
||||
throw new Error(
|
||||
`Routable extension component with mount point ${mountPoint} was not discovered in the app element tree. ` +
|
||||
'Routable extension components may not be rendered by other components and must be ' +
|
||||
'directly available as an element within the App provider component.',
|
||||
);
|
||||
}
|
||||
return <InnerComponent {...props} />;
|
||||
};
|
||||
|
||||
const componentName =
|
||||
(InnerComponent as { displayName?: string }).displayName ||
|
||||
InnerComponent.name ||
|
||||
'LazyComponent';
|
||||
const componentName =
|
||||
(InnerComponent as { displayName?: string }).displayName ||
|
||||
InnerComponent.name ||
|
||||
'LazyComponent';
|
||||
|
||||
RoutableExtensionWrapper.displayName = `RoutableExtension(${componentName})`;
|
||||
RoutableExtensionWrapper.displayName = `RoutableExtension(${componentName})`;
|
||||
|
||||
return RoutableExtensionWrapper as T;
|
||||
}),
|
||||
return RoutableExtensionWrapper as T;
|
||||
},
|
||||
error => {
|
||||
const RoutableExtensionWrapper: any = (_: any) => {
|
||||
const app = useApp();
|
||||
const { BootErrorPage } = app.getComponents();
|
||||
|
||||
return <BootErrorPage step="load-chunk" error={error} />;
|
||||
};
|
||||
return RoutableExtensionWrapper;
|
||||
},
|
||||
),
|
||||
},
|
||||
data: {
|
||||
'core.mountPoint': mountPoint,
|
||||
|
||||
@@ -97,16 +97,32 @@ export function createApp(options?: AppOptions) {
|
||||
<ErrorPage status="404" statusMessage="PAGE NOT FOUND" />
|
||||
);
|
||||
const DefaultBootErrorPage = ({ step, error }: BootErrorPageProps) => {
|
||||
let message = '';
|
||||
if (step === 'load-config') {
|
||||
message = `The configuration failed to load, someone should have a look at this error: ${error.message}`;
|
||||
switch (step) {
|
||||
case 'load-config':
|
||||
// TODO: figure out a nicer way to handle routing on the error page, when it can be done.
|
||||
return (
|
||||
<MemoryRouter>
|
||||
<ErrorPage
|
||||
status="501"
|
||||
statusMessage={`The configuration failed to load, someone should have a look at this error: ${error.message}`}
|
||||
/>
|
||||
</MemoryRouter>
|
||||
);
|
||||
case 'load-chunk':
|
||||
return (
|
||||
<ErrorPage
|
||||
status="501"
|
||||
statusMessage={`Lazy loaded chunk failed to load, try to reload the page: ${error.message}`}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
// TODO: figure out a nicer way to handle routing on the error page, when it can be done.
|
||||
return (
|
||||
<MemoryRouter>
|
||||
<ErrorPage status="501" statusMessage="" />
|
||||
</MemoryRouter>
|
||||
);
|
||||
}
|
||||
// TODO: figure out a nicer way to handle routing on the error page, when it can be done.
|
||||
return (
|
||||
<MemoryRouter>
|
||||
<ErrorPage status="501" statusMessage={message} />
|
||||
</MemoryRouter>
|
||||
);
|
||||
};
|
||||
|
||||
const apis = options?.apis ?? [];
|
||||
|
||||
Reference in New Issue
Block a user