frontend-app-api: split out and export createSpecializedApp
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/frontend-app-api': patch
|
||||
---
|
||||
|
||||
Added `createSpecializedApp`, which is a synchronous version of `createApp` where config and features already need to be loaded.
|
||||
@@ -41,6 +41,15 @@ export function createApp(options?: {
|
||||
// @public (undocumented)
|
||||
export function createExtensionTree(options: { config: Config }): ExtensionTree;
|
||||
|
||||
// @public
|
||||
export function createSpecializedApp(options?: {
|
||||
features?: (BackstagePlugin | ExtensionOverrides)[];
|
||||
config?: ConfigApi;
|
||||
bindRoutes?(context: { bind: AppRouteBinder }): void;
|
||||
}): {
|
||||
createRoot(): JSX_2.Element;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export interface ExtensionTree {
|
||||
// (undocumented)
|
||||
|
||||
@@ -244,49 +244,18 @@ export function createApp(options?: {
|
||||
|
||||
const discoveredFeatures = getAvailableFeatures(config);
|
||||
const loadedFeatures = (await options?.featureLoader?.({ config })) ?? [];
|
||||
const allFeatures = deduplicateFeatures([
|
||||
...discoveredFeatures,
|
||||
...loadedFeatures,
|
||||
...(options?.features ?? []),
|
||||
]);
|
||||
|
||||
const tree = createAppTree({
|
||||
features: allFeatures,
|
||||
builtinExtensions,
|
||||
const app = createSpecializedApp({
|
||||
config,
|
||||
});
|
||||
features: [
|
||||
...discoveredFeatures,
|
||||
...loadedFeatures,
|
||||
...(options?.features ?? []),
|
||||
],
|
||||
bindRoutes: options?.bindRoutes,
|
||||
}).createRoot();
|
||||
|
||||
const appContext = createLegacyAppContext(
|
||||
allFeatures.filter(
|
||||
(f): f is BackstagePlugin => f.$$type === '@backstage/BackstagePlugin',
|
||||
),
|
||||
);
|
||||
|
||||
const routeIds = collectRouteIds(allFeatures);
|
||||
|
||||
const App = () => (
|
||||
<ApiProvider apis={createApiHolder(tree, config)}>
|
||||
<AppContextProvider appContext={appContext}>
|
||||
<AppThemeProvider>
|
||||
<RoutingProvider
|
||||
{...extractRouteInfoFromAppNode(tree.root)}
|
||||
routeBindings={resolveRouteBindings(
|
||||
options?.bindRoutes,
|
||||
config,
|
||||
routeIds,
|
||||
)}
|
||||
>
|
||||
{/* TODO: set base path using the logic from AppRouter */}
|
||||
<BrowserRouter>
|
||||
{tree.root.instance!.getData(coreExtensionData.reactElement)}
|
||||
</BrowserRouter>
|
||||
</RoutingProvider>
|
||||
</AppThemeProvider>
|
||||
</AppContextProvider>
|
||||
</ApiProvider>
|
||||
);
|
||||
|
||||
return { default: App };
|
||||
return { default: () => app };
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -301,6 +270,66 @@ export function createApp(options?: {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronous version of {@link createApp}, expecting all features and
|
||||
* config to have been loaded already.
|
||||
* @public
|
||||
*/
|
||||
export function createSpecializedApp(options?: {
|
||||
features?: (BackstagePlugin | ExtensionOverrides)[];
|
||||
config?: ConfigApi;
|
||||
bindRoutes?(context: { bind: AppRouteBinder }): void;
|
||||
}): { createRoot(): JSX.Element } {
|
||||
const {
|
||||
features: duplicatedFeatures = [],
|
||||
config = new ConfigReader({}, 'empty-config'),
|
||||
} = options ?? {};
|
||||
|
||||
const features = deduplicateFeatures(duplicatedFeatures);
|
||||
|
||||
const tree = createAppTree({
|
||||
features,
|
||||
builtinExtensions,
|
||||
config,
|
||||
});
|
||||
|
||||
const appContext = createLegacyAppContext(
|
||||
features.filter(
|
||||
(f): f is BackstagePlugin => f.$$type === '@backstage/BackstagePlugin',
|
||||
),
|
||||
);
|
||||
|
||||
const routeIds = collectRouteIds(features);
|
||||
|
||||
const App = () => (
|
||||
<ApiProvider apis={createApiHolder(tree, config)}>
|
||||
<AppContextProvider appContext={appContext}>
|
||||
<AppThemeProvider>
|
||||
<RoutingProvider
|
||||
{...extractRouteInfoFromAppNode(tree.root)}
|
||||
routeBindings={resolveRouteBindings(
|
||||
options?.bindRoutes,
|
||||
config,
|
||||
routeIds,
|
||||
)}
|
||||
>
|
||||
{/* TODO: set base path using the logic from AppRouter */}
|
||||
<BrowserRouter>
|
||||
{tree.root.instance!.getData(coreExtensionData.reactElement)}
|
||||
</BrowserRouter>
|
||||
</RoutingProvider>
|
||||
</AppThemeProvider>
|
||||
</AppContextProvider>
|
||||
</ApiProvider>
|
||||
);
|
||||
|
||||
return {
|
||||
createRoot() {
|
||||
return <App />;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// Make sure that we only convert each new plugin instance to its legacy equivalent once
|
||||
const legacyPluginStore = getOrCreateGlobalSingleton(
|
||||
'legacy-plugin-compatibility-store',
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
export {
|
||||
createApp,
|
||||
createSpecializedApp,
|
||||
createExtensionTree,
|
||||
type ExtensionTreeNode,
|
||||
type ExtensionTree,
|
||||
|
||||
Reference in New Issue
Block a user