add a new base extension initializer to initialize new types of entry point modules

This commit is contained in:
Jacob Overgaard
2024-04-18 14:32:20 +02:00
parent 1201f9e961
commit efce6d40e9
4 changed files with 80 additions and 60 deletions

View File

@@ -1,35 +1,18 @@
import type { ManifestBase, ManifestBundle } from '../types/index.js';
import type { UmbExtensionRegistry } from '../registry/extension.registry.js';
import { loadManifestPlainJs } from '../functions/load-manifest-plain-js.function.js';
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbExtensionInitializerBase } from './extension-initializer-base.js';
import type { UmbElement } from '@umbraco-cms/backoffice/element-api';
export class UmbBundleExtensionInitializer extends UmbControllerBase {
#extensionRegistry;
#bundleMap = new Map();
constructor(host: UmbControllerHost, extensionRegistry: UmbExtensionRegistry<ManifestBundle>) {
super(host);
this.#extensionRegistry = extensionRegistry;
this.observe(extensionRegistry.byType('bundle'), (bundles) => {
// Unregister removed bundles:
this.#bundleMap.forEach((existingBundle) => {
if (!bundles.find((b) => b.alias === existingBundle.alias)) {
this.unregisterBundle(existingBundle);
this.#bundleMap.delete(existingBundle.alias);
}
});
// Register new bundles:
bundles.forEach((bundle) => {
if (this.#bundleMap.has(bundle.alias)) return;
this.#bundleMap.set(bundle.alias, bundle);
this.instantiateBundle(bundle);
});
});
/**
* Extension initializer for the `bundle` extension type
*/
export class UmbBundleExtensionInitializer extends UmbExtensionInitializerBase<'bundle', ManifestBundle> {
constructor(host: UmbElement, extensionRegistry: UmbExtensionRegistry<ManifestBundle>) {
super(host, extensionRegistry, 'bundle');
}
async instantiateBundle(manifest: ManifestBundle) {
async instantiateExtension(manifest: ManifestBundle): Promise<void> {
if (manifest.js) {
const js = await loadManifestPlainJs(manifest.js);
@@ -38,16 +21,16 @@ export class UmbBundleExtensionInitializer extends UmbControllerBase {
const value = js[key];
if (Array.isArray(value)) {
this.#extensionRegistry.registerMany(value);
this.extensionRegistry.registerMany(value);
} else if (typeof value === 'object') {
this.#extensionRegistry.register(value);
this.extensionRegistry.register(value);
}
});
}
}
}
async unregisterBundle(manifest: ManifestBundle) {
async unloadExtension(manifest: ManifestBundle): Promise<void> {
if (manifest.js) {
const js = await loadManifestPlainJs(manifest.js);
@@ -56,9 +39,9 @@ export class UmbBundleExtensionInitializer extends UmbControllerBase {
const value = js[key];
if (Array.isArray(value)) {
this.#extensionRegistry.unregisterMany(value.map((v) => v.alias));
this.extensionRegistry.unregisterMany(value.map((v) => v.alias));
} else if (typeof value === 'object') {
this.#extensionRegistry.unregister((value as ManifestBase).alias);
this.extensionRegistry.unregister((value as ManifestBase).alias);
}
});
}

View File

@@ -1,43 +1,31 @@
import type { ManifestEntryPoint } from '../types/index.js';
import { hasInitExport, loadManifestPlainJs } from '../functions/index.js';
import type { UmbExtensionRegistry } from '../registry/extension.registry.js';
import type { UmbEntryPointModule } from '../models/entry-point.interface.js';
import { hasBeforeInitExport, hasInitExport, loadManifestPlainJs } from '../functions/index.js';
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import { UmbExtensionInitializerBase } from './extension-initializer-base.js';
import type { UmbElement } from '@umbraco-cms/backoffice/element-api';
export class UmbEntryPointExtensionInitializer extends UmbControllerBase {
#host;
#extensionRegistry;
#entryPointMap = new Map();
constructor(
host: UmbElement,
extensionRegistry: UmbExtensionRegistry<ManifestEntryPoint>,
initFn: keyof UmbEntryPointModule,
) {
super(host);
this.#host = host;
this.#extensionRegistry = extensionRegistry;
this.observe(extensionRegistry.byType('entryPoint'), (entryPoints) => {
entryPoints.forEach((entryPoint) => {
if (this.#entryPointMap.has(entryPoint.alias)) return;
this.#entryPointMap.set(entryPoint.alias, entryPoint);
// TODO: Should we unInit a entry point if is removed?
this.instantiateEntryPoint(entryPoint, initFn);
});
});
/**
* Extension initializer for the `entryPoint` extension type
*/
export class UmbEntryPointExtensionInitializer extends UmbExtensionInitializerBase<'entryPoint', ManifestEntryPoint> {
constructor(host: UmbElement, extensionRegistry: UmbExtensionRegistry<ManifestEntryPoint>) {
super(host, extensionRegistry, 'entryPoint');
}
async instantiateEntryPoint(manifest: ManifestEntryPoint, initFn: keyof UmbEntryPointModule = 'onInit') {
async instantiateExtension(manifest: ManifestEntryPoint) {
if (manifest.js) {
const js = await loadManifestPlainJs(manifest.js);
// If the extension has known exports, be sure to run those
if (initFn === 'beforeInit' && hasBeforeInitExport(js)) {
js.beforeInit(this.#host, this.#extensionRegistry);
} else if (initFn === 'onInit' && hasInitExport(js)) {
js.onInit(this.#host, this.#extensionRegistry);
if (hasInitExport(js)) {
js.onInit(this.host, this.extensionRegistry);
}
}
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
unloadExtension(_manifest: ManifestEntryPoint): void {
// No-op
// Entry points are not unloaded, but if they were, this is where you would do it.
}
}

View File

@@ -0,0 +1,48 @@
import type { ManifestBase } from '../types/index.js';
import type { UmbExtensionRegistry } from '../registry/extension.registry.js';
import type { SpecificManifestTypeOrManifestBase } from '../types/map.types.js';
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import type { UmbElement } from '@umbraco-cms/backoffice/element-api';
import type { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry';
/**
* Base class for extension initializers, which are responsible for loading and unloading extensions.
*/
export abstract class UmbExtensionInitializerBase<
Key extends string,
T extends ManifestBase = SpecificManifestTypeOrManifestBase<ManifestTypes, Key>,
> extends UmbControllerBase {
protected host;
protected extensionRegistry;
#extensionMap = new Map();
constructor(host: UmbElement, extensionRegistry: UmbExtensionRegistry<T>, manifestType: Key) {
super(host);
this.host = host;
this.extensionRegistry = extensionRegistry;
this.observe(extensionRegistry.byType<Key, T>(manifestType), (extensions) => {
this.#extensionMap.forEach((existingExt) => {
if (!extensions.find((b) => b.alias === existingExt.alias)) {
this.unloadExtension(existingExt);
this.#extensionMap.delete(existingExt.alias);
}
});
extensions.forEach((extension) => {
if (this.#extensionMap.has(extension.alias)) return;
this.#extensionMap.set(extension.alias, extension);
this.instantiateExtension(extension);
});
});
}
/**
* Perform any logic required to instantiate the extension.
*/
abstract instantiateExtension(manifest: T): Promise<void> | void;
/**
* Perform any logic required to unload the extension.
*/
abstract unloadExtension(manifest: T): Promise<void> | void;
}

View File

@@ -1,2 +1,3 @@
export * from './bundle-extension-initializer.js';
export * from './entry-point-extension-initializer.js';
export * from './extension-initializer-base.js';