no more featureLoader

Signed-off-by: Fredrik Adelöw <freben@gmail.com>
This commit is contained in:
Fredrik Adelöw
2023-12-14 10:33:44 +01:00
parent a3792432bb
commit 44735df633
7 changed files with 72 additions and 10 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/frontend-app-api': minor
---
Removed `featureLoader` from `createApp`, `features` instead accepts both `FrontendFeature` and `CreateAppFeatureLoader`
+6 -2
View File
@@ -14,16 +14,20 @@ import { SubRouteRef } from '@backstage/frontend-plugin-api';
// @public (undocumented)
export function createApp(options?: {
features?: FrontendFeature[];
features?: (FrontendFeature | CreateAppFeatureLoader)[];
configLoader?: () => Promise<{
config: ConfigApi;
}>;
bindRoutes?(context: { bind: CreateAppRouteBinder }): void;
featureLoader?: (ctx: { config: ConfigApi }) => Promise<FrontendFeature[]>;
}): {
createRoot(): JSX_2.Element;
};
// @public
export type CreateAppFeatureLoader = (options: {
config: ConfigApi;
}) => Promise<FrontendFeature[]>;
// @public
export type CreateAppRouteBinder = <
TExternalRoutes extends {
+1
View File
@@ -38,6 +38,7 @@
"@backstage/core-app-api": "workspace:^",
"@backstage/core-components": "workspace:^",
"@backstage/core-plugin-api": "workspace:^",
"@backstage/errors": "workspace:^",
"@backstage/frontend-plugin-api": "workspace:^",
"@backstage/theme": "workspace:^",
"@backstage/types": "workspace:^",
@@ -99,6 +99,33 @@ describe('createApp', () => {
);
});
it('should support feature loaders', async () => {
const app = createApp({
configLoader: async () => ({
config: new MockConfigApi({ key: 'config-value' }),
}),
features: [
async ({ config }) => [
createPlugin({
id: 'test',
extensions: [
createPageExtension({
defaultPath: '/',
loader: async () => <div>{config.getString('key')}</div>,
}),
],
}),
],
],
});
await renderWithEffects(app.createRoot());
await expect(
screen.findByText('config-value'),
).resolves.toBeInTheDocument();
});
it('should register feature flags', async () => {
const app = createApp({
configLoader: async () => ({ config: new MockConfigApi({}) }),
@@ -101,6 +101,7 @@ import { toInternalBackstagePlugin } from '../../../frontend-plugin-api/src/wiri
// eslint-disable-next-line @backstage/no-relative-monorepo-imports
import { toInternalExtensionOverrides } from '../../../frontend-plugin-api/src/wiring/createExtensionOverrides';
import { DefaultComponentsApi } from '../apis/implementations/ComponentsApi';
import { stringifyError } from '@backstage/errors';
export const builtinExtensions = [
Core,
@@ -238,12 +239,20 @@ function deduplicateFeatures(
.reverse();
}
/**
* A source of dynamically loaded frontend features.
*
* @public
*/
export type CreateAppFeatureLoader = (options: {
config: ConfigApi;
}) => Promise<FrontendFeature[]>;
/** @public */
export function createApp(options?: {
features?: FrontendFeature[];
features?: (FrontendFeature | CreateAppFeatureLoader)[];
configLoader?: () => Promise<{ config: ConfigApi }>;
bindRoutes?(context: { bind: CreateAppRouteBinder }): void;
featureLoader?: (ctx: { config: ConfigApi }) => Promise<FrontendFeature[]>;
}): {
createRoot(): JSX.Element;
} {
@@ -255,15 +264,28 @@ export function createApp(options?: {
);
const discoveredFeatures = getAvailableFeatures(config);
const loadedFeatures = (await options?.featureLoader?.({ config })) ?? [];
const providedFeatures: FrontendFeature[] = [];
for (const feature of options?.features ?? []) {
if (typeof feature === 'function') {
try {
const loadedFeatures = await feature({ config });
providedFeatures.push(...loadedFeatures);
} catch (e) {
throw new Error(
`Failed to read frontend features from loader, ${stringifyError(
e,
)}`,
);
}
} else {
providedFeatures.push(feature);
}
}
const app = createSpecializedApp({
config,
features: [
...discoveredFeatures,
...loadedFeatures,
...(options?.features ?? []),
],
features: [...discoveredFeatures, ...providedFeatures],
bindRoutes: options?.bindRoutes,
}).createRoot();
@@ -285,6 +307,7 @@ export function createApp(options?: {
/**
* Synchronous version of {@link createApp}, expecting all features and
* config to have been loaded already.
*
* @public
*/
export function createSpecializedApp(options?: {
@@ -18,6 +18,7 @@ export {
createApp,
createSpecializedApp,
createExtensionTree,
type CreateAppFeatureLoader,
type ExtensionTreeNode,
type ExtensionTree,
} from './createApp';
+1
View File
@@ -4158,6 +4158,7 @@ __metadata:
"@backstage/core-app-api": "workspace:^"
"@backstage/core-components": "workspace:^"
"@backstage/core-plugin-api": "workspace:^"
"@backstage/errors": "workspace:^"
"@backstage/frontend-plugin-api": "workspace:^"
"@backstage/test-utils": "workspace:^"
"@backstage/theme": "workspace:^"