backend-app-api: add support for adding module imports

Co-authored-by: Fredrik Adelöw <freben@gmail.com>
Co-authored-by: Johan Haals <johan.haals@gmail.com>
Co-authored-by: Camila Belo <camilaibs@gmail.com>
Co-authored-by: Philipp Hugenroth <philipph@spotify.com>
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2023-09-06 16:01:41 +02:00
parent 4d5eeec52d
commit 3b30b179cb
5 changed files with 72 additions and 41 deletions
@@ -46,6 +46,7 @@ export class BackendInitializer {
#features = new Array<InternalBackendFeature>();
#extensionPoints = new Map<string, { impl: unknown; pluginId: string }>();
#serviceRegistry: ServiceRegistry;
#registeredFeatures = new Array<Promise<BackendFeature>>();
constructor(defaultApiFactories: ServiceFactory[]) {
this.#serviceRegistry = ServiceRegistry.create([...defaultApiFactories]);
@@ -90,11 +91,11 @@ export class BackendInitializer {
return Object.fromEntries(result);
}
add(feature: BackendFeature) {
add(feature: Promise<BackendFeature>) {
if (this.#startPromise) {
throw new Error('feature can not be added after the backend has started');
}
this.#addFeature(feature);
this.#registeredFeatures.push(feature);
}
#addFeature(feature: BackendFeature) {
@@ -150,6 +151,10 @@ export class BackendInitializer {
async #doStart(): Promise<void> {
this.#serviceRegistry.checkForCircularDeps();
for (const feature of this.#registeredFeatures) {
this.#addFeature(await feature);
}
const featureDiscovery = await this.#serviceRegistry.get(
featureDiscoveryServiceRef,
'root',
@@ -25,8 +25,17 @@ export class BackstageBackend implements Backend {
this.#initializer = new BackendInitializer(defaultServiceFactories);
}
add(feature: BackendFeature | (() => BackendFeature)): void {
this.#initializer.add(typeof feature === 'function' ? feature() : feature);
add(
feature:
| BackendFeature
| (() => BackendFeature)
| Promise<{ default: BackendFeature | (() => BackendFeature) }>,
): void {
if (isPromise(feature)) {
this.#initializer.add(feature.then(f => unwrapFeature(f.default)));
} else {
this.#initializer.add(Promise.resolve(unwrapFeature(feature)));
}
}
async start(): Promise<void> {
@@ -37,3 +46,18 @@ export class BackstageBackend implements Backend {
await this.#initializer.stop();
}
}
function isPromise<T>(value: unknown | Promise<T>): value is Promise<T> {
return (
typeof value === 'object' &&
value !== null &&
'then' in value &&
typeof value.then === 'function'
);
}
function unwrapFeature(
feature: BackendFeature | (() => BackendFeature),
): BackendFeature {
return typeof feature === 'function' ? feature() : feature;
}
+6 -1
View File
@@ -25,7 +25,12 @@ import {
* @public
*/
export interface Backend {
add(feature: BackendFeature | (() => BackendFeature)): void;
add(
feature:
| BackendFeature
| (() => BackendFeature)
| Promise<{ default: BackendFeature | (() => BackendFeature) }>,
): void;
start(): Promise<void>;
stop(): Promise<void>;
}