59 lines
1.6 KiB
TypeScript
59 lines
1.6 KiB
TypeScript
import {
|
|
init,
|
|
loadRemote,
|
|
registerRemotes,
|
|
} from "@module-federation/enhanced/runtime";
|
|
|
|
export interface RemoteModuleRef<T = unknown> {
|
|
name: string;
|
|
module: string;
|
|
/** Phantom marker to preserve the generic parameter through the type system. */
|
|
readonly __type?: T;
|
|
}
|
|
|
|
export interface RemoteEntry {
|
|
name: string;
|
|
entry: string;
|
|
}
|
|
|
|
let initialized = false;
|
|
const HOST_NAME = "aeroflot_flights_host" as const;
|
|
|
|
/**
|
|
* Registers a remote with the MF runtime. On the first call, this also calls
|
|
* `init()` to bootstrap the MF runtime with the host identity. Subsequent
|
|
* calls use `registerRemotes()` to add remotes without re-initializing.
|
|
*/
|
|
export function registerRemote(entry: RemoteEntry): void {
|
|
if (!initialized) {
|
|
init({
|
|
name: HOST_NAME,
|
|
remotes: [entry],
|
|
});
|
|
initialized = true;
|
|
return;
|
|
}
|
|
registerRemotes([entry]);
|
|
}
|
|
|
|
/**
|
|
* Loads an exposed module from a previously registered remote. The `name` +
|
|
* `module` fields are concatenated into MF's `remote/module` lookup key.
|
|
*
|
|
* Throws if the runtime returns a null/undefined module, which usually means
|
|
* the remote manifest does not actually expose the requested path.
|
|
*/
|
|
export async function loadRemoteModule<T>(ref: RemoteModuleRef<T>): Promise<T> {
|
|
const key = `${ref.name}/${ref.module.replace(/^\.\//, "")}`;
|
|
const result = await loadRemote<T>(key);
|
|
if (result === null || result === undefined) {
|
|
throw new Error(`Remote module ${key} loaded as null/undefined`);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/** Test-only: resets the one-shot init flag. */
|
|
export function __resetRemoteLoaderForTests(): void {
|
|
initialized = false;
|
|
}
|